testMaps_test.go 10.9 KB
Newer Older
Eric Myhre's avatar
Eric Myhre committed
1 2 3 4 5
package gengo

import (
	"testing"

6
	. "github.com/warpfork/go-wish"
Eric Myhre's avatar
Eric Myhre committed
7 8

	"github.com/ipld/go-ipld-prime"
9 10
	"github.com/ipld/go-ipld-prime/fluent"
	"github.com/ipld/go-ipld-prime/must"
Eric Myhre's avatar
Eric Myhre committed
11 12 13 14
	"github.com/ipld/go-ipld-prime/schema"
)

func TestMapsContainingMaybe(t *testing.T) {
15 16
	t.Parallel()

Eric Myhre's avatar
Eric Myhre committed
17 18 19 20 21 22 23
	ts := schema.TypeSystem{}
	ts.Init()
	adjCfg := &AdjunctCfg{
		maybeUsesPtr: map[schema.TypeName]bool{},
	}
	ts.Accumulate(schema.SpawnString("String"))
	ts.Accumulate(schema.SpawnMap("Map__String__String",
24
		"String", "String", false))
Eric Myhre's avatar
Eric Myhre committed
25
	ts.Accumulate(schema.SpawnMap("Map__String__nullableString",
26
		"String", "String", true))
Eric Myhre's avatar
Eric Myhre committed
27

28
	test := func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
29
		t.Run("non-nullable", func(t *testing.T) {
30 31
			np := getPrototypeByName("Map__String__String")
			nrp := getPrototypeByName("Map__String__String.Repr")
32 33
			var n schema.TypedNode
			t.Run("typed-create", func(t *testing.T) {
34
				n = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) {
35 36 37 38
					ma.AssembleEntry("one").AssignString("1")
					ma.AssembleEntry("two").AssignString("2")
				}).(schema.TypedNode)
				t.Run("typed-read", func(t *testing.T) {
39
					Require(t, n.Kind(), ShouldEqual, ipld.Kind_Map)
40
					Wish(t, n.Length(), ShouldEqual, int64(2))
41 42 43
					Wish(t, must.String(must.Node(n.LookupByString("one"))), ShouldEqual, "1")
					Wish(t, must.String(must.Node(n.LookupByString("two"))), ShouldEqual, "2")
					_, err := n.LookupByString("miss")
44 45 46 47
					Wish(t, err, ShouldBeSameTypeAs, ipld.ErrNotExists{})
				})
				t.Run("repr-read", func(t *testing.T) {
					nr := n.Representation()
48
					Require(t, nr.Kind(), ShouldEqual, ipld.Kind_Map)
49
					Wish(t, nr.Length(), ShouldEqual, int64(2))
50 51 52
					Wish(t, must.String(must.Node(nr.LookupByString("one"))), ShouldEqual, "1")
					Wish(t, must.String(must.Node(nr.LookupByString("two"))), ShouldEqual, "2")
					_, err := nr.LookupByString("miss")
53 54 55 56
					Wish(t, err, ShouldBeSameTypeAs, ipld.ErrNotExists{})
				})
			})
			t.Run("repr-create", func(t *testing.T) {
57
				nr := fluent.MustBuildMap(nrp, 2, func(ma fluent.MapAssembler) {
58 59 60
					ma.AssembleEntry("one").AssignString("1")
					ma.AssembleEntry("two").AssignString("2")
				})
61
				Wish(t, ipld.DeepEqual(n, nr), ShouldEqual, true)
62 63 64
			})
		})
		t.Run("nullable", func(t *testing.T) {
65 66
			np := getPrototypeByName("Map__String__nullableString")
			nrp := getPrototypeByName("Map__String__nullableString.Repr")
67 68
			var n schema.TypedNode
			t.Run("typed-create", func(t *testing.T) {
69
				n = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) {
70 71 72 73
					ma.AssembleEntry("one").AssignString("1")
					ma.AssembleEntry("none").AssignNull()
				}).(schema.TypedNode)
				t.Run("typed-read", func(t *testing.T) {
74
					Require(t, n.Kind(), ShouldEqual, ipld.Kind_Map)
75
					Wish(t, n.Length(), ShouldEqual, int64(2))
76 77 78
					Wish(t, must.String(must.Node(n.LookupByString("one"))), ShouldEqual, "1")
					Wish(t, must.Node(n.LookupByString("none")), ShouldEqual, ipld.Null)
					_, err := n.LookupByString("miss")
79 80 81 82
					Wish(t, err, ShouldBeSameTypeAs, ipld.ErrNotExists{})
				})
				t.Run("repr-read", func(t *testing.T) {
					nr := n.Representation()
83
					Require(t, nr.Kind(), ShouldEqual, ipld.Kind_Map)
84
					Wish(t, nr.Length(), ShouldEqual, int64(2))
85 86 87
					Wish(t, must.String(must.Node(nr.LookupByString("one"))), ShouldEqual, "1")
					Wish(t, must.Node(nr.LookupByString("none")), ShouldEqual, ipld.Null)
					_, err := nr.LookupByString("miss")
88 89 90 91
					Wish(t, err, ShouldBeSameTypeAs, ipld.ErrNotExists{})
				})
			})
			t.Run("repr-create", func(t *testing.T) {
92
				nr := fluent.MustBuildMap(nrp, 2, func(ma fluent.MapAssembler) {
93 94 95
					ma.AssembleEntry("one").AssignString("1")
					ma.AssembleEntry("none").AssignNull()
				})
96
				Wish(t, ipld.DeepEqual(n, nr), ShouldEqual, true)
97 98 99 100
			})
		})
	}

