github.com/cayleygraph/cayley@v0.7.7/schema/writer_test.go (about)

     1  package schema_test
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/cayleygraph/cayley/schema"
     9  	"github.com/cayleygraph/quad"
    10  )
    11  
    12  type quadSlice []quad.Quad
    13  
    14  func (s *quadSlice) WriteQuad(q quad.Quad) error {
    15  	*s = append(*s, q)
    16  	return nil
    17  }
    18  
    19  func (s *quadSlice) WriteQuads(buf []quad.Quad) (int, error) {
    20  	*s = append(*s, buf...)
    21  	return len(buf), nil
    22  }
    23  
    24  func TestWriteAsQuads(t *testing.T) {
    25  	sch := schema.NewConfig()
    26  	for _, c := range testWriteValueCases {
    27  		t.Run(c.name, func(t *testing.T) {
    28  			var out quadSlice
    29  			id, err := sch.WriteAsQuads(&out, c.obj)
    30  			if err != c.err {
    31  				t.Errorf("unexpected error: %v (expected: %v)", err, c.err)
    32  			} else if c.err != nil {
    33  				return // case with expected error; omit other checks
    34  			}
    35  			if c.id == nil {
    36  				for i := range out {
    37  					if c.expect[i].Subject == nil {
    38  						c.expect[i].Subject = id
    39  					}
    40  				}
    41  			} else if id != c.id {
    42  				t.Errorf("ids are different: %v vs %v", id, c.id)
    43  			}
    44  			if !reflect.DeepEqual([]quad.Quad(out), c.expect) {
    45  				t.Errorf("quad sets are different\n%#v\n%#v", []quad.Quad(out), c.expect)
    46  			}
    47  		})
    48  	}
    49  }
    50  
    51  var testWriteValueCases = []struct {
    52  	name   string
    53  	obj    interface{}
    54  	id     quad.Value
    55  	expect []quad.Quad
    56  	err    error
    57  }{
    58  	{
    59  		"complex object",
    60  		struct {
    61  			rdfType struct{} `quad:"rdf:type > some:Type"`
    62  			ID      quad.IRI `quad:"@id"`
    63  			Name    string   `quad:"name"`
    64  			Values  []string `quad:"values"`
    65  			Items   []item   `quad:"items"`
    66  			Sub     *item    `quad:"sub"`
    67  		}{
    68  			ID:     "1234",
    69  			Name:   "some item",
    70  			Values: []string{"val1", "val2"},
    71  			Items: []item{
    72  				{ID: "sub1", Name: "Sub 1"},
    73  				{ID: "sub2", Name: "Sub 2"},
    74  			},
    75  			Sub: &item{ID: "sub3", Name: "Sub 3"},
    76  		},
    77  		iri("1234"),
    78  		[]quad.Quad{
    79  			{iri("1234"), typeIRI, iri("some:Type"), nil},
    80  			{iri("1234"), iri("name"), quad.String(`some item`), nil},
    81  			{iri("1234"), iri("values"), quad.String(`val1`), nil},
    82  			{iri("1234"), iri("values"), quad.String(`val2`), nil},
    83  
    84  			{iri("sub1"), typeIRI, iri("some:item"), nil},
    85  			{iri("sub1"), iri("name"), quad.String(`Sub 1`), nil},
    86  			{iri("1234"), iri("items"), iri("sub1"), nil},
    87  
    88  			{iri("sub2"), typeIRI, iri("some:item"), nil},
    89  			{iri("sub2"), iri("name"), quad.String(`Sub 2`), nil},
    90  			{iri("1234"), iri("items"), iri("sub2"), nil},
    91  
    92  			{iri("sub3"), typeIRI, iri("some:item"), nil},
    93  			{iri("sub3"), iri("name"), quad.String(`Sub 3`), nil},
    94  			{iri("1234"), iri("sub"), iri("sub3"), nil},
    95  		},
    96  		nil,
    97  	},
    98  	{
    99  		"complex object (embedded)",
   100  		struct {
   101  			rdfType struct{} `quad:"rdf:type > some:Type"`
   102  			item2
   103  			ID     quad.IRI `quad:"@id"`
   104  			Values []string `quad:"values"`
   105  		}{
   106  			item2:  item2{Name: "Sub 1", Spec: "special"},
   107  			ID:     "1234",
   108  			Values: []string{"val1", "val2"},
   109  		},
   110  		iri("1234"),
   111  		[]quad.Quad{
   112  			{iri("1234"), typeIRI, iri("some:Type"), nil},
   113  			{iri("1234"), iri("name"), quad.String(`Sub 1`), nil},
   114  			{iri("1234"), iri("spec"), quad.String(`special`), nil},
   115  			{iri("1234"), iri("values"), quad.String(`val1`), nil},
   116  			{iri("1234"), iri("values"), quad.String(`val2`), nil},
   117  		},
   118  		nil,
   119  	},
   120  	{
   121  		"type shorthand",
   122  		struct {
   123  			rdfType struct{} `quad:"@type > some:Type"`
   124  			item2
   125  			ID     quad.IRI `quad:"@id"`
   126  			Values []string `quad:"values"`
   127  		}{
   128  			item2:  item2{Name: "Sub 1", Spec: "special"},
   129  			ID:     "1234",
   130  			Values: []string{"val1", "val2"},
   131  		},
   132  		iri("1234"),
   133  		[]quad.Quad{
   134  			{iri("1234"), typeIRI, iri("some:Type"), nil},
   135  			{iri("1234"), iri("name"), quad.String("Sub 1"), nil},
   136  			{iri("1234"), iri("spec"), quad.String("special"), nil},
   137  			{iri("1234"), iri("values"), quad.String("val1"), nil},
   138  			{iri("1234"), iri("values"), quad.String("val2"), nil},
   139  		},
   140  		nil,
   141  	},
   142  	{
   143  		"json tags",
   144  		struct {
   145  			rdfType struct{} `quad:"@type > some:Type"`
   146  			item2
   147  			ID     quad.IRI `json:"@id"`
   148  			Values []string `json:"values,omitempty"`
   149  		}{
   150  			item2:  item2{Name: "Sub 1", Spec: "special"},
   151  			ID:     "1234",
   152  			Values: []string{"val1", "val2"},
   153  		},
   154  		iri("1234"),
   155  		[]quad.Quad{
   156  			{iri("1234"), typeIRI, iri("some:Type"), nil},
   157  			{iri("1234"), iri("name"), quad.String("Sub 1"), nil},
   158  			{iri("1234"), iri("spec"), quad.String("special"), nil},
   159  			{iri("1234"), iri("values"), quad.String("val1"), nil},
   160  			{iri("1234"), iri("values"), quad.String("val2"), nil},
   161  		},
   162  		nil,
   163  	},
   164  	{
   165  		"simple object",
   166  		subObject{
   167  			genObject: genObject{
   168  				ID:   "1234",
   169  				Name: "Obj",
   170  			},
   171  			Num: 3,
   172  		},
   173  		iri("1234"),
   174  		[]quad.Quad{
   175  			{iri("1234"), iri("name"), quad.String("Obj"), nil},
   176  			{iri("1234"), iri("num"), quad.Int(3), nil},
   177  		},
   178  		nil,
   179  	},
   180  	{
   181  		"typedef",
   182  		genObjectTypedef{
   183  			ID:   "1234",
   184  			Name: "Obj",
   185  		},
   186  		iri("1234"),
   187  		[]quad.Quad{
   188  			{iri("1234"), iri("name"), quad.String("Obj"), nil},
   189  		},
   190  		nil,
   191  	},
   192  	{
   193  		"simple object (embedded multiple levels)",
   194  		subSubObject{
   195  			subObject: subObject{
   196  				genObject: genObject{
   197  					ID:   "1234",
   198  					Name: "Obj",
   199  				},
   200  				Num: 3,
   201  			},
   202  			Num2: 4,
   203  		},
   204  		iri("1234"),
   205  		[]quad.Quad{
   206  			{iri("1234"), iri("name"), quad.String("Obj"), nil},
   207  			{iri("1234"), iri("num"), quad.Int(3), nil},
   208  			{iri("1234"), iri("num2"), quad.Int(4), nil},
   209  		},
   210  		nil,
   211  	},
   212  	{
   213  		"required field not set",
   214  		item2{Name: "partial"},
   215  		nil, nil,
   216  		schema.ErrReqFieldNotSet{Field: "Spec"},
   217  	},
   218  	{
   219  		"required unexported",
   220  		timeItem{ID: "1", Name: "t", TS: time.Unix(100, 0)},
   221  		nil,
   222  		[]quad.Quad{
   223  			{iri("1"), iri("name"), quad.String("t"), nil},
   224  			{iri("1"), iri("ts"), quad.Time(time.Unix(100, 0)), nil},
   225  		},
   226  		nil,
   227  	},
   228  	{
   229  		"single tree node",
   230  		treeItemOpt{
   231  			ID:   iri("n1"),
   232  			Name: "Node 1",
   233  		},
   234  		iri("n1"),
   235  		[]quad.Quad{
   236  			{iri("n1"), iri("name"), quad.String("Node 1"), nil},
   237  		},
   238  		nil,
   239  	},
   240  	{
   241  		"nested tree nodes",
   242  		treeItemOpt{
   243  			ID:   iri("n1"),
   244  			Name: "Node 1",
   245  			Children: []treeItemOpt{
   246  				{ID: iri("n2"), Name: "Node 2"},
   247  			},
   248  		},
   249  		iri("n1"),
   250  		[]quad.Quad{
   251  			{iri("n1"), iri("name"), quad.String("Node 1"), nil},
   252  			{iri("n2"), iri("name"), quad.String("Node 2"), nil},
   253  			{iri("n1"), iri("child"), iri("n2"), nil},
   254  		},
   255  		nil,
   256  	},
   257  	{
   258  		"coords",
   259  		Coords{Lat: 12.3, Lng: 34.5},
   260  		nil,
   261  		[]quad.Quad{
   262  			{nil, typeIRI, iri("ex:Coords"), nil},
   263  			{nil, iri("ex:lat"), quad.Float(12.3), nil},
   264  			{nil, iri("ex:lng"), quad.Float(34.5), nil},
   265  		},
   266  		nil,
   267  	},
   268  	{
   269  		"self loop",
   270  		func() *NodeLoop {
   271  			a := &NodeLoop{ID: iri("A"), Name: "Node A"}
   272  			a.Next = a
   273  			return a
   274  		}(),
   275  		iri("A"),
   276  		[]quad.Quad{
   277  			{iri("A"), iri("name"), quad.String("Node A"), nil},
   278  			{iri("A"), iri("next"), iri("A"), nil},
   279  		},
   280  		nil,
   281  	},
   282  	{
   283  		"pointer chain",
   284  		func() *NodeLoop {
   285  			a := &NodeLoop{ID: iri("A"), Name: "Node A"}
   286  			b := &NodeLoop{ID: iri("B"), Name: "Node B"}
   287  			c := &NodeLoop{ID: iri("C"), Name: "Node C"}
   288  
   289  			a.Next = b
   290  			b.Next = c
   291  			c.Next = a
   292  			return a
   293  		}(),
   294  		iri("A"),
   295  		[]quad.Quad{
   296  			{iri("A"), iri("name"), quad.String("Node A"), nil},
   297  			{iri("B"), iri("name"), quad.String("Node B"), nil},
   298  			{iri("C"), iri("name"), quad.String("Node C"), nil},
   299  			{iri("C"), iri("next"), iri("A"), nil},
   300  			{iri("B"), iri("next"), iri("C"), nil},
   301  			{iri("A"), iri("next"), iri("B"), nil},
   302  		},
   303  		nil,
   304  	},
   305  }