weak_test.go

  1package ygo_test
  2
  3import (
  4	"git.kilimanjaro.io/ygo"
  5	"testing"
  6)
  7
  8func TestWeakLinkText(t *testing.T) {
  9	// WARNING: This test is skipped due to a known memory corruption bug in the
 10	// underlying yffi library when using QuoteText. While QuoteText crashes less
 11	// frequently than QuoteArray, it still causes memory corruption that can lead
 12	// to crashes in subsequent tests or during garbage collection.
 13	//
 14	// Safe usage pattern for QuoteText (if you choose to use it despite the risk):
 15	//   1. Create ONE weak link per transaction
 16	//   2. Convert to Input immediately if you need to persist the link
 17	//   3. Call Destroy() on the Weak reference BEFORE the transaction callback returns
 18	//   4. Do NOT let the Weak reference escape the transaction scope
 19	t.Skip("Skipping - known yffi memory corruption when using QuoteText")
 20
 21	doc, err := ygo.NewDoc()
 22	if err != nil {
 23		t.Fatalf("failed to create doc: %v", err)
 24	}
 25	defer doc.Destroy()
 26
 27	txt, err := doc.GetText("text")
 28	if err != nil {
 29		t.Fatalf("failed to get text: %v", err)
 30	}
 31	defer txt.Destroy()
 32
 33	m, err := doc.GetMap("map")
 34	if err != nil {
 35		t.Fatalf("failed to get map: %v", err)
 36	}
 37	defer m.Destroy()
 38
 39	// Initialize text and create weak link using callback-based API
 40	var link *ygo.Weak
 41	err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
 42		// Initialize text
 43		txt.Insert(txn, 0, "hello world!")
 44
 45		// Create a text quotation (indices 2-10, exclusive of start, inclusive of end)
 46		var err error
 47		link, err = txt.QuoteText(txn, 2, 10, false, false)
 48		return err
 49	})
 50	if err != nil {
 51		t.Fatalf("transaction failed: %v", err)
 52	}
 53	defer link.Destroy()
 54
 55	// Store the link in map (need a new transaction for this)
 56	err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
 57		input, err := link.Input()
 58		if err != nil {
 59			return err
 60		}
 61		return m.Insert(txn, "text-link", input)
 62	})
 63	if err != nil {
 64		t.Fatalf("failed to insert link into map: %v", err)
 65	}
 66
 67	// Get the link back
 68	err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
 69		linkOut, err := m.Get(txn, "text-link")
 70		if err != nil {
 71			return err
 72		}
 73		defer linkOut.Destroy()
 74		return nil
 75	})
 76	if err != nil {
 77		t.Fatalf("failed to get link from map: %v", err)
 78	}
 79}
 80
 81func TestWeakLinkArrayCreateOnly(t *testing.T) {
 82	// WARNING: This test is skipped due to a known memory corruption bug in the
 83	// underlying yffi library when using QuoteArray. The memory corruption occurs
 84	// during garbage collection of weak references created via yarray_quote.
 85	//
 86	// Safe usage pattern: Always call Destroy() on the Weak reference BEFORE
 87	// committing the transaction, and only create ONE weak link per transaction.
 88	t.Skip("Skipping - known yffi memory corruption when using QuoteArray")
 89
 90	// Test that just creating and destroying a weak link works
 91	doc, err := ygo.NewDoc()
 92	if err != nil {
 93		t.Fatalf("failed to create doc: %v", err)
 94	}
 95	defer doc.Destroy()
 96
 97	arr, err := doc.GetArray("array")
 98	if err != nil {
 99		t.Fatalf("failed to get array: %v", err)
100	}
101	defer arr.Destroy()
102
103	// Initialize array and create weak link using callback-based API
104	err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
105		// Initialize array
106		arr.InsertRange(txn, 0, []ygo.Input{ygo.Int(1), ygo.Int(2), ygo.Int(3), ygo.Int(4)})
107
108		// Create weak link
109		link, err := arr.QuoteArray(txn, 1, 3, false, true)
110		if err != nil {
111			return err
112		}
113
114		// Immediately destroy without using
115		link.Destroy()
116		return nil
117	})
118	if err != nil {
119		t.Fatalf("transaction failed: %v", err)
120	}
121}
122
123func TestWeakLinkArrayInputOnly(t *testing.T) {
124	// WARNING: This test is skipped due to a known memory corruption bug in the
125	// underlying yffi library when using QuoteArray. The memory corruption occurs
126	// during garbage collection of weak references created via yarray_quote.
127	//
128	// Safe usage pattern: Always call Destroy() on the Weak reference BEFORE
129	// committing the transaction, and only create ONE weak link per transaction.
130	t.Skip("Skipping - known yffi memory corruption when using QuoteArray")
131
132	// Test calling Input() without inserting into map
133	doc, err := ygo.NewDoc()
134	if err != nil {
135		t.Fatalf("failed to create doc: %v", err)
136	}
137	defer doc.Destroy()
138
139	arr, err := doc.GetArray("array")
140	if err != nil {
141		t.Fatalf("failed to get array: %v", err)
142	}
143	defer arr.Destroy()
144
145	// Initialize array and create weak link using callback-based API
146	err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
147		// Initialize array
148		arr.InsertRange(txn, 0, []ygo.Input{ygo.Int(1), ygo.Int(2), ygo.Int(3), ygo.Int(4)})
149
150		// Create weak link
151		link, err := arr.QuoteArray(txn, 1, 3, false, true)
152		if err != nil {
153			return err
154		}
155
156		// Call Input() but don't use it
157		_, err = link.Input()
158		if err != nil {
159			return err
160		}
161
162		// Destroy
163		link.Destroy()
164		return nil
165	})
166	if err != nil {
167		t.Fatalf("transaction failed: %v", err)
168	}
169}
170
171func TestWeakLinkArrayFullWorkflow(t *testing.T) {
172	// This test is skipped due to a known memory corruption bug in the underlying
173	// yffi library when using QuoteArray. The memory corruption occurs when:
174	// 1. Multiple weak links are created
175	// 2. Weak links are inserted into maps/arrays
176	// 3. The weak link outlives the transaction
177	//
178	// Safe usage pattern: Always call Destroy() on the Weak reference BEFORE
179	// committing the transaction, and only create ONE weak link per transaction.
180	t.Skip("Skipping - known yffi memory corruption when using QuoteArray with maps")
181
182	doc, err := ygo.NewDoc()
183	if err != nil {
184		t.Fatalf("failed to create doc: %v", err)
185	}
186	defer doc.Destroy()
187
188	arr, err := doc.GetArray("array")
189	if err != nil {
190		t.Fatalf("failed to get array: %v", err)
191	}
192	defer arr.Destroy()
193
194	m, err := doc.GetMap("map")
195	if err != nil {
196		t.Fatalf("failed to get map: %v", err)
197	}
198	defer m.Destroy()
199
200	var link *ygo.Weak
201
202	// Initialize array and create weak link using callback-based API
203	err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
204		// Initialize array
205		arr.InsertRange(txn, 0, []ygo.Input{ygo.Int(1), ygo.Int(2), ygo.Int(3), ygo.Int(4)})
206
207		// Create weak link
208		var err error
209		link, err = arr.QuoteArray(txn, 1, 3, false, true)
210		if err != nil {
211			return err
212		}
213
214		// Convert to input
215		input, err := link.Input()
216		if err != nil {
217			return err
218		}
219
220		// Insert into map - THIS IS THE PROBLEMATIC OPERATION
221		return m.Insert(txn, "array-link", input)
222	})
223	if err != nil {
224		t.Fatalf("transaction failed: %v", err)
225	}
226
227	// Try different cleanup orders
228	link.Destroy()
229}