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  }