github.com/ipld/go-ipld-prime@v0.21.0/node/tests/schemaScalars.go (about)

     1  package tests
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	qt "github.com/frankban/quicktest"
     8  
     9  	"github.com/ipld/go-ipld-prime/datamodel"
    10  	"github.com/ipld/go-ipld-prime/schema"
    11  )
    12  
    13  func assignValue(am datamodel.NodeAssembler, value interface{}) error {
    14  	switch value := value.(type) {
    15  	case bool:
    16  		return am.AssignBool(value)
    17  	case int64:
    18  		return am.AssignInt(value)
    19  	case float64:
    20  		return am.AssignFloat(value)
    21  	case string:
    22  		return am.AssignString(value)
    23  	case []byte:
    24  		return am.AssignBytes(value)
    25  	default:
    26  		panic(fmt.Sprintf("%T", value))
    27  	}
    28  }
    29  
    30  func SchemaTestScalars(t *testing.T, engine Engine) {
    31  	ts := schema.TypeSystem{}
    32  	ts.Init()
    33  
    34  	ts.Accumulate(schema.SpawnBool("Bool"))
    35  	ts.Accumulate(schema.SpawnInt("Int"))
    36  	ts.Accumulate(schema.SpawnFloat("Float"))
    37  	ts.Accumulate(schema.SpawnString("String"))
    38  	ts.Accumulate(schema.SpawnBytes("Bytes"))
    39  	engine.Init(t, ts)
    40  
    41  	var tests = []struct {
    42  		name  string
    43  		kind  datamodel.Kind
    44  		value interface{}
    45  	}{
    46  		{"Bool", datamodel.Kind_Bool, true},
    47  		{"Int", datamodel.Kind_Int, int64(23)},
    48  		{"Float", datamodel.Kind_Float, 12.25},
    49  		{"String", datamodel.Kind_String, "foo"},
    50  		{"Bytes", datamodel.Kind_Bytes, []byte("bar")},
    51  	}
    52  
    53  	// We test each of the five scalar prototypes in subtests.
    54  	for _, testProto := range tests {
    55  
    56  		// For both the regular node and its repr version,
    57  		// getting the right value for the kind should work.
    58  		for _, useRepr := range []bool{false, true} {
    59  
    60  			protoName := testProto.name
    61  			if useRepr {
    62  				protoName += ".Repr"
    63  			}
    64  			np := engine.PrototypeByName(protoName)
    65  
    66  			// For each prototype, we try assigning all scalar values.
    67  			for _, testAssign := range tests {
    68  
    69  				// We try both AssignKind and AssignNode.
    70  				for _, useAssignNode := range []bool{false, true} {
    71  					testName := fmt.Sprintf("%s-Assign%s", protoName, testAssign.name)
    72  					if useAssignNode {
    73  						testName = fmt.Sprintf("%s-AssignNode-%s", protoName, testAssign.name)
    74  					}
    75  					t.Run(testName, func(t *testing.T) {
    76  						nb := np.NewBuilder()
    77  
    78  						// Assigning null, a list, or a map, should always fail.
    79  						err := nb.AssignNull()
    80  						qt.Check(t, err, qt.Not(qt.IsNil))
    81  						_, err = nb.BeginMap(-1)
    82  						qt.Check(t, err, qt.Not(qt.IsNil))
    83  						_, err = nb.BeginList(-1)
    84  						qt.Check(t, err, qt.Not(qt.IsNil))
    85  
    86  						// Assigning the right value for the kind should succeed.
    87  						if useAssignNode {
    88  							np2 := engine.PrototypeByName(testAssign.name)
    89  							nb2 := np2.NewBuilder()
    90  							qt.Check(t, assignValue(nb2, testAssign.value), qt.IsNil)
    91  							n2 := nb2.Build()
    92  
    93  							err = nb.AssignNode(n2)
    94  						} else {
    95  							err = assignValue(nb, testAssign.value)
    96  						}
    97  						if testAssign.kind == testProto.kind {
    98  							qt.Check(t, err, qt.IsNil)
    99  						} else {
   100  							qt.Check(t, err, qt.Not(qt.IsNil))
   101  
   102  							// Assign something anyway, just so we can Build later.
   103  							err := assignValue(nb, testProto.value)
   104  							qt.Check(t, err, qt.IsNil)
   105  						}
   106  
   107  						n := nb.Build()
   108  
   109  						var gotValue interface{}
   110  						err = nil
   111  						switch testAssign.kind {
   112  						case datamodel.Kind_Bool:
   113  							gotValue, err = n.AsBool()
   114  						case datamodel.Kind_Int:
   115  							gotValue, err = n.AsInt()
   116  						case datamodel.Kind_Float:
   117  							gotValue, err = n.AsFloat()
   118  						case datamodel.Kind_String:
   119  							gotValue, err = n.AsString()
   120  						case datamodel.Kind_Bytes:
   121  							gotValue, err = n.AsBytes()
   122  						default:
   123  							t.Fatal(testAssign.kind)
   124  						}
   125  						if testAssign.kind == testProto.kind {
   126  							qt.Check(t, err, qt.IsNil)
   127  							qt.Check(t, gotValue, qt.DeepEquals, testAssign.value)
   128  						} else {
   129  							qt.Check(t, err, qt.Not(qt.IsNil))
   130  						}
   131  
   132  						// Using Node methods which should never
   133  						// work on scalar kinds.
   134  
   135  						_, err = n.LookupByString("foo")
   136  						qt.Check(t, err, qt.Not(qt.IsNil))
   137  						_, err = n.LookupByIndex(3)
   138  						qt.Check(t, err, qt.Not(qt.IsNil))
   139  						qt.Check(t, n.MapIterator(), qt.IsNil)
   140  						qt.Check(t, n.ListIterator(), qt.IsNil)
   141  						qt.Check(t, n.Length(), qt.Equals, int64(-1))
   142  						qt.Check(t, n.IsAbsent(), qt.IsFalse)
   143  						qt.Check(t, n.IsNull(), qt.IsFalse)
   144  					})
   145  				}
   146  			}
   147  		}
   148  	}
   149  }