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 }