map_test.go
1package ygo_test
2
3import (
4 "encoding/json"
5 "git.kilimanjaro.io/ygo"
6 "testing"
7)
8
9func TestMapBasic(t *testing.T) {
10 doc, err := ygo.NewDoc()
11 if err != nil {
12 t.Fatalf("failed to create doc: %v", err)
13 }
14 defer doc.Destroy()
15
16 m, err := doc.GetMap("test")
17 if err != nil {
18 t.Fatalf("failed to get map: %v", err)
19 }
20 defer m.Destroy()
21
22 var length uint32
23 var removed1, removed2 bool
24 var out *ygo.Output
25
26 err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
27 // Insert values
28 m.Insert(txn, "a", ygo.String("value"))
29
30 // Insert JSON array
31 arrayItems := []ygo.Input{ygo.Int(11), ygo.Int(22)}
32 m.Insert(txn, "b", ygo.JSONArray(arrayItems))
33
34 length = m.Len(txn)
35
36 // Remove key twice
37 removed1, err = m.Remove(txn, "a")
38 if err != nil {
39 return err
40 }
41 removed2, err = m.Remove(txn, "a")
42 if err != nil {
43 return err
44 }
45
46 // Get remaining value
47 out, err = m.Get(txn, "b")
48 if err != nil {
49 return err
50 }
51
52 // Clear map
53 m.Clear(txn)
54 length = m.Len(txn)
55 return nil
56 })
57 if err != nil {
58 t.Fatalf("transaction failed: %v", err)
59 }
60 defer out.Destroy()
61
62 // Check results after transaction
63 if length != 0 {
64 t.Errorf("expected length 0 after clear, got %d", length)
65 }
66
67 if !removed1 {
68 t.Error("expected first remove to return true")
69 }
70 if removed2 {
71 t.Error("expected second remove to return false")
72 }
73
74 // Verify we got something back
75 if out.IsUndefined() {
76 t.Error("expected non-undefined output")
77 }
78}
79
80func TestMapNested(t *testing.T) {
81 doc, err := ygo.NewDoc()
82 if err != nil {
83 t.Fatalf("failed to create doc: %v", err)
84 }
85 defer doc.Destroy()
86
87 m, err := doc.GetMap("test")
88 if err != nil {
89 t.Fatalf("failed to get map: %v", err)
90 }
91 defer m.Destroy()
92
93 var length uint32
94 var out *ygo.Output
95
96 err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
97 // Insert nested maps
98 innerValue := ygo.String("Nested data")
99 innerMap, mapErr := ygo.YMap([]string{"text"}, []ygo.Input{innerValue})
100 if mapErr != nil {
101 return mapErr
102 }
103 outerMap, mapErr := ygo.YMap([]string{"innerMap"}, []ygo.Input{innerMap})
104 if mapErr != nil {
105 return mapErr
106 }
107
108 m.Insert(txn, "outerMap", outerMap)
109
110 length = m.Len(txn)
111
112 // Retrieve and verify nested structure
113 out, err = m.Get(txn, "outerMap")
114 return err
115 })
116 if err != nil {
117 t.Fatalf("transaction failed: %v", err)
118 }
119 defer out.Destroy()
120
121 // Check results after transaction
122 if length != 1 {
123 t.Errorf("expected length 1, got %d", length)
124 }
125
126 // Should be a map type
127 if out.IsUndefined() {
128 t.Fatal("expected map output, got undefined")
129 }
130}
131
132func collectMapEntries(m *ygo.Map, txn *ygo.Transaction) (map[string]interface{}, error) {
133 iter, err := m.Iter(txn)
134 if err != nil {
135 return nil, err
136 }
137 defer iter.Destroy()
138
139 entries := make(map[string]interface{})
140 for {
141 entry, err := iter.Next()
142 if err != nil {
143 return nil, err
144 }
145 if entry == nil {
146 break
147 }
148
149 // Convert value based on type
150 var value interface{}
151 switch entry.Value.Tag() {
152 case ygo.TagJSONBool:
153 if v, ok := entry.Value.Bool(); ok {
154 value = v
155 }
156 case ygo.TagJSONNum:
157 if v, ok := entry.Value.Float(); ok {
158 value = v
159 }
160 case ygo.TagJSONInt:
161 if v, ok := entry.Value.Int(); ok {
162 value = v
163 }
164 case ygo.TagJSONStr:
165 if v, ok := entry.Value.String(); ok {
166 value = v
167 }
168 case ygo.TagJSONNull:
169 value = nil
170 default:
171 value = nil
172 }
173
174 entries[entry.Key] = value
175 // Note: Don't destroy entry.Value - it's managed by the entry
176 // The iterator will clean up entries when destroyed
177 }
178 return entries, nil
179}
180
181func TestMapIter(t *testing.T) {
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 m, err := doc.GetMap("test")
189 if err != nil {
190 t.Fatalf("failed to get map: %v", err)
191 }
192 defer m.Destroy()
193
194 // Insert test data
195 err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
196 m.Insert(txn, "key1", ygo.String("value1"))
197 m.Insert(txn, "key2", ygo.Int(42))
198 m.Insert(txn, "key3", ygo.Bool(true))
199 return nil
200 })
201 if err != nil {
202 t.Fatalf("transaction failed: %v", err)
203 }
204
205 // Test iteration
206 var entries map[string]interface{}
207 err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
208 var err error
209 entries, err = collectMapEntries(m, txn)
210 return err
211 })
212 if err != nil {
213 t.Fatalf("iteration failed: %v", err)
214 }
215
216 if len(entries) != 3 {
217 t.Errorf("expected 3 entries, got %d", len(entries))
218 }
219 if entries["key1"] != "value1" {
220 t.Errorf("expected key1=value1, got %v", entries["key1"])
221 }
222 if entries["key2"] != int64(42) {
223 t.Errorf("expected key2=42, got %v", entries["key2"])
224 }
225 if entries["key3"] != true {
226 t.Errorf("expected key3=true, got %v", entries["key3"])
227 }
228}
229
230func TestMapMarshalJSON(t *testing.T) {
231 doc, err := ygo.NewDoc()
232 if err != nil {
233 t.Fatalf("failed to create doc: %v", err)
234 }
235 defer doc.Destroy()
236
237 m, err := doc.GetMap("test")
238 if err != nil {
239 t.Fatalf("failed to get map: %v", err)
240 }
241 defer m.Destroy()
242
243 err = doc.WithWriteTransaction(func(txn *ygo.Transaction) error {
244 m.Insert(txn, "string", ygo.String("hello"))
245 m.Insert(txn, "number", ygo.Int(42))
246 m.Insert(txn, "float", ygo.Float(3.14))
247 m.Insert(txn, "bool", ygo.Bool(true))
248 m.Insert(txn, "null", ygo.Null())
249 return nil
250 })
251 if err != nil {
252 t.Fatalf("transaction failed: %v", err)
253 }
254
255 // Marshal within read transaction
256 var jsonBytes []byte
257 err = doc.WithReadTransaction(func(txn *ygo.Transaction) error {
258 var err error
259 jsonBytes, err = m.MarshalJSONWithTxn(txn)
260 return err
261 })
262 if err != nil {
263 t.Fatalf("marshal failed: %v", err)
264 }
265
266 // Verify JSON is valid
267 var result map[string]interface{}
268 if err := json.Unmarshal(jsonBytes, &result); err != nil {
269 t.Fatalf("failed to unmarshal result: %v", err)
270 }
271
272 // Check values (order doesn't matter for maps)
273 if result["string"] != "hello" {
274 t.Errorf("expected string=hello, got %v", result["string"])
275 }
276 if result["number"] != float64(42) {
277 t.Errorf("expected number=42, got %v", result["number"])
278 }
279 if result["float"] != 3.14 {
280 t.Errorf("expected float=3.14, got %v", result["float"])
281 }
282 if result["bool"] != true {
283 t.Errorf("expected bool=true, got %v", result["bool"])
284 }
285 if result["null"] != nil {
286 t.Errorf("expected null=nil, got %v", result["null"])
287 }
288}