Eric Myhre's avatar
Eric Myhre committed
101 102 103 104 105
	t.Run("maybe-using-embed", func(t *testing.T) {
		adjCfg.maybeUsesPtr["String"] = false

		prefix := "maps-embed"
		pkgName := "main"
106 107
		genAndCompileAndTest(t, prefix, pkgName, ts, adjCfg, func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
			test(t, getPrototypeByName)
Eric Myhre's avatar
Eric Myhre committed
108 109 110 111 112 113 114
		})
	})
	t.Run("maybe-using-ptr", func(t *testing.T) {
		adjCfg.maybeUsesPtr["String"] = true

		prefix := "maps-mptr"
		pkgName := "main"
115 116
		genAndCompileAndTest(t, prefix, pkgName, ts, adjCfg, func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
			test(t, getPrototypeByName)
Eric Myhre's avatar
Eric Myhre committed
117 118 119
		})
	})
}
120

121 122 123 124
// TestMapsContainingMaps is probing *two* things:
//   - that maps can nest, obviously
//   - that representation semantics are held correctly when we recurse, both in builders and in reading
// To cover that latter situation, this depends on structs (so we can use rename directives on the representation to make it distinctive).
125
func TestMapsContainingMaps(t *testing.T) {
126 127
	t.Parallel()

128 129 130 131 132 133
	ts := schema.TypeSystem{}
	ts.Init()
	adjCfg := &AdjunctCfg{
		maybeUsesPtr: map[schema.TypeName]bool{},
	}
	ts.Accumulate(schema.SpawnString("String"))
134 135
	ts.Accumulate(schema.SpawnStruct("Frub", // "type Frub struct { field String (rename "encoded") }"
		[]schema.StructField{
136
			schema.SpawnStructField("field", "String", false, false), // plain field.
137 138 139 140 141 142
		},
		schema.SpawnStructRepresentationMap(map[string]string{
			"field": "encoded",
		}),
	))
	ts.Accumulate(schema.SpawnMap("Map__String__Frub", // "{String:Frub}"
143
		"String", "Frub", false))
144
	ts.Accumulate(schema.SpawnMap("Map__String__nullableMap__String__Frub", // "{String:nullable {String:Frub}}"
145
		"String", "Map__String__Frub", true))
146 147 148

	prefix := "maps-recursive"
	pkgName := "main"
149 150 151 152 153
	genAndCompileAndTest(t, prefix, pkgName, ts, adjCfg, func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
		np := getPrototypeByName("Map__String__nullableMap__String__Frub")
		nrp := getPrototypeByName("Map__String__nullableMap__String__Frub.Repr")
		creation := func(t *testing.T, np ipld.NodePrototype, fieldName string) schema.TypedNode {
			return fluent.MustBuildMap(np, 3, func(ma fluent.MapAssembler) {
154 155 156
				ma.AssembleEntry("one").CreateMap(2, func(ma fluent.MapAssembler) {
					ma.AssembleEntry("zot").CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(fieldName).AssignString("11") })
					ma.AssembleEntry("zop").CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(fieldName).AssignString("12") })
157 158
				})
				ma.AssembleEntry("two").CreateMap(1, func(ma fluent.MapAssembler) {
159
					ma.AssembleEntry("zim").CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(fieldName).AssignString("21") })
160 161 162
				})
				ma.AssembleEntry("none").AssignNull()
			}).(schema.TypedNode)
