compat_test.go

  1package ygo_test
  2
  3import (
  4	"encoding/json"
  5	"os"
  6	"testing"
  7
  8	"git.kilimanjaro.io/ygo"
  9)
 10
 11func TestYjsCompatibility(t *testing.T) {
 12	t.Run("shared YText", func(t *testing.T) {
 13		data, err := os.ReadFile("testdata/shared-YText.yjs")
 14		if err != nil {
 15			t.Fatalf("failed to read testdata: %v", err)
 16		}
 17
 18		doc, err := ygo.NewDoc()
 19		if err != nil {
 20			t.Fatalf("failed to create doc: %v", err)
 21		}
 22		defer doc.Destroy()
 23
 24		err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
 25			update := ygo.UpdateFromBytes(data)
 26			return txn.ApplyUpdate(update)
 27		})
 28		if err != nil {
 29			t.Fatalf("failed to apply update: %v", err)
 30		}
 31
 32		txt, err := doc.GetText("test")
 33		if err != nil {
 34			t.Fatalf("failed to get text: %v", err)
 35		}
 36		defer txt.Destroy()
 37
 38		var content string
 39		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
 40			var err error
 41			content, err = txt.String(txn)
 42			return err
 43		})
 44		if err != nil {
 45			t.Fatalf("failed to read text: %v", err)
 46		}
 47
 48		if content != "test text" {
 49			t.Errorf("expected 'test text', got %q", content)
 50		}
 51	})
 52
 53	t.Run("map value types", func(t *testing.T) {
 54		data, err := os.ReadFile("testdata/map-value-types.yjs")
 55		if err != nil {
 56			t.Fatalf("failed to read testdata: %v", err)
 57		}
 58
 59		doc, err := ygo.NewDoc()
 60		if err != nil {
 61			t.Fatalf("failed to create doc: %v", err)
 62		}
 63		defer doc.Destroy()
 64
 65		err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
 66			update := ygo.UpdateFromBytes(data)
 67			return txn.ApplyUpdate(update)
 68		})
 69		if err != nil {
 70			t.Fatalf("failed to apply update: %v", err)
 71		}
 72
 73		m, err := doc.GetMap("test")
 74		if err != nil {
 75			t.Fatalf("failed to get map: %v", err)
 76		}
 77		defer m.Destroy()
 78
 79		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
 80			out, err := m.Get(txn, "string")
 81			if err != nil {
 82				t.Errorf("failed to get 'string': %v", err)
 83			} else if v, ok := out.String(); !ok || v != "value" {
 84				t.Errorf("expected string='value', got %v", v)
 85			}
 86			out.Destroy()
 87
 88			out, err = m.Get(txn, "bool")
 89			if err != nil {
 90				t.Errorf("failed to get 'bool': %v", err)
 91			} else if v, ok := out.Bool(); !ok || v != true {
 92				t.Errorf("expected bool=true, got %v", v)
 93			}
 94			out.Destroy()
 95
 96			out, err = m.Get(txn, "number")
 97			if err != nil {
 98				t.Errorf("failed to get 'number': %v", err)
 99			} else if v, ok := out.Float(); !ok || v != 1 {
100				t.Errorf("expected number=1, got %v", v)
101			}
102			out.Destroy()
103
104			out, err = m.Get(txn, "object")
105			if err != nil {
106				t.Errorf("failed to get 'object': %v", err)
107			} else {
108				var obj map[string]interface{}
109				if err := out.JSON(&obj); err != nil {
110					t.Errorf("failed to parse JSON: %v", err)
111				} else {
112					if obj["foo"] != "bar" {
113						t.Errorf("expected object.foo='bar', got %v", obj["foo"])
114					}
115					if obj["num"] != float64(1) {
116						t.Errorf("expected object.num=1, got %v", obj["num"])
117					}
118					if obj["test"] != true {
119						t.Errorf("expected object.test=true, got %v", obj["test"])
120					}
121				}
122			}
123			out.Destroy()
124
125			return nil
126		})
127		if err != nil {
128			t.Fatalf("map verification failed: %v", err)
129		}
130	})
131
132	t.Run("shared YArray", func(t *testing.T) {
133		data, err := os.ReadFile("testdata/shared-YArray.yjs")
134		if err != nil {
135			t.Fatalf("failed to read testdata: %v", err)
136		}
137
138		doc, err := ygo.NewDoc()
139		if err != nil {
140			t.Fatalf("failed to create doc: %v", err)
141		}
142		defer doc.Destroy()
143
144		err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
145			update := ygo.UpdateFromBytes(data)
146			return txn.ApplyUpdate(update)
147		})
148		if err != nil {
149			t.Fatalf("failed to apply update: %v", err)
150		}
151
152		arr, err := doc.GetArray("test")
153		if err != nil {
154			t.Fatalf("failed to get array: %v", err)
155		}
156		defer arr.Destroy()
157
158		var length uint32
159		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
160			var err error
161			length = arr.Len()
162			return err
163		})
164		if err != nil {
165			t.Fatalf("failed to get array length: %v", err)
166		}
167
168		if length != 4 {
169			t.Errorf("expected array length 4, got %d", length)
170		}
171
172		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
173			out, err := arr.Get(txn, 0)
174			if err != nil {
175				t.Errorf("failed to get element 0: %v", err)
176			} else if v, ok := out.String(); !ok || v != "first" {
177				t.Errorf("expected element 0='first', got %v", v)
178			}
179			out.Destroy()
180
181			out, err = arr.Get(txn, 1)
182			if err != nil {
183				t.Errorf("failed to get element 1: %v", err)
184			} else if v, ok := out.String(); !ok || v != "middle" {
185				t.Errorf("expected element 1='middle', got %v", v)
186			}
187			out.Destroy()
188
189			out, err = arr.Get(txn, 2)
190			if err != nil {
191				t.Errorf("failed to get element 2: %v", err)
192			} else if v, ok := out.String(); !ok || v != "second" {
193				t.Errorf("expected element 2='second', got %v", v)
194			}
195			out.Destroy()
196
197			out, err = arr.Get(txn, 3)
198			if err != nil {
199				t.Errorf("failed to get element 3: %v", err)
200			} else if v, ok := out.String(); !ok || v != "third" {
201				t.Errorf("expected element 3='third', got %v", v)
202			}
203			out.Destroy()
204
205			return nil
206		})
207		if err != nil {
208			t.Fatalf("array element verification failed: %v", err)
209		}
210	})
211
212	t.Run("nested XmlElement with attrs", func(t *testing.T) {
213		data, err := os.ReadFile("testdata/nested-XmlElement-with-attrs.yjs")
214		if err != nil {
215			t.Fatalf("failed to read testdata: %v", err)
216		}
217
218		doc, err := ygo.NewDoc()
219		if err != nil {
220			t.Fatalf("failed to create doc: %v", err)
221		}
222		defer doc.Destroy()
223
224		err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
225			update := ygo.UpdateFromBytes(data)
226			return txn.ApplyUpdate(update)
227		})
228		if err != nil {
229			t.Fatalf("failed to apply update: %v", err)
230		}
231
232		frag, err := doc.GetXmlFragment("test")
233		if err != nil {
234			t.Fatalf("failed to get xml fragment: %v", err)
235		}
236		defer frag.Destroy()
237
238		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
239			jsonBytes, err := frag.MarshalJSONWithTxn(txn)
240			if err != nil {
241				return err
242			}
243
244			var children []interface{}
245			if err := json.Unmarshal(jsonBytes, &children); err != nil {
246				return err
247			}
248
249			if len(children) < 1 {
250				t.Error("expected at least one child")
251				return nil
252			}
253
254			div, ok := children[0].(map[string]interface{})
255			if !ok {
256				t.Error("expected first child to be a map")
257				return nil
258			}
259
260			if div["type"] != "div" {
261				t.Errorf("expected type='div', got %v", div["type"])
262			}
263
264			attrs, ok := div["attrs"].(map[string]interface{})
265			if !ok {
266				t.Error("expected attrs to be a map")
267				return nil
268			}
269			if attrs["class"] != "container" {
270				t.Errorf("expected class='container', got %v", attrs["class"])
271			}
272			if attrs["data-id"] != "main" {
273				t.Errorf("expected data-id='main', got %v", attrs["data-id"])
274			}
275
276			childList, ok := div["children"].([]interface{})
277			if !ok {
278				t.Error("expected children to be a list")
279				return nil
280			}
281			if len(childList) != 2 {
282				t.Errorf("expected 2 children, got %d", len(childList))
283			}
284
285			return nil
286		})
287		if err != nil {
288			t.Fatalf("xml verification failed: %v", err)
289		}
290	})
291
292	t.Run("mixed content array", func(t *testing.T) {
293		data, err := os.ReadFile("testdata/mixed-content-array.yjs")
294		if err != nil {
295			t.Fatalf("failed to read testdata: %v", err)
296		}
297
298		doc, err := ygo.NewDoc()
299		if err != nil {
300			t.Fatalf("failed to create doc: %v", err)
301		}
302		defer doc.Destroy()
303
304		err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
305			update := ygo.UpdateFromBytes(data)
306			return txn.ApplyUpdate(update)
307		})
308		if err != nil {
309			t.Fatalf("failed to apply update: %v", err)
310		}
311
312		arr, err := doc.GetArray("test")
313		if err != nil {
314			t.Fatalf("failed to get array: %v", err)
315		}
316		defer arr.Destroy()
317
318		var length uint32
319		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
320			var err error
321			length = arr.Len()
322			return err
323		})
324		if err != nil {
325			t.Fatalf("failed to get array length: %v", err)
326		}
327
328		if length != 5 {
329			t.Errorf("expected array length 5, got %d", length)
330		}
331
332		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
333			out, err := arr.Get(txn, 0)
334			if err != nil {
335				t.Errorf("failed to get element 0: %v", err)
336			} else if v, ok := out.String(); !ok || v != "string" {
337				t.Errorf("expected element 0='string', got %v", v)
338			}
339			out.Destroy()
340
341			out, err = arr.Get(txn, 1)
342			if err != nil {
343				t.Errorf("failed to get element 1: %v", err)
344			} else if v, ok := out.Float(); !ok || v != 42 {
345				t.Errorf("expected element 1=42, got %v", v)
346			}
347			out.Destroy()
348
349			out, err = arr.Get(txn, 2)
350			if err != nil {
351				t.Errorf("failed to get element 2: %v", err)
352			} else if v, ok := out.Bool(); !ok || v != true {
353				t.Errorf("expected element 2=true, got %v", v)
354			}
355			out.Destroy()
356
357			out, err = arr.Get(txn, 3)
358			if err != nil {
359				t.Errorf("failed to get element 3: %v", err)
360			} else if !out.IsNull() {
361				t.Errorf("expected element 3=null")
362			}
363			out.Destroy()
364
365			out, err = arr.Get(txn, 4)
366			if err != nil {
367				t.Errorf("failed to get element 4: %v", err)
368			} else {
369				var obj map[string]interface{}
370				if err := out.JSON(&obj); err != nil {
371					t.Errorf("failed to parse JSON: %v", err)
372				} else {
373					if obj["nested"] != "object" {
374						t.Errorf("expected element 4.nested='object', got %v", obj["nested"])
375					}
376				}
377			}
378			out.Destroy()
379
380			return nil
381		})
382		if err != nil {
383			t.Fatalf("array element verification failed: %v", err)
384		}
385	})
386
387	t.Run("nested YMap in YMap", func(t *testing.T) {
388		data, err := os.ReadFile("testdata/nested-YMap-in-YMap.yjs")
389		if err != nil {
390			t.Fatalf("failed to read testdata: %v", err)
391		}
392
393		doc, err := ygo.NewDoc()
394		if err != nil {
395			t.Fatalf("failed to create doc: %v", err)
396		}
397		defer doc.Destroy()
398
399		err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
400			update := ygo.UpdateFromBytes(data)
401			return txn.ApplyUpdate(update)
402		})
403		if err != nil {
404			t.Fatalf("failed to apply update: %v", err)
405		}
406
407		m, err := doc.GetMap("test")
408		if err != nil {
409			t.Fatalf("failed to get map: %v", err)
410		}
411		defer m.Destroy()
412
413		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
414			out, err := m.Get(txn, "child")
415			if err != nil {
416				t.Fatalf("failed to get 'child': %v", err)
417			}
418			defer out.Destroy()
419
420			if out.Tag() != ygo.TagMap {
421				t.Fatalf("expected TagMap, got %v", out.Tag())
422			}
423
424			childMap, err := m.GetNestedMap(txn, "child")
425			if err != nil {
426				t.Fatalf("failed to get nested map: %v", err)
427			}
428			defer childMap.Destroy()
429
430			childOut, err := childMap.Get(txn, "key1")
431			if err != nil {
432				t.Fatalf("failed to get nested key1: %v", err)
433			}
434			defer childOut.Destroy()
435
436			val, ok := childOut.String()
437			if !ok || val != "value1" {
438				t.Errorf("expected 'value1', got %v", val)
439			}
440
441			childOut, err = childMap.Get(txn, "key2")
442			if err != nil {
443				t.Fatalf("failed to get nested key2: %v", err)
444			}
445			defer childOut.Destroy()
446
447			num, ok := childOut.Float()
448			if !ok || num != 42 {
449				t.Errorf("expected 42, got %v", num)
450			}
451
452			return nil
453		})
454		if err != nil {
455			t.Fatalf("nested map test failed: %v", err)
456		}
457	})
458
459	t.Run("nested YArray in YMap", func(t *testing.T) {
460		data, err := os.ReadFile("testdata/nested-YArray-in-YMap.yjs")
461		if err != nil {
462			t.Fatalf("failed to read testdata: %v", err)
463		}
464
465		doc, err := ygo.NewDoc()
466		if err != nil {
467			t.Fatalf("failed to create doc: %v", err)
468		}
469		defer doc.Destroy()
470
471		err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
472			update := ygo.UpdateFromBytes(data)
473			return txn.ApplyUpdate(update)
474		})
475		if err != nil {
476			t.Fatalf("failed to apply update: %v", err)
477		}
478
479		m, err := doc.GetMap("test")
480		if err != nil {
481			t.Fatalf("failed to get map: %v", err)
482		}
483		defer m.Destroy()
484
485		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
486			arr, err := m.GetNestedArray(txn, "arr")
487			if err != nil {
488				t.Fatalf("failed to get nested array: %v", err)
489			}
490			defer arr.Destroy()
491
492			length := arr.Len()
493			if length != 3 {
494				t.Errorf("expected length 3, got %d", length)
495			}
496
497			out, err := arr.Get(txn, 0)
498			if err != nil {
499				t.Fatalf("failed to get element 0: %v", err)
500			}
501			defer out.Destroy()
502
503			val, ok := out.String()
504			if !ok || val != "a" {
505				t.Errorf("expected 'a', got %v", val)
506			}
507
508			out, err = arr.Get(txn, 2)
509			if err != nil {
510				t.Fatalf("failed to get element 2: %v", err)
511			}
512			defer out.Destroy()
513
514			val, ok = out.String()
515			if !ok || val != "c" {
516				t.Errorf("expected 'c', got %v", val)
517			}
518
519			return nil
520		})
521		if err != nil {
522			t.Fatalf("nested array test failed: %v", err)
523		}
524	})
525
526	t.Run("nested YMap in YArray", func(t *testing.T) {
527		data, err := os.ReadFile("testdata/nested-YMap-in-YArray.yjs")
528		if err != nil {
529			t.Fatalf("failed to read testdata: %v", err)
530		}
531
532		doc, err := ygo.NewDoc()
533		if err != nil {
534			t.Fatalf("failed to create doc: %v", err)
535		}
536		defer doc.Destroy()
537
538		err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
539			update := ygo.UpdateFromBytes(data)
540			return txn.ApplyUpdate(update)
541		})
542		if err != nil {
543			t.Fatalf("failed to apply update: %v", err)
544		}
545
546		arr, err := doc.GetArray("test")
547		if err != nil {
548			t.Fatalf("failed to get array: %v", err)
549		}
550		defer arr.Destroy()
551
552		err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
553			length := arr.Len()
554			if length != 2 {
555				t.Errorf("expected length 2, got %d", length)
556			}
557
558			itemOut, err := arr.Get(txn, 0)
559			if err != nil {
560				t.Fatalf("failed to get element 0: %v", err)
561			}
562			defer itemOut.Destroy()
563
564			childMap, err := itemOut.ToMap()
565			if err != nil {
566				t.Fatalf("failed to convert to map: %v", err)
567			}
568			defer childMap.Destroy()
569
570			nameOut, err := childMap.Get(txn, "name")
571			if err != nil {
572				t.Fatalf("failed to get nested 'name': %v", err)
573			}
574			defer nameOut.Destroy()
575
576			val, ok := nameOut.String()
577			if !ok || val != "first" {
578				t.Errorf("expected 'first', got %v", val)
579			}
580
581			itemOut, err = arr.Get(txn, 1)
582			if err != nil {
583				t.Fatalf("failed to get element 1: %v", err)
584			}
585			defer itemOut.Destroy()
586
587			childMap, err = itemOut.ToMap()
588			if err != nil {
589				t.Fatalf("failed to convert to map: %v", err)
590			}
591
592			nameOut, err = childMap.Get(txn, "name")
593			if err != nil {
594				t.Fatalf("failed to get nested 'name' from element 1: %v", err)
595			}
596			defer nameOut.Destroy()
597
598			val, ok = nameOut.String()
599			if !ok || val != "second" {
600				t.Errorf("expected 'second', got %v", val)
601			}
602
603			return nil
604		})
605		if err != nil {
606			t.Fatalf("nested map in array test failed: %v", err)
607		}
608	})
609}