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

     1  package tests
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/ipld/go-ipld-prime/datamodel"
     7  	"github.com/ipld/go-ipld-prime/schema"
     8  )
     9  
    10  // TestStructsContainingMaybe checks all the variations of "nullable" and "optional" on struct fields.
    11  // It does this twice: once for the child maybes being implemented with pointers,
    12  // and once with maybes implemented as embeds.
    13  // The child values are scalars.
    14  //
    15  // Both type-level generic build and access as well as representation build and access are exercised;
    16  // the representation used is map (the native representation for structs).
    17  func SchemaTestStructsContainingMaybe(t *testing.T, engine Engine) {
    18  	// Type declarations.
    19  	//  The tests here will all be targetted against this "Stroct" type.
    20  	ts := schema.TypeSystem{}
    21  	ts.Init()
    22  	ts.Accumulate(schema.SpawnString("String"))
    23  	ts.Accumulate(schema.SpawnStruct("Stroct",
    24  		[]schema.StructField{
    25  			// Every field in this struct (including their order) is exercising an interesting case...
    26  			schema.SpawnStructField("f1", "String", false, false), // plain field.
    27  			schema.SpawnStructField("f2", "String", true, false),  // optional; later we have more than one optional field, nonsequentially.
    28  			schema.SpawnStructField("f3", "String", false, true),  // nullable; but required.
    29  			schema.SpawnStructField("f4", "String", true, true),   // optional and nullable; trailing optional.
    30  			schema.SpawnStructField("f5", "String", true, false),  // optional; and the second one in a row, trailing.
    31  		},
    32  		schema.SpawnStructRepresentationMap(map[string]string{
    33  			"f1": "r1",
    34  			"f2": "r2",
    35  			"f3": "r3",
    36  			"f4": "r4",
    37  		}),
    38  	))
    39  	engine.Init(t, ts)
    40  
    41  	// There's a lot of cases to cover so a shorthand code labels each case for clarity:
    42  	//  - 'v' -- value in that entry
    43  	//  - 'n' -- null in that entry
    44  	//  - 'z' -- absent entry
    45  	// There's also a semantic description of the main detail being probed suffixed to the shortcode.
    46  	specs := []testcase{
    47  		{
    48  			name:     "vvvvv-AllFieldsSet",
    49  			typeJson: `{"f1":"a","f2":"b","f3":"c","f4":"d","f5":"e"}`,
    50  			reprJson: `{"f5":"e","r1":"a","r2":"b","r3":"c","r4":"d"}`,
    51  			typePoints: []testcasePoint{
    52  				{"", datamodel.Kind_Map},
    53  				{"f1", "a"},
    54  				{"f2", "b"},
    55  				{"f3", "c"},
    56  				{"f4", "d"},
    57  				{"f5", "e"},
    58  			},
    59  			reprPoints: []testcasePoint{
    60  				{"", datamodel.Kind_Map},
    61  				{"r1", "a"},
    62  				{"r2", "b"},
    63  				{"r3", "c"},
    64  				{"r4", "d"},
    65  				{"f5", "e"},
    66  			},
    67  		},
    68  		{
    69  			name:     "vvnnv-Nulls",
    70  			typeJson: `{"f1":"a","f2":"b","f3":null,"f4":null,"f5":"e"}`,
    71  			reprJson: `{"f5":"e","r1":"a","r2":"b","r3":null,"r4":null}`,
    72  			typePoints: []testcasePoint{
    73  				{"", datamodel.Kind_Map},
    74  				{"f1", "a"},
    75  				{"f2", "b"},
    76  				{"f3", datamodel.Null},
    77  				{"f4", datamodel.Null},
    78  				{"f5", "e"},
    79  			},
    80  			reprPoints: []testcasePoint{
    81  				{"", datamodel.Kind_Map},
    82  				{"r1", "a"},
    83  				{"r2", "b"},
    84  				{"r3", datamodel.Null},
    85  				{"r4", datamodel.Null},
    86  				{"f5", "e"},
    87  			},
    88  		},
    89  		{
    90  			name:     "vzvzv-AbsentOptionals",
    91  			typeJson: `{"f1":"a","f3":"c","f5":"e"}`,
    92  			reprJson: `{"f5":"e","r1":"a","r3":"c"}`,
    93  			typePoints: []testcasePoint{
    94  				{"", datamodel.Kind_Map},
    95  				{"f1", "a"},
    96  				{"f2", datamodel.Absent},
    97  				{"f3", "c"},
    98  				{"f4", datamodel.Absent},
    99  				{"f5", "e"},
   100  			},
   101  			reprPoints: []testcasePoint{
   102  				{"", datamodel.Kind_Map},
   103  				{"r1", "a"},
   104  				//{"r2", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.
   105  				{"r3", "c"},
   106  				//{"r4", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.
   107  				{"f5", "e"},
   108  			},
   109  			typeItr: []entry{
   110  				{"f1", "a"},
   111  				{"f2", datamodel.Absent},
   112  				{"f3", "c"},
   113  				{"f4", datamodel.Absent},
   114  				{"f5", "e"},
   115  			},
   116  		},
   117  		{
   118  			name:     "vvnzz-AbsentTrailingOptionals",
   119  			typeJson: `{"f1":"a","f2":"b","f3":null}`,
   120  			reprJson: `{"r1":"a","r2":"b","r3":null}`,
   121  			typePoints: []testcasePoint{
   122  				{"", datamodel.Kind_Map},
   123  				{"f1", "a"},
   124  				{"f2", "b"},
   125  				{"f3", datamodel.Null},
   126  				{"f4", datamodel.Absent},
   127  				{"f5", datamodel.Absent},
   128  			},
   129  			reprPoints: []testcasePoint{
   130  				{"", datamodel.Kind_Map},
   131  				{"r1", "a"},
   132  				{"r2", "b"},
   133  				{"r3", datamodel.Null},
   134  				//{"r4", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.
   135  				//{"f5", datamodel.ErrNotExists{}}, // TODO: need better error typing from traversal package.
   136  			},
   137  			typeItr: []entry{
   138  				{"f1", "a"},
   139  				{"f2", "b"},
   140  				{"f3", datamodel.Null},
   141  				{"f4", datamodel.Absent},
   142  				{"f5", datamodel.Absent},
   143  			},
   144  		},
   145  	}
   146  
   147  	for _, tcase := range specs {
   148  		tcase.Test(t, engine.PrototypeByName("Stroct"), engine.PrototypeByName("Stroct.Repr"))
   149  	}
   150  }