163 164 165
		}
		reading := func(t *testing.T, n ipld.Node, fieldName string) {
			withNode(n, func(n ipld.Node) {
166
				Require(t, n.Kind(), ShouldEqual, ipld.Kind_Map)
167
				Wish(t, n.Length(), ShouldEqual, int64(3))
168
				withNode(must.Node(n.LookupByString("one")), func(n ipld.Node) {
169
					Require(t, n.Kind(), ShouldEqual, ipld.Kind_Map)
170
					Wish(t, n.Length(), ShouldEqual, int64(2))
171
					withNode(must.Node(n.LookupByString("zot")), func(n ipld.Node) {
172
						Require(t, n.Kind(), ShouldEqual, ipld.Kind_Map)
173
						Wish(t, n.Length(), ShouldEqual, int64(1))
174
						Wish(t, must.String(must.Node(n.LookupByString(fieldName))), ShouldEqual, "11")
175
					})
176
					withNode(must.Node(n.LookupByString("zop")), func(n ipld.Node) {
177
						Require(t, n.Kind(), ShouldEqual, ipld.Kind_Map)
178
						Wish(t, n.Length(), ShouldEqual, int64(1))
179
						Wish(t, must.String(must.Node(n.LookupByString(fieldName))), ShouldEqual, "12")
180 181
					})
				})
182
				withNode(must.Node(n.LookupByString("two")), func(n ipld.Node) {
183
					Wish(t, n.Length(), ShouldEqual, int64(1))
184
					withNode(must.Node(n.LookupByString("zim")), func(n ipld.Node) {
185
						Require(t, n.Kind(), ShouldEqual, ipld.Kind_Map)
186
						Wish(t, n.Length(), ShouldEqual, int64(1))
187
						Wish(t, must.String(must.Node(n.LookupByString(fieldName))), ShouldEqual, "21")
188 189
					})
				})
190
				withNode(must.Node(n.LookupByString("none")), func(n ipld.Node) {
191 192
					Wish(t, n, ShouldEqual, ipld.Null)
				})
193
				_, err := n.LookupByString("miss")
194 195
				Wish(t, err, ShouldBeSameTypeAs, ipld.ErrNotExists{})
			})
196 197 198
		}
		var n schema.TypedNode
		t.Run("typed-create", func(t *testing.T) {
199
			n = creation(t, np, "field")
200 201 202
			t.Run("typed-read", func(t *testing.T) {
				reading(t, n, "field")
			})
203
			t.Run("repr-read", func(t *testing.T) {
204
				reading(t, n.Representation(), "encoded")
205 206 207
			})
		})
		t.Run("repr-create", func(t *testing.T) {
208
			nr := creation(t, nrp, "encoded")
209
			Wish(t, ipld.DeepEqual(n, nr), ShouldEqual, true)
210
		})
211 212
	})
}
213

214
func TestMapsWithComplexKeys(t *testing.T) {
215 216
	t.Parallel()

217 218 219 220 221 222 223 224
	ts := schema.TypeSystem{}
	ts.Init()
	adjCfg := &AdjunctCfg{
		maybeUsesPtr: map[schema.TypeName]bool{},
	}
	ts.Accumulate(schema.SpawnString("String"))
	ts.Accumulate(schema.SpawnStruct("StringyStruct",
		[]schema.StructField{
225 226
			schema.SpawnStructField("foo", "String", false, false),
			schema.SpawnStructField("bar", "String", false, false),
227 228 229 230
		},
		schema.SpawnStructRepresentationStringjoin(":"),
	))
	ts.Accumulate(schema.SpawnMap("Map__StringyStruct__String",
231
		"StringyStruct", "String", false))
232 233 234

	prefix := "maps-cmplx-keys"
	pkgName := "main"
235 236 237
	genAndCompileAndTest(t, prefix, pkgName, ts, adjCfg, func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
		np := getPrototypeByName("Map__StringyStruct__String")
		nrp := getPrototypeByName("Map__StringyStruct__String.Repr")
238 239
		var n schema.TypedNode
		t.Run("typed-create", func(t *testing.T) {
240
			n = fluent.MustBuildMap(np, 3, func(ma fluent.MapAssembler) {
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
				ma.AssembleKey().CreateMap(2, func(ma fluent.MapAssembler) {
					ma.AssembleEntry("foo").AssignString("a")
					ma.AssembleEntry("bar").AssignString("b")
				})
				ma.AssembleValue().AssignString("1")
				ma.AssembleKey().CreateMap(2, func(ma fluent.MapAssembler) {
					ma.AssembleEntry("foo").AssignString("c")
					ma.AssembleEntry("bar").AssignString("d")
				})
				ma.AssembleValue().AssignString("2")
				ma.AssembleKey().CreateMap(2, func(ma fluent.MapAssembler) {
					ma.AssembleEntry("foo").AssignString("e")
					ma.AssembleEntry("bar").AssignString("f")
				})
				ma.AssembleValue().AssignString("3")
			}).(schema.TypedNode)
			t.Run("typed-read", func(t *testing.T) {
258
				Require(t, n.Kind(), ShouldEqual, ipld.Kind_Map)
259
				Wish(t, n.Length(), ShouldEqual, int64(3))
260
				n2 := must.Node(n.LookupByString("c:d"))
261
				Require(t, n2.Kind(), ShouldEqual, ipld.Kind_String)
262 263 264 265
				Wish(t, must.String(n2), ShouldEqual, "2")
			})
			t.Run("repr-read", func(t *testing.T) {
				nr := n.Representation()
266
				Require(t, nr.Kind(), ShouldEqual, ipld.Kind_Map)
267
				Wish(t, nr.Length(), ShouldEqual, int64(3))
268
				n2 := must.Node(nr.LookupByString("c:d"))
269
				Require(t, n2.Kind(), ShouldEqual, ipld.Kind_String)
270 271 272 273
				Wish(t, must.String(n2), ShouldEqual, "2")
			})
		})
		t.Run("repr-create", func(t *testing.T) {
274
			nr := fluent.MustBuildMap(nrp, 3, func(ma fluent.MapAssembler) {
275 276 277 278
				ma.AssembleEntry("a:b").AssignString("1")
				ma.AssembleEntry("c:d").AssignString("2")
				ma.AssembleEntry("e:f").AssignString("3")
			})
279
			Wish(t, ipld.DeepEqual(n, nr), ShouldEqual, true)
280 281 282
		})
	})
}