github.com/cayleygraph/cayley@v0.7.7/schema/loader_test.go (about) 1 package schema_test 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/cayleygraph/cayley/graph" 8 "github.com/cayleygraph/cayley/graph/iterator" 9 "github.com/cayleygraph/cayley/graph/memstore" 10 "github.com/cayleygraph/cayley/schema" 11 "github.com/cayleygraph/quad" 12 ) 13 14 func TestLoadLoop(t *testing.T) { 15 sch := schema.NewConfig() 16 17 a := &NodeLoop{ID: iri("A"), Name: "Node A"} 18 a.Next = a 19 20 qs := memstore.New([]quad.Quad{ 21 {a.ID, iri("name"), quad.String(a.Name), nil}, 22 {a.ID, iri("next"), a.ID, nil}, 23 }...) 24 25 b := &NodeLoop{} 26 if err := sch.LoadIteratorTo(nil, qs, reflect.ValueOf(b), nil); err != nil { 27 t.Error(err) 28 return 29 } 30 if a.ID != b.ID || a.Name != b.Name { 31 t.Fatalf("%#v vs %#v", a, b) 32 } 33 if b != b.Next { 34 t.Fatalf("loop is broken: %p vs %p", b, b.Next) 35 } 36 37 a = &NodeLoop{ID: iri("A"), Name: "Node A"} 38 b = &NodeLoop{ID: iri("B"), Name: "Node B"} 39 c := &NodeLoop{ID: iri("C"), Name: "Node C"} 40 a.Next = b 41 b.Next = c 42 c.Next = a 43 44 qs = memstore.New([]quad.Quad{ 45 {a.ID, iri("name"), quad.String(a.Name), nil}, 46 {b.ID, iri("name"), quad.String(b.Name), nil}, 47 {c.ID, iri("name"), quad.String(c.Name), nil}, 48 {a.ID, iri("next"), b.ID, nil}, 49 {b.ID, iri("next"), c.ID, nil}, 50 {c.ID, iri("next"), a.ID, nil}, 51 }...) 52 53 a1 := &NodeLoop{} 54 if err := sch.LoadIteratorTo(nil, qs, reflect.ValueOf(a1), nil); err != nil { 55 t.Error(err) 56 return 57 } 58 if a.ID != a1.ID || a.Name != a1.Name { 59 t.Fatalf("%#v vs %#v", a, b) 60 } 61 b1 := a1.Next 62 c1 := b1.Next 63 if b.ID != b1.ID || b.Name != b1.Name { 64 t.Fatalf("%#v vs %#v", a, b) 65 } 66 if c.ID != c1.ID || c.Name != c1.Name { 67 t.Fatalf("%#v vs %#v", a, b) 68 } 69 if a1 != c1.Next { 70 t.Fatalf("loop is broken: %p vs %p", a1, c1.Next) 71 } 72 } 73 74 func TestLoadIteratorTo(t *testing.T) { 75 sch := schema.NewConfig() 76 for i, c := range testFillValueCases { 77 t.Run(c.name, func(t *testing.T) { 78 qs := memstore.New(c.quads...) 79 rt := reflect.TypeOf(c.expect) 80 var out reflect.Value 81 if rt.Kind() == reflect.Ptr { 82 out = reflect.New(rt.Elem()) 83 } else { 84 out = reflect.New(rt) 85 } 86 var it graph.Iterator 87 if c.from != nil { 88 fixed := iterator.NewFixed() 89 for _, id := range c.from { 90 fixed.Add(qs.ValueOf(id)) 91 } 92 it = fixed 93 } 94 depth := c.depth 95 if depth == 0 { 96 depth = -1 97 } 98 if err := sch.LoadIteratorToDepth(nil, qs, out, depth, it); err != nil { 99 t.Errorf("case %d failed: %v", i+1, err) 100 return 101 } 102 var got interface{} 103 if rt.Kind() == reflect.Ptr { 104 got = out.Interface() 105 } else { 106 got = out.Elem().Interface() 107 } 108 if s, ok := got.(interface { 109 Sort() 110 }); ok { 111 s.Sort() 112 } 113 if s, ok := c.expect.(interface { 114 Sort() 115 }); ok { 116 s.Sort() 117 } 118 if !reflect.DeepEqual(got, c.expect) { 119 t.Errorf("case %d failed: objects are different\n%#v\n%#v", 120 i+1, got, c.expect, 121 ) 122 } 123 }) 124 } 125 } 126 127 var testFillValueCases = []struct { 128 name string 129 expect interface{} 130 quads []quad.Quad 131 depth int 132 from []quad.Value 133 }{ 134 { 135 name: "complex object", 136 expect: struct { 137 rdfType struct{} `quad:"rdf:type > some:Type"` 138 ID quad.IRI `quad:"@id"` 139 Name string `quad:"name"` 140 Values []string `quad:"values"` 141 Items []item `quad:"items"` 142 Sub *item `quad:"sub"` 143 Val int `quad:"val"` 144 }{ 145 ID: "1234", 146 Name: "some item", 147 Values: []string{"val1", "val2"}, 148 Items: []item{ 149 {ID: "sub1", Name: "Sub 1"}, 150 {ID: "sub2", Name: "Sub 2"}, 151 }, 152 Sub: &item{ID: "sub3", Name: "Sub 3"}, 153 Val: 123, 154 }, 155 quads: []quad.Quad{ 156 {iri("1234"), typeIRI, iri("some:Type"), nil}, 157 {iri("1234"), iri("name"), quad.String("some item"), nil}, 158 {iri("1234"), iri("values"), quad.String("val1"), nil}, 159 {iri("1234"), iri("values"), quad.String("val2"), nil}, 160 {iri("sub1"), typeIRI, iri("some:item"), nil}, 161 {iri("sub1"), iri("name"), quad.String("Sub 1"), nil}, 162 {iri("1234"), iri("items"), iri("sub1"), nil}, 163 {iri("sub2"), typeIRI, iri("some:item"), nil}, 164 {iri("sub2"), iri("name"), quad.String("Sub 2"), nil}, 165 {iri("1234"), iri("items"), iri("sub2"), nil}, 166 {iri("sub3"), typeIRI, iri("some:item"), nil}, 167 {iri("sub3"), iri("name"), quad.String("Sub 3"), nil}, 168 {iri("1234"), iri("sub"), iri("sub3"), nil}, 169 {iri("1234"), iri("val"), quad.Int(123), nil}, 170 }, 171 }, 172 { 173 name: "complex object (id value)", 174 expect: struct { 175 rdfType struct{} `quad:"rdf:type > some:Type"` 176 ID quad.Value `quad:"@id"` 177 Name string `quad:"name"` 178 Values []string `quad:"values"` 179 Items []item `quad:"items"` 180 }{ 181 ID: quad.BNode("1234"), 182 Name: "some item", 183 Values: []string{"val1", "val2"}, 184 Items: []item{ 185 {ID: "sub1", Name: "Sub 1"}, 186 {ID: "sub2", Name: "Sub 2"}, 187 }, 188 }, 189 quads: []quad.Quad{ 190 {quad.BNode("1234"), typeIRI, iri("some:Type"), nil}, 191 {quad.BNode("1234"), iri("name"), quad.String("some item"), nil}, 192 {quad.BNode("1234"), iri("values"), quad.String("val1"), nil}, 193 {quad.BNode("1234"), iri("values"), quad.String("val2"), nil}, 194 {iri("sub1"), typeIRI, iri("some:item"), nil}, 195 {iri("sub1"), iri("name"), quad.String("Sub 1"), nil}, 196 {quad.BNode("1234"), iri("items"), iri("sub1"), nil}, 197 {iri("sub2"), typeIRI, iri("some:item"), nil}, 198 {iri("sub2"), iri("name"), quad.String("Sub 2"), nil}, 199 {quad.BNode("1234"), iri("items"), iri("sub2"), nil}, 200 }, 201 }, 202 { 203 name: "embedded object", 204 expect: struct { 205 rdfType struct{} `quad:"rdf:type > some:Type"` 206 item2 207 ID quad.IRI `quad:"@id"` 208 Values []string `quad:"values"` 209 }{ 210 item2: item2{Name: "Sub 1", Spec: "special"}, 211 ID: "1234", 212 Values: []string{"val1", "val2"}, 213 }, 214 quads: []quad.Quad{ 215 {iri("1234"), typeIRI, iri("some:Type"), nil}, 216 {iri("1234"), iri("name"), quad.String("Sub 1"), nil}, 217 {iri("1234"), iri("spec"), quad.String("special"), nil}, 218 {iri("1234"), iri("values"), quad.String("val1"), nil}, 219 {iri("1234"), iri("values"), quad.String("val2"), nil}, 220 }, 221 }, 222 { 223 name: "type shorthand", 224 expect: struct { 225 rdfType struct{} `quad:"@type > some:Type"` 226 item2 227 ID quad.IRI `quad:"@id"` 228 Values []string `quad:"values"` 229 }{ 230 item2: item2{Name: "Sub 1", Spec: "special"}, 231 ID: "1234", 232 Values: []string{"val1", "val2"}, 233 }, 234 quads: []quad.Quad{ 235 {iri("1234"), typeIRI, iri("some:Type"), nil}, 236 {iri("1234"), iri("name"), quad.String("Sub 1"), nil}, 237 {iri("1234"), iri("spec"), quad.String("special"), nil}, 238 {iri("1234"), iri("values"), quad.String("val1"), nil}, 239 {iri("1234"), iri("values"), quad.String("val2"), nil}, 240 }, 241 }, 242 { 243 name: "tree", 244 expect: treeItem{ 245 ID: iri("n1"), 246 Name: "Node 1", 247 Children: []treeItem{ 248 { 249 ID: iri("n2"), 250 Name: "Node 2", 251 }, 252 { 253 ID: iri("n3"), 254 Name: "Node 3", 255 Children: []treeItem{ 256 { 257 ID: iri("n4"), 258 Name: "Node 4", 259 }, 260 }, 261 }, 262 }, 263 }, 264 quads: treeQuads, 265 from: []quad.Value{iri("n1")}, 266 }, 267 { 268 name: "tree with depth limit 1", 269 expect: treeItem{ 270 ID: iri("n1"), 271 Name: "Node 1", 272 Children: []treeItem{ 273 { 274 ID: iri("n2"), 275 Name: "Node 2", 276 }, 277 { 278 ID: iri("n3"), 279 Name: "Node 3", 280 Children: []treeItem{ 281 { 282 ID: iri("n4"), 283 }, 284 }, 285 }, 286 }, 287 }, 288 depth: 1, 289 quads: treeQuads, 290 from: []quad.Value{iri("n1")}, 291 }, 292 { 293 name: "tree with depth limit 2", 294 expect: treeItemOpt{ 295 ID: iri("n1"), 296 Name: "Node 1", 297 Children: []treeItemOpt{ 298 { 299 ID: iri("n2"), 300 Name: "Node 2", 301 }, 302 { 303 ID: iri("n3"), 304 Name: "Node 3", 305 Children: []treeItemOpt{ 306 { 307 ID: iri("n4"), 308 Name: "Node 4", 309 }, 310 }, 311 }, 312 }, 313 }, 314 depth: 2, 315 quads: treeQuads, 316 from: []quad.Value{iri("n1")}, 317 }, 318 { 319 name: "tree with required children", 320 expect: treeItemReq{ 321 ID: iri("n1"), 322 Name: "Node 1", 323 Children: []treeItemReq{ 324 { 325 ID: iri("n3"), 326 Name: "Node 3", 327 // TODO(dennwc): a strange behavior: this field is required, but it's empty for current object, 328 // because all it's children are missing the same field. Leaving this as-is for now because 329 // it's weird to set Children field as required in a tree. 330 Children: nil, 331 }, 332 }, 333 }, 334 quads: treeQuads, 335 from: []quad.Value{iri("n1")}, 336 }, 337 { 338 name: "simple object", 339 expect: subObject{ 340 genObject: genObject{ 341 ID: "1234", 342 Name: "Obj", 343 }, 344 Num: 3, 345 }, 346 quads: []quad.Quad{ 347 {iri("1234"), iri("name"), quad.String("Obj"), nil}, 348 {iri("1234"), iri("num"), quad.Int(3), nil}, 349 }, 350 }, 351 { 352 name: "typedef", 353 expect: genObjectTypedef{ 354 ID: "1234", 355 Name: "Obj", 356 }, 357 quads: []quad.Quad{ 358 {iri("1234"), iri("name"), quad.String("Obj"), nil}, 359 }, 360 }, 361 { 362 name: "coords", 363 expect: Coords{Lat: 12.3, Lng: 34.5}, 364 quads: []quad.Quad{ 365 {iri("c1"), typeIRI, iri("ex:Coords"), nil}, 366 {iri("c1"), iri("ex:lat"), quad.Float(12.3), nil}, 367 {iri("c1"), iri("ex:lng"), quad.Float(34.5), nil}, 368 }, 369 }, 370 { 371 name: "same node", 372 expect: NestedNode{ 373 ID: "c1", 374 Name: "A", 375 Prev: genObject{ 376 ID: "c2", 377 Name: "B", 378 }, 379 Next: genObject{ 380 ID: "c2", 381 Name: "B", 382 }, 383 }, 384 quads: []quad.Quad{ 385 {iri("c1"), iri("name"), quad.String("A"), nil}, 386 {iri("c2"), iri("name"), quad.String("B"), nil}, 387 {iri("c1"), iri("next"), iri("c2"), nil}, 388 {iri("c1"), iri("prev"), iri("c2"), nil}, 389 }, 390 }, 391 { 392 name: "all optional", 393 expect: Alts{ 394 Alt: []OptFields{ 395 {One: "A"}, 396 {Two: "B"}, 397 {One: "C", Two: "D"}, 398 }, 399 }, 400 quads: []quad.Quad{ 401 {iri("c1"), iri("alt"), iri("h1"), nil}, 402 {iri("c1"), iri("alt"), iri("h2"), nil}, 403 {iri("c1"), iri("alt"), iri("h3"), nil}, 404 405 {iri("h1"), iri("one"), quad.String("A"), nil}, 406 {iri("h2"), iri("two"), quad.String("B"), nil}, 407 {iri("h3"), iri("one"), quad.String("C"), nil}, 408 {iri("h3"), iri("two"), quad.String("D"), nil}, 409 }, 410 }, 411 }