github.com/ipld/go-ipld-prime@v0.21.0/node/tests/schemaMaps.go (about) 1 package tests 2 3 import ( 4 "testing" 5 6 qt "github.com/frankban/quicktest" 7 8 "github.com/ipld/go-ipld-prime/datamodel" 9 "github.com/ipld/go-ipld-prime/fluent" 10 "github.com/ipld/go-ipld-prime/must" 11 "github.com/ipld/go-ipld-prime/schema" 12 ) 13 14 func SchemaTestMapsContainingMaybe(t *testing.T, engine Engine) { 15 ts := schema.TypeSystem{} 16 ts.Init() 17 ts.Accumulate(schema.SpawnString("String")) 18 ts.Accumulate(schema.SpawnMap("Map__String__String", 19 "String", "String", false)) 20 ts.Accumulate(schema.SpawnMap("Map__String__nullableString", 21 "String", "String", true)) 22 engine.Init(t, ts) 23 24 t.Run("non-nullable", func(t *testing.T) { 25 np := engine.PrototypeByName("Map__String__String") 26 nrp := engine.PrototypeByName("Map__String__String.Repr") 27 var n schema.TypedNode 28 t.Run("typed-create", func(t *testing.T) { 29 n = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) { 30 ma.AssembleEntry("one").AssignString("1") 31 ma.AssembleEntry("two").AssignString("2") 32 }).(schema.TypedNode) 33 t.Run("typed-read", func(t *testing.T) { 34 qt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map) 35 qt.Check(t, n.Length(), qt.Equals, int64(2)) 36 qt.Check(t, must.String(must.Node(n.LookupByString("one"))), qt.Equals, "1") 37 qt.Check(t, must.String(must.Node(n.LookupByString("two"))), qt.Equals, "2") 38 _, err := n.LookupByString("miss") 39 qt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{}) 40 }) 41 t.Run("repr-read", func(t *testing.T) { 42 nr := n.Representation() 43 qt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_Map) 44 qt.Check(t, nr.Length(), qt.Equals, int64(2)) 45 qt.Check(t, must.String(must.Node(nr.LookupByString("one"))), qt.Equals, "1") 46 qt.Check(t, must.String(must.Node(nr.LookupByString("two"))), qt.Equals, "2") 47 _, err := nr.LookupByString("miss") 48 qt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{}) 49 }) 50 }) 51 t.Run("repr-create", func(t *testing.T) { 52 nr := fluent.MustBuildMap(nrp, 2, func(ma fluent.MapAssembler) { 53 ma.AssembleEntry("one").AssignString("1") 54 ma.AssembleEntry("two").AssignString("2") 55 }) 56 qt.Check(t, n, NodeContentEquals, nr) 57 }) 58 }) 59 t.Run("nullable", func(t *testing.T) { 60 np := engine.PrototypeByName("Map__String__nullableString") 61 nrp := engine.PrototypeByName("Map__String__nullableString.Repr") 62 var n schema.TypedNode 63 t.Run("typed-create", func(t *testing.T) { 64 n = fluent.MustBuildMap(np, 2, func(ma fluent.MapAssembler) { 65 ma.AssembleEntry("one").AssignString("1") 66 ma.AssembleEntry("none").AssignNull() 67 }).(schema.TypedNode) 68 t.Run("typed-read", func(t *testing.T) { 69 qt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map) 70 qt.Check(t, n.Length(), qt.Equals, int64(2)) 71 qt.Check(t, must.String(must.Node(n.LookupByString("one"))), qt.Equals, "1") 72 qt.Check(t, must.Node(n.LookupByString("none")), qt.Equals, datamodel.Null) 73 _, err := n.LookupByString("miss") 74 qt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{}) 75 }) 76 t.Run("repr-read", func(t *testing.T) { 77 nr := n.Representation() 78 qt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_Map) 79 qt.Check(t, nr.Length(), qt.Equals, int64(2)) 80 qt.Check(t, must.String(must.Node(nr.LookupByString("one"))), qt.Equals, "1") 81 qt.Check(t, must.Node(nr.LookupByString("none")), qt.Equals, datamodel.Null) 82 _, err := nr.LookupByString("miss") 83 qt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{}) 84 }) 85 }) 86 t.Run("repr-create", func(t *testing.T) { 87 nr := fluent.MustBuildMap(nrp, 2, func(ma fluent.MapAssembler) { 88 ma.AssembleEntry("one").AssignString("1") 89 ma.AssembleEntry("none").AssignNull() 90 }) 91 qt.Check(t, n, NodeContentEquals, nr) 92 }) 93 }) 94 } 95 96 // TestMapsContainingMaps is probing *two* things: 97 // - that maps can nest, obviously 98 // - that representation semantics are held correctly when we recurse, both in builders and in reading 99 // 100 // To cover that latter situation, this depends on structs (so we can use rename directives on the representation to make it distinctive). 101 func SchemaTestMapsContainingMaps(t *testing.T, engine Engine) { 102 ts := schema.TypeSystem{} 103 ts.Init() 104 ts.Accumulate(schema.SpawnString("String")) 105 ts.Accumulate(schema.SpawnStruct("Frub", // "type Frub struct { field String (rename "encoded") }" 106 []schema.StructField{ 107 schema.SpawnStructField("field", "String", false, false), // plain field. 108 }, 109 schema.SpawnStructRepresentationMap(map[string]string{ 110 "field": "encoded", 111 }), 112 )) 113 ts.Accumulate(schema.SpawnMap("Map__String__Frub", // "{String:Frub}" 114 "String", "Frub", false)) 115 ts.Accumulate(schema.SpawnMap("Map__String__nullableMap__String__Frub", // "{String:nullable {String:Frub}}" 116 "String", "Map__String__Frub", true)) 117 engine.Init(t, ts) 118 119 np := engine.PrototypeByName("Map__String__nullableMap__String__Frub") 120 nrp := engine.PrototypeByName("Map__String__nullableMap__String__Frub.Repr") 121 creation := func(t *testing.T, np datamodel.NodePrototype, fieldName string) schema.TypedNode { 122 return fluent.MustBuildMap(np, 3, func(ma fluent.MapAssembler) { 123 ma.AssembleEntry("one").CreateMap(2, func(ma fluent.MapAssembler) { 124 ma.AssembleEntry("zot").CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(fieldName).AssignString("11") }) 125 ma.AssembleEntry("zop").CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(fieldName).AssignString("12") }) 126 }) 127 ma.AssembleEntry("two").CreateMap(1, func(ma fluent.MapAssembler) { 128 ma.AssembleEntry("zim").CreateMap(1, func(ma fluent.MapAssembler) { ma.AssembleEntry(fieldName).AssignString("21") }) 129 }) 130 ma.AssembleEntry("none").AssignNull() 131 }).(schema.TypedNode) 132 } 133 reading := func(t *testing.T, n datamodel.Node, fieldName string) { 134 withNode(n, func(n datamodel.Node) { 135 qt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map) 136 qt.Check(t, n.Length(), qt.Equals, int64(3)) 137 withNode(must.Node(n.LookupByString("one")), func(n datamodel.Node) { 138 qt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map) 139 qt.Check(t, n.Length(), qt.Equals, int64(2)) 140 withNode(must.Node(n.LookupByString("zot")), func(n datamodel.Node) { 141 qt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map) 142 qt.Check(t, n.Length(), qt.Equals, int64(1)) 143 qt.Check(t, must.String(must.Node(n.LookupByString(fieldName))), qt.Equals, "11") 144 }) 145 withNode(must.Node(n.LookupByString("zop")), func(n datamodel.Node) { 146 qt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map) 147 qt.Check(t, n.Length(), qt.Equals, int64(1)) 148 qt.Check(t, must.String(must.Node(n.LookupByString(fieldName))), qt.Equals, "12") 149 }) 150 }) 151 withNode(must.Node(n.LookupByString("two")), func(n datamodel.Node) { 152 qt.Check(t, n.Length(), qt.Equals, int64(1)) 153 withNode(must.Node(n.LookupByString("zim")), func(n datamodel.Node) { 154 qt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map) 155 qt.Check(t, n.Length(), qt.Equals, int64(1)) 156 qt.Check(t, must.String(must.Node(n.LookupByString(fieldName))), qt.Equals, "21") 157 }) 158 }) 159 withNode(must.Node(n.LookupByString("none")), func(n datamodel.Node) { 160 qt.Check(t, n, NodeContentEquals, datamodel.Null) 161 }) 162 _, err := n.LookupByString("miss") 163 qt.Check(t, err, qt.ErrorAs, &datamodel.ErrNotExists{}) 164 }) 165 } 166 var n schema.TypedNode 167 t.Run("typed-create", func(t *testing.T) { 168 n = creation(t, np, "field") 169 t.Run("typed-read", func(t *testing.T) { 170 reading(t, n, "field") 171 }) 172 t.Run("repr-read", func(t *testing.T) { 173 reading(t, n.Representation(), "encoded") 174 }) 175 }) 176 t.Run("repr-create", func(t *testing.T) { 177 nr := creation(t, nrp, "encoded") 178 qt.Check(t, n, NodeContentEquals, nr) 179 }) 180 } 181 182 func SchemaTestMapsWithComplexKeys(t *testing.T, engine Engine) { 183 ts := schema.TypeSystem{} 184 ts.Init() 185 ts.Accumulate(schema.SpawnString("String")) 186 ts.Accumulate(schema.SpawnStruct("StringyStruct", 187 []schema.StructField{ 188 schema.SpawnStructField("foo", "String", false, false), 189 schema.SpawnStructField("bar", "String", false, false), 190 }, 191 schema.SpawnStructRepresentationStringjoin(":"), 192 )) 193 ts.Accumulate(schema.SpawnMap("Map__StringyStruct__String", 194 "StringyStruct", "String", false)) 195 engine.Init(t, ts) 196 197 np := engine.PrototypeByName("Map__StringyStruct__String") 198 nrp := engine.PrototypeByName("Map__StringyStruct__String.Repr") 199 var n schema.TypedNode 200 t.Run("typed-create", func(t *testing.T) { 201 n = fluent.MustBuildMap(np, 3, func(ma fluent.MapAssembler) { 202 ma.AssembleKey().CreateMap(2, func(ma fluent.MapAssembler) { 203 ma.AssembleEntry("foo").AssignString("a") 204 ma.AssembleEntry("bar").AssignString("b") 205 }) 206 ma.AssembleValue().AssignString("1") 207 ma.AssembleKey().CreateMap(2, func(ma fluent.MapAssembler) { 208 ma.AssembleEntry("foo").AssignString("c") 209 ma.AssembleEntry("bar").AssignString("d") 210 }) 211 ma.AssembleValue().AssignString("2") 212 ma.AssembleKey().CreateMap(2, func(ma fluent.MapAssembler) { 213 ma.AssembleEntry("foo").AssignString("e") 214 ma.AssembleEntry("bar").AssignString("f") 215 }) 216 ma.AssembleValue().AssignString("3") 217 }).(schema.TypedNode) 218 t.Run("typed-read", func(t *testing.T) { 219 qt.Assert(t, n.Kind(), qt.Equals, datamodel.Kind_Map) 220 qt.Check(t, n.Length(), qt.Equals, int64(3)) 221 n2 := must.Node(n.LookupByString("c:d")) 222 qt.Assert(t, n2.Kind(), qt.Equals, datamodel.Kind_String) 223 qt.Check(t, must.String(n2), qt.Equals, "2") 224 }) 225 t.Run("repr-read", func(t *testing.T) { 226 nr := n.Representation() 227 qt.Assert(t, nr.Kind(), qt.Equals, datamodel.Kind_Map) 228 qt.Check(t, nr.Length(), qt.Equals, int64(3)) 229 n2 := must.Node(nr.LookupByString("c:d")) 230 qt.Assert(t, n2.Kind(), qt.Equals, datamodel.Kind_String) 231 qt.Check(t, must.String(n2), qt.Equals, "2") 232 }) 233 }) 234 t.Run("repr-create", func(t *testing.T) { 235 nr := fluent.MustBuildMap(nrp, 3, func(ma fluent.MapAssembler) { 236 ma.AssembleEntry("a:b").AssignString("1") 237 ma.AssembleEntry("c:d").AssignString("2") 238 ma.AssembleEntry("e:f").AssignString("3") 239 }) 240 qt.Check(t, n, NodeContentEquals, nr) 241 }) 242 }