github.com/ipld/go-ipld-prime@v0.21.0/printer/printer_test.go (about)

     1  package printer
     2  
     3  import (
     4  	"testing"
     5  
     6  	qt "github.com/frankban/quicktest"
     7  
     8  	"github.com/ipfs/go-cid"
     9  	"github.com/ipld/go-ipld-prime/datamodel"
    10  	"github.com/ipld/go-ipld-prime/fluent/qp"
    11  	cidlink "github.com/ipld/go-ipld-prime/linking/cid"
    12  	"github.com/ipld/go-ipld-prime/node/basicnode"
    13  	"github.com/ipld/go-ipld-prime/node/bindnode"
    14  	"github.com/ipld/go-ipld-prime/schema"
    15  	"github.com/ipld/go-ipld-prime/testutil"
    16  )
    17  
    18  var testLink = func() datamodel.Link {
    19  	someCid, _ := cid.Cast([]byte{1, 85, 0, 5, 0, 1, 2, 3, 4})
    20  	return cidlink.Link{Cid: someCid}
    21  }()
    22  
    23  func TestSimpleData(t *testing.T) {
    24  	t.Run("nested-maps", func(t *testing.T) {
    25  		n, _ := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {
    26  			qp.MapEntry(ma, "some key", qp.String("some value"))
    27  			qp.MapEntry(ma, "another key", qp.String("another value"))
    28  			qp.MapEntry(ma, "nested map", qp.Map(2, func(ma datamodel.MapAssembler) {
    29  				qp.MapEntry(ma, "deeper entries", qp.String("deeper values"))
    30  				qp.MapEntry(ma, "more deeper entries", qp.String("more deeper values"))
    31  			}))
    32  			qp.MapEntry(ma, "nested list", qp.List(2, func(la datamodel.ListAssembler) {
    33  				qp.ListEntry(la, qp.Int(1))
    34  				qp.ListEntry(la, qp.Int(2))
    35  			}))
    36  			qp.MapEntry(ma, "list with float", qp.List(1, func(la datamodel.ListAssembler) {
    37  				qp.ListEntry(la, qp.Float(3.4))
    38  			}))
    39  		})
    40  		qt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(`
    41  		map{
    42  			string{"some key"}: string{"some value"}
    43  			string{"another key"}: string{"another value"}
    44  			string{"nested map"}: map{
    45  				string{"deeper entries"}: string{"deeper values"}
    46  				string{"more deeper entries"}: string{"more deeper values"}
    47  			}
    48  			string{"nested list"}: list{
    49  				0: int{1}
    50  				1: int{2}
    51  			}
    52  			string{"list with float"}: list{
    53  				0: float{3.4}
    54  			}
    55  		}`,
    56  		))
    57  	})
    58  
    59  	t.Run("map-with-link-and-bytes", func(t *testing.T) {
    60  		n, _ := qp.BuildMap(basicnode.Prototype.Any, -1, func(ma datamodel.MapAssembler) {
    61  			qp.MapEntry(ma, "some key", qp.Link(testLink))
    62  			qp.MapEntry(ma, "another key", qp.String("another value"))
    63  			qp.MapEntry(ma, "nested map", qp.Map(2, func(ma datamodel.MapAssembler) {
    64  				qp.MapEntry(ma, "deeper entries", qp.String("deeper values"))
    65  				qp.MapEntry(ma, "more deeper entries", qp.Link(testLink))
    66  				qp.MapEntry(ma, "yet another deeper entries", qp.Bytes([]byte("fish")))
    67  			}))
    68  			qp.MapEntry(ma, "nested list", qp.List(2, func(la datamodel.ListAssembler) {
    69  				qp.ListEntry(la, qp.Bytes([]byte("ghoti")))
    70  				qp.ListEntry(la, qp.Int(1))
    71  				qp.ListEntry(la, qp.Link(testLink))
    72  			}))
    73  		})
    74  		qt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(`
    75  		map{
    76  			string{"some key"}: link{bafkqabiaaebagba}
    77  			string{"another key"}: string{"another value"}
    78  			string{"nested map"}: map{
    79  				string{"deeper entries"}: string{"deeper values"}
    80  				string{"more deeper entries"}: link{bafkqabiaaebagba}
    81  				string{"yet another deeper entries"}: bytes{66697368}
    82  			}
    83  			string{"nested list"}: list{
    84  				0: bytes{67686f7469}
    85  				1: int{1}
    86  				2: link{bafkqabiaaebagba}
    87  			}
    88  		}`,
    89  		))
    90  	})
    91  }
    92  
    93  func TestTypedData(t *testing.T) {
    94  	t.Run("structs", func(t *testing.T) {
    95  		type FooBar struct {
    96  			Foo  string
    97  			Bar  string
    98  			Baz  []byte
    99  			Jazz datamodel.Link
   100  		}
   101  		ts := schema.MustTypeSystem(
   102  			schema.SpawnString("String"),
   103  			schema.SpawnBytes("Bytes"),
   104  			schema.SpawnLink("Link"),
   105  			schema.SpawnStruct("FooBar", []schema.StructField{
   106  				schema.SpawnStructField("foo", "String", false, false),
   107  				schema.SpawnStructField("bar", "String", false, false),
   108  				schema.SpawnStructField("baz", "Bytes", false, false),
   109  				schema.SpawnStructField("jazz", "Link", false, false),
   110  			}, nil),
   111  		)
   112  		n := bindnode.Wrap(&FooBar{"x", "y", []byte("zed"), testLink}, ts.TypeByName("FooBar"))
   113  		qt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(`
   114  			struct<FooBar>{
   115  				foo: string<String>{"x"}
   116  				bar: string<String>{"y"}
   117  				baz: bytes<Bytes>{7a6564}
   118  				jazz: link<Link>{bafkqabiaaebagba}
   119  			}`,
   120  		))
   121  	})
   122  	t.Run("map-with-struct-keys", func(t *testing.T) {
   123  		type FooBar struct {
   124  			Foo string
   125  			Bar string
   126  		}
   127  		type WowMap struct {
   128  			Keys   []FooBar
   129  			Values map[FooBar]string
   130  		}
   131  		ts := schema.MustTypeSystem(
   132  			schema.SpawnString("String"),
   133  			schema.SpawnStruct("FooBar", []schema.StructField{
   134  				schema.SpawnStructField("foo", "String", false, false),
   135  				schema.SpawnStructField("bar", "String", false, false),
   136  			}, schema.SpawnStructRepresentationStringjoin(":")),
   137  			schema.SpawnMap("WowMap", "FooBar", "String", false),
   138  		)
   139  		n := bindnode.Wrap(&WowMap{
   140  			Keys: []FooBar{{"x", "y"}, {"z", "z"}},
   141  			Values: map[FooBar]string{
   142  				{"x", "y"}: "a",
   143  				{"z", "z"}: "b",
   144  			},
   145  		}, ts.TypeByName("WowMap"))
   146  		qt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(`
   147  			map<WowMap>{
   148  				struct<FooBar>{foo: string<String>{"x"}, bar: string<String>{"y"}}: string<String>{"a"}
   149  				struct<FooBar>{foo: string<String>{"z"}, bar: string<String>{"z"}}: string<String>{"b"}
   150  			}`,
   151  		))
   152  	})
   153  	t.Run("map-with-nested-struct-keys", func(t *testing.T) {
   154  		type Baz struct {
   155  			Baz string
   156  		}
   157  		type FooBar struct {
   158  			Foo string
   159  			Bar Baz
   160  			Baz Baz
   161  		}
   162  		type WowMap struct {
   163  			Keys   []FooBar
   164  			Values map[FooBar]Baz
   165  		}
   166  		ts := schema.MustTypeSystem(
   167  			schema.SpawnString("String"),
   168  			schema.SpawnStruct("FooBar", []schema.StructField{
   169  				schema.SpawnStructField("foo", "String", false, false),
   170  				schema.SpawnStructField("bar", "Baz", false, false),
   171  				schema.SpawnStructField("baz", "Baz", false, false),
   172  			}, schema.SpawnStructRepresentationStringjoin(":")),
   173  			schema.SpawnStruct("Baz", []schema.StructField{
   174  				schema.SpawnStructField("baz", "String", false, false),
   175  			}, schema.SpawnStructRepresentationStringjoin(":")),
   176  			schema.SpawnMap("WowMap", "FooBar", "Baz", false),
   177  		)
   178  		n := bindnode.Wrap(&WowMap{
   179  			Keys: []FooBar{{"x", Baz{"y"}, Baz{"y"}}, {"z", Baz{"z"}, Baz{"z"}}},
   180  			Values: map[FooBar]Baz{
   181  				{"x", Baz{"y"}, Baz{"y"}}: {"a"},
   182  				{"z", Baz{"z"}, Baz{"z"}}: {"b"},
   183  			},
   184  		}, ts.TypeByName("WowMap"))
   185  		t.Run("complex-keys-in-effect", func(t *testing.T) {
   186  			cfg := Config{
   187  				UseMapComplexStyleAlways: true,
   188  			}
   189  			qt.Check(t, cfg.Sprint(n), qt.CmpEquals(), testutil.Dedent(`
   190  				map<WowMap>{
   191  					struct<FooBar>{
   192  							foo: string<String>{"x"}
   193  							bar: struct<Baz>{
   194  								baz: string<String>{"y"}
   195  							}
   196  							baz: struct<Baz>{
   197  								baz: string<String>{"y"}
   198  							}
   199  					}: struct<Baz>{
   200  						baz: string<String>{"a"}
   201  					}
   202  					struct<FooBar>{
   203  							foo: string<String>{"z"}
   204  							bar: struct<Baz>{
   205  								baz: string<String>{"z"}
   206  							}
   207  							baz: struct<Baz>{
   208  								baz: string<String>{"z"}
   209  							}
   210  					}: struct<Baz>{
   211  						baz: string<String>{"b"}
   212  					}
   213  				}`,
   214  			))
   215  		})
   216  		t.Run("complex-keys-in-disabled", func(t *testing.T) {
   217  			cfg := Config{
   218  				UseMapComplexStyleOnType: map[schema.TypeName]bool{
   219  					"WowMap": false,
   220  				},
   221  			}
   222  			qt.Check(t, cfg.Sprint(n), qt.CmpEquals(), testutil.Dedent(`
   223  				map<WowMap>{
   224  					struct<FooBar>{foo: string<String>{"x"}, bar: struct<Baz>{baz: string<String>{"y"}}, baz: struct<Baz>{baz: string<String>{"y"}}}: struct<Baz>{
   225  						baz: string<String>{"a"}
   226  					}
   227  					struct<FooBar>{foo: string<String>{"z"}, bar: struct<Baz>{baz: string<String>{"z"}}, baz: struct<Baz>{baz: string<String>{"z"}}}: struct<Baz>{
   228  						baz: string<String>{"b"}
   229  					}
   230  				}`,
   231  			))
   232  		})
   233  	})
   234  	t.Run("invalid-nil-typed-node", func(t *testing.T) {
   235  		qt.Check(t, Sprint(&nilTypedNode{datamodel.Kind_Invalid}), qt.CmpEquals(), "invalid<?!nil>{?!}")
   236  	})
   237  	t.Run("invalid-nil-typed-node-with-map-kind", func(t *testing.T) {
   238  		qt.Check(t, Sprint(&nilTypedNode{datamodel.Kind_Map}), qt.CmpEquals(), "invalid<?!nil>{?!}{}")
   239  	})
   240  }
   241  
   242  var _ schema.TypedNode = (*nilTypedNode)(nil)
   243  
   244  type nilTypedNode struct {
   245  	kind datamodel.Kind
   246  }
   247  
   248  func (n *nilTypedNode) Kind() datamodel.Kind {
   249  	return n.kind
   250  }
   251  
   252  func (n nilTypedNode) LookupByString(key string) (datamodel.Node, error) {
   253  	return nil, nil
   254  }
   255  
   256  func (n nilTypedNode) LookupByNode(key datamodel.Node) (datamodel.Node, error) {
   257  	return nil, nil
   258  }
   259  
   260  func (n nilTypedNode) LookupByIndex(idx int64) (datamodel.Node, error) {
   261  	return nil, nil
   262  }
   263  
   264  func (n nilTypedNode) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {
   265  	return nil, nil
   266  }
   267  
   268  func (n nilTypedNode) MapIterator() datamodel.MapIterator {
   269  	return nil
   270  }
   271  
   272  func (n nilTypedNode) ListIterator() datamodel.ListIterator {
   273  	return nil
   274  }
   275  
   276  func (n nilTypedNode) Length() int64 {
   277  	return 0
   278  }
   279  
   280  func (n nilTypedNode) IsAbsent() bool {
   281  	return false
   282  }
   283  
   284  func (n nilTypedNode) IsNull() bool {
   285  	return false
   286  }
   287  
   288  func (n nilTypedNode) AsBool() (bool, error) {
   289  	panic("nil-typed-node")
   290  }
   291  
   292  func (n nilTypedNode) AsInt() (int64, error) {
   293  	panic("nil-typed-node")
   294  }
   295  
   296  func (n nilTypedNode) AsFloat() (float64, error) {
   297  	panic("nil-typed-node")
   298  }
   299  
   300  func (n nilTypedNode) AsString() (string, error) {
   301  	panic("nil-typed-node")
   302  }
   303  
   304  func (n nilTypedNode) AsBytes() ([]byte, error) {
   305  	panic("nil-typed-node")
   306  }
   307  
   308  func (n nilTypedNode) AsLink() (datamodel.Link, error) {
   309  	panic("nil-typed-node")
   310  }
   311  
   312  func (n nilTypedNode) Prototype() datamodel.NodePrototype {
   313  	return nil
   314  }
   315  
   316  func (n nilTypedNode) Type() schema.Type {
   317  	return nil
   318  }
   319  
   320  func (n nilTypedNode) Representation() datamodel.Node {
   321  	return nil
   322  }