github.com/storacha/go-ucanto@v0.7.2/core/ipld/rebind_test.go (about)

     1  package ipld
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/ipfs/go-cid"
     8  	"github.com/ipld/go-ipld-prime"
     9  	"github.com/ipld/go-ipld-prime/datamodel"
    10  	cidlink "github.com/ipld/go-ipld-prime/linking/cid"
    11  	"github.com/ipld/go-ipld-prime/node/bindnode"
    12  	"github.com/storacha/go-ucanto/core/ipld/codec/cbor"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestRebind(t *testing.T) {
    17  	type Target struct {
    18  		Abool    bool
    19  		Aint     int
    20  		Afloat   float64
    21  		Astring  string
    22  		Abytes   []byte
    23  		Aenumstr string
    24  		Aenumint int
    25  		Alist    []string
    26  		Amap     struct {
    27  			Keys   []string
    28  			Values map[string]int
    29  		}
    30  		Alink        ipld.Link
    31  		Aoptionalstr *string
    32  		Anullablestr *string
    33  	}
    34  	type Origin struct {
    35  		Value Target
    36  	}
    37  	type Base struct {
    38  		Value datamodel.Node
    39  	}
    40  
    41  	ts, err := ipld.LoadSchemaBytes([]byte(`
    42  		type Origin struct {
    43  			value Target
    44  		}
    45  		type Base struct {
    46  			value Any
    47  		}
    48  		type Target struct {
    49  			abool Bool
    50  			aint Int
    51  			afloat Float
    52  			astring String
    53  			abytes Bytes
    54  			aenumstr EnumString
    55  			aenumint EnumInt
    56  			alist [String]
    57  			amap { String: Int }
    58  			alink Link
    59  			aoptionalstr optional String
    60  			anullablestr nullable String
    61  		}
    62  		type EnumString enum {
    63  			| Nope
    64  			| Yep
    65  			| Maybe
    66  		}
    67  		type EnumInt enum {
    68  			| Nope  ("0")
    69  			| Yep   ("1")
    70  			| Maybe ("100")
    71  		} representation int
    72  	`))
    73  	if err != nil {
    74  		t.Fatalf("failed to load schema: %s", err)
    75  	}
    76  	otyp := ts.TypeByName("Origin")
    77  	btyp := ts.TypeByName("Base")
    78  	ttyp := ts.TypeByName("Target")
    79  
    80  	str := "foo"
    81  	origin := Origin{
    82  		Value: Target{
    83  			Abool:    true,
    84  			Aint:     138,
    85  			Afloat:   1.138,
    86  			Astring:  "foo",
    87  			Abytes:   []byte{1, 2, 3},
    88  			Aenumstr: "Yep",
    89  			Aenumint: 100,
    90  			Alist:    []string{"bar"},
    91  			Amap: struct {
    92  				Keys   []string
    93  				Values map[string]int
    94  			}{
    95  				Keys:   []string{"foo"},
    96  				Values: map[string]int{"foo": 1138},
    97  			},
    98  			Alink:        cidlink.Link{Cid: cid.MustParse("bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui")},
    99  			Aoptionalstr: &str,
   100  			Anullablestr: &str,
   101  		},
   102  	}
   103  	b, err := cbor.Encode(&origin, otyp)
   104  	if err != nil {
   105  		t.Fatalf("encoding origin: %s", err)
   106  	}
   107  
   108  	var bind Base
   109  	err = cbor.Decode(b, &bind, btyp)
   110  	if err != nil {
   111  		t.Fatalf("decoding base: %s", err)
   112  	}
   113  
   114  	sub, err := Rebind[Target](bind.Value, ttyp)
   115  	if err != nil {
   116  		t.Fatalf("binding subtype: %s", err)
   117  	}
   118  
   119  	fmt.Printf("%+v\n", sub)
   120  
   121  	if sub.Astring != "foo" {
   122  		t.Fatalf("failed round trip")
   123  	}
   124  	if sub.Aint != 138 {
   125  		t.Fatalf("failed round trip")
   126  	}
   127  }
   128  
   129  func TestRebindNonCompatibleStruct(t *testing.T) {
   130  	type Target struct {
   131  		Astring string
   132  		Aint    int
   133  	}
   134  	type TargetIncompatible struct {
   135  		Abool bool
   136  	}
   137  	type Origin struct {
   138  		Value Target
   139  	}
   140  	type Base struct {
   141  		Value datamodel.Node
   142  	}
   143  
   144  	ts, err := ipld.LoadSchemaBytes([]byte(`
   145  	  type Origin struct {
   146  		  value Target
   147  		}
   148  		type Base struct {
   149  			value Any
   150  		}
   151  		type Target struct {
   152  			astring String
   153  			aint Int
   154  		}
   155  	`))
   156  	if err != nil {
   157  		t.Fatalf("failed to load schema: %s", err)
   158  	}
   159  	otyp := ts.TypeByName("Origin")
   160  	btyp := ts.TypeByName("Base")
   161  	ttyp := ts.TypeByName("Target")
   162  
   163  	origin := Origin{Value: Target{Astring: "foo", Aint: 138}}
   164  	b, err := cbor.Encode(&origin, otyp)
   165  	if err != nil {
   166  		t.Fatalf("encoding origin: %s", err)
   167  	}
   168  
   169  	var bind Base
   170  	err = cbor.Decode(b, &bind, btyp)
   171  	if err != nil {
   172  		t.Fatalf("decoding base: %s", err)
   173  	}
   174  
   175  	_, err = Rebind[TargetIncompatible](bind.Value, ttyp)
   176  	if err == nil {
   177  		t.Fatalf("expected error rebinding")
   178  	}
   179  	fmt.Println(err)
   180  }
   181  
   182  func TestRebindNonCompatibleSchema(t *testing.T) {
   183  	type Target struct {
   184  		Astring string
   185  		Aint    int
   186  	}
   187  	type Origin struct {
   188  		Value Target
   189  	}
   190  	type Base struct {
   191  		Value datamodel.Node
   192  	}
   193  
   194  	ts, err := ipld.LoadSchemaBytes([]byte(`
   195  	  type Origin struct {
   196  		  value Target
   197  		}
   198  		type Base struct {
   199  			value Any
   200  		}
   201  		type Target struct {
   202  			astring String
   203  			aint Int
   204  		}
   205  		type TargetIncompatible struct {
   206  			abool Bool
   207  		}
   208  	`))
   209  	if err != nil {
   210  		t.Fatalf("failed to load schema: %s", err)
   211  	}
   212  	otyp := ts.TypeByName("Origin")
   213  	btyp := ts.TypeByName("Base")
   214  	ttyp := ts.TypeByName("TargetIncompatible")
   215  
   216  	origin := Origin{Value: Target{Astring: "foo", Aint: 138}}
   217  	b, err := cbor.Encode(&origin, otyp)
   218  	if err != nil {
   219  		t.Fatalf("encoding origin: %s", err)
   220  	}
   221  
   222  	var bind Base
   223  	err = cbor.Decode(b, &bind, btyp)
   224  	if err != nil {
   225  		t.Fatalf("decoding base: %s", err)
   226  	}
   227  
   228  	_, err = Rebind[Target](bind.Value, ttyp)
   229  	if err == nil {
   230  		t.Fatalf("expected error rebinding")
   231  	}
   232  	fmt.Println(err)
   233  }
   234  
   235  func TestRebindTypedNode(t *testing.T) {
   236  	type Target struct {
   237  		Astring string
   238  		Aint    int
   239  	}
   240  
   241  	ts, err := ipld.LoadSchemaBytes([]byte(`
   242  		type Target struct {
   243  			astring String
   244  			aint Int
   245  		} representation tuple
   246  	`))
   247  	require.NoError(t, err)
   248  
   249  	typ := ts.TypeByName("Target")
   250  
   251  	target := Target{Astring: "hello", Aint: 1}
   252  	nd := bindnode.Wrap(&target, typ)
   253  
   254  	rebindTarget, err := Rebind[Target](nd, typ)
   255  	require.NoError(t, err)
   256  	fmt.Printf("%+v\n", rebindTarget)
   257  }