From c2fd33f9d0eb59062ff05e0aaeef82b89c6d7e03 Mon Sep 17 00:00:00 2001 From: kortschak Date: Thu, 3 Jul 2014 17:55:22 +0930 Subject: [PATCH 1/4] Fix missed test messages --- query/gremlin/gremlin_test.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/query/gremlin/gremlin_test.go b/query/gremlin/gremlin_test.go index 0ffedcf..416c651 100644 --- a/query/gremlin/gremlin_test.go +++ b/query/gremlin/gremlin_test.go @@ -119,7 +119,7 @@ var testQueries = []struct { // Morphism tests. { - message: "show simple morphism works", + message: "show simple morphism", query: ` grandfollows = g.M().Out("follows").Out("follows") g.V("C").Follow(grandfollows).All() @@ -127,7 +127,7 @@ var testQueries = []struct { expect: []string{"G", "F", "B"}, }, { - message: "show reverse morphism works", + message: "show reverse morphism", query: ` grandfollows = g.M().Out("follows").Out("follows") g.V("F").FollowR(grandfollows).All() @@ -137,7 +137,7 @@ var testQueries = []struct { // Intersection tests. { - message: "Simple intersection", + message: "show simple intersection", query: ` function follows(x) { return g.V(x).Out("follows") } follows("D").And(follows("C")).All() @@ -145,7 +145,7 @@ var testQueries = []struct { expect: []string{"B"}, }, { - message: "Simple Morphism Intersection", + message: "show simple morphism intersection", query: ` grandfollows = g.M().Out("follows").Out("follows") function gfollows(x) { return g.V(x).Follow(grandfollows) } @@ -154,7 +154,7 @@ var testQueries = []struct { expect: []string{"F"}, }, { - message: "Double Morphism Intersection", + message: "show double morphism intersection", query: ` grandfollows = g.M().Out("follows").Out("follows") function gfollows(x) { return g.V(x).Follow(grandfollows) } @@ -163,16 +163,15 @@ var testQueries = []struct { expect: []string{"G"}, }, { - message: "Reverse Intersection", + message: "show reverse intersection", query: ` grandfollows = g.M().Out("follows").Out("follows") g.V("G").FollowR(grandfollows).Intersect(g.V("F").FollowR(grandfollows)).All() `, expect: []string{"C"}, }, - { - message: "Standard sort of morphism intersection, continue follow", + message: "show standard sort of morphism intersection, continue follow", query: `gfollowers = g.M().In("follows").In("follows") function cool(x) { return g.V(x).As("a").Out("status").Is("cool").Back("a") } cool("G").Follow(gfollowers).Intersect(cool("B").Follow(gfollowers)).All() From 102402a13b2f066d1ecd273f966c4975a89c97ce Mon Sep 17 00:00:00 2001 From: kortschak Date: Thu, 3 Jul 2014 17:55:40 +0930 Subject: [PATCH 2/4] Clean tests Remove goconvey dependency and improve clarity of intention. --- query/mql/functional_test.go | 276 ------------------------------------------- query/mql/mql_test.go | 195 ++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 276 deletions(-) delete mode 100644 query/mql/functional_test.go create mode 100644 query/mql/mql_test.go diff --git a/query/mql/functional_test.go b/query/mql/functional_test.go deleted file mode 100644 index 59a7990..0000000 --- a/query/mql/functional_test.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2014 The Cayley Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package mql - -import ( - "encoding/json" - "testing" - - . "github.com/smartystreets/goconvey/convey" - - "github.com/google/cayley/graph/memstore" -) - -// +---+ +---+ -// | A |------- ->| F |<-- -// +---+ \------>+---+-/ +---+ \--+---+ -// ------>|#B#| | | E | -// +---+-------/ >+---+ | +---+ -// | C | / v -// +---+ -/ +---+ -// ---- +---+/ |#G#| -// \-->|#D#|------------->+---+ -// +---+ -// - -func buildTripleStore() *Session { - ts := memstore.MakeTestingMemstore() - return NewSession(ts) -} - -func compareJsonInterfaces(actual interface{}, expected interface{}, path Path, t *testing.T) { - isError := false - switch ex := expected.(type) { - case bool: - switch ac := actual.(type) { - case bool: - if ac != ex { - isError = true - } - default: - t.Log("Mismatched type") - isError = true - } - case float64: - switch ac := actual.(type) { - case float64: - if ac != ex { - isError = true - } - default: - t.Log("Mismatched type") - isError = true - } - case string: - switch ac := actual.(type) { - case string: - if ac != ex { - isError = true - } - default: - isError = true - } - case []interface{}: - switch ac := actual.(type) { - case []interface{}: - if len(ac) != len(ex) { - t.Log("Different lengths") - isError = true - } else { - for i, elem := range ex { - compareJsonInterfaces(ac[i], elem, path.Follow(string(i)), t) - } - } - default: - t.Log("Mismatched type") - isError = true - } - case map[string]interface{}: - switch ac := actual.(type) { - case map[string]interface{}: - for k, v := range ex { - actual_value, ok := ac[k] - if !ok { - t.Log("Key", k, "not in actual output.") - isError = true - } else { - compareJsonInterfaces(actual_value, v, path.Follow(string(k)), t) - } - } - default: - t.Log("Mismatched type") - isError = true - } - case nil: - switch ac := actual.(type) { - case nil: - if ac != ex { - isError = true - } - default: - t.Log("Mismatched type") - isError = true - } - default: - t.Error("Unknown JSON type?", expected) - } - - if isError { - actual_bytes, _ := json.MarshalIndent(actual, "", " ") - expected_bytes, _ := json.MarshalIndent(expected, "", " ") - t.Error(path.DisplayString(), ":\n", string(actual_bytes), "\nexpected", string(expected_bytes)) - } -} - -func runAndTestQuery(query string, expected string, t *testing.T) { - ses := buildTripleStore() - c := make(chan interface{}, 5) - go ses.ExecInput(query, c, -1) - for result := range c { - ses.BuildJson(result) - } - actual_struct, _ := ses.GetJson() - var expected_struct interface{} - json.Unmarshal([]byte(expected), &expected_struct) - compareJsonInterfaces(actual_struct, expected_struct, NewPath(), t) - ses.ClearJson() -} - -func TestGetAllIds(t *testing.T) { - Convey("Should get all IDs in the database", t, func() { - query := ` - [{"id": null}] - ` - expected := ` - [ - {"id": "A"}, - {"id": "follows"}, - {"id": "B"}, - {"id": "C"}, - {"id": "D"}, - {"id": "F"}, - {"id": "G"}, - {"id": "E"}, - {"id": "status"}, - {"id": "cool"}, - {"id": "status_graph"} - ] - ` - runAndTestQuery(query, expected, t) - }) -} - -func TestGetCool(t *testing.T) { - query := ` - [{"id": null, "status": "cool"}] - ` - expected := ` - [ - {"id": "B", "status": "cool"}, - {"id": "D", "status": "cool"}, - {"id": "G", "status": "cool"} - ] - ` - runAndTestQuery(query, expected, t) -} - -func TestNullSemantics(t *testing.T) { - query := ` - [{"id": "cool", "status": null}] - ` - expected := ` - [ - {"id": "cool", "status": null} - ] - ` - runAndTestQuery(query, expected, t) -} - -func TestGetFollowsList(t *testing.T) { - query := ` - [{"id": "C", "follows": []}] - ` - expected := ` - [{ - "id": "C", - "follows": [ - "B", "D" - ] - }] - ` - runAndTestQuery(query, expected, t) -} - -func TestGetFollowsStruct(t *testing.T) { - query := ` - [{"id": null, "follows": {"id": null, "status": "cool"}}] - ` - expected := ` - [ - {"id": "A", "follows": {"id": "B", "status": "cool"}}, - {"id": "C", "follows": {"id": "D", "status": "cool"}}, - {"id": "D", "follows": {"id": "G", "status": "cool"}}, - {"id": "F", "follows": {"id": "G", "status": "cool"}} - ] - ` - runAndTestQuery(query, expected, t) -} - -func TestGetFollowsReverseStructList(t *testing.T) { - query := ` - [{"id": null, "!follows": [{"id": null, "status" : "cool"}]}] - ` - expected := ` - [ - {"id": "F", "!follows": [{"id": "B", "status": "cool"}]}, - {"id": "B", "!follows": [{"id": "D", "status": "cool"}]}, - {"id": "G", "!follows": [{"id": "D", "status": "cool"}]} - ] - ` - runAndTestQuery(query, expected, t) -} - -func TestGetRevFollowsList(t *testing.T) { - query := ` - [{"id": "F", "!follows": []}] - ` - expected := ` - [{ - "id": "F", - "!follows": [ - "B", "E" - ] - }] - ` - runAndTestQuery(query, expected, t) -} - -func TestCoFollows(t *testing.T) { - query := ` - [{"id": null, "@A:follows": "B", "@B:follows": "D"}] - ` - expected := ` - [{ - "id": "C", - "@A:follows": "B", - "@B:follows": "D" - }] - ` - runAndTestQuery(query, expected, t) -} - -func TestRevCoFollows(t *testing.T) { - query := ` - [{"id": null, "!follows": {"id": "C"}, "@a:!follows": "D"}] - ` - expected := ` - [{ - "id": "B", - "!follows": {"id": "C"}, - "@a:!follows": "D" - }] - ` - runAndTestQuery(query, expected, t) -} diff --git a/query/mql/mql_test.go b/query/mql/mql_test.go new file mode 100644 index 0000000..53e5a8d --- /dev/null +++ b/query/mql/mql_test.go @@ -0,0 +1,195 @@ +// Copyright 2014 The Cayley Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mql + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/google/cayley/graph" + "github.com/google/cayley/graph/memstore" +) + +// This is a simple test graph. +// +// +---+ +---+ +// | A |------- ->| F |<-- +// +---+ \------>+---+-/ +---+ \--+---+ +// ------>|#B#| | | E | +// +---+-------/ >+---+ | +---+ +// | C | / v +// +---+ -/ +---+ +// ---- +---+/ |#G#| +// \-->|#D#|------------->+---+ +// +---+ +// +var simpleGraph = []*graph.Triple{ + {"A", "follows", "B", ""}, + {"C", "follows", "B", ""}, + {"C", "follows", "D", ""}, + {"D", "follows", "B", ""}, + {"B", "follows", "F", ""}, + {"F", "follows", "G", ""}, + {"D", "follows", "G", ""}, + {"E", "follows", "F", ""}, + {"B", "status", "cool", "status_graph"}, + {"D", "status", "cool", "status_graph"}, + {"G", "status", "cool", "status_graph"}, +} + +func makeTestSession(data []*graph.Triple) *Session { + ts := memstore.NewTripleStore() + for _, t := range data { + ts.AddTriple(t) + } + return NewSession(ts) +} + +var testQueries = []struct { + message string + query string + tag string + expect string +}{ + { + message: "get all IDs in the database", + query: `[{"id": null}]`, + expect: ` + [ + {"id": "A"}, + {"id": "follows"}, + {"id": "B"}, + {"id": "C"}, + {"id": "D"}, + {"id": "F"}, + {"id": "G"}, + {"id": "E"}, + {"id": "status"}, + {"id": "cool"}, + {"id": "status_graph"} + ] + `, + }, + { + message: "get nodes by status", + query: `[{"id": null, "status": "cool"}]`, + expect: ` + [ + {"id": "B", "status": "cool"}, + {"id": "D", "status": "cool"}, + {"id": "G", "status": "cool"} + ] + `, + }, + { + message: "show correct null semantics", + query: `[{"id": "cool", "status": null}]`, + expect: ` + [{"id": "cool", "status": null}] + `, + }, + { + message: "get correct follows list", + query: `[{"id": "C", "follows": []}]`, + expect: ` + [{ + "id": "C", + "follows": ["B", "D"] + }] + `, + }, + { + message: "get correct reverse follows list", + query: `[{"id": "F", "!follows": []}]`, + expect: ` + [{ + "id": "F", + "!follows": ["B", "E"] + }] + `, + }, + { + message: "get correct follows struct", + query: `[{"id": null, "follows": {"id": null, "status": "cool"}}]`, + expect: ` + [ + {"id": "A", "follows": {"id": "B", "status": "cool"}}, + {"id": "C", "follows": {"id": "D", "status": "cool"}}, + {"id": "D", "follows": {"id": "G", "status": "cool"}}, + {"id": "F", "follows": {"id": "G", "status": "cool"}} + ] + `, + }, + { + message: "get correct reverse follows struct", + query: `[{"id": null, "!follows": [{"id": null, "status" : "cool"}]}]`, + expect: ` + [ + {"id": "F", "!follows": [{"id": "B", "status": "cool"}]}, + {"id": "B", "!follows": [{"id": "D", "status": "cool"}]}, + {"id": "G", "!follows": [{"id": "D", "status": "cool"}]} + ] + `, + }, + { + message: "get correct co-follows", + query: `[{"id": null, "@A:follows": "B", "@B:follows": "D"}]`, + expect: ` + [{ + "id": "C", + "@A:follows": "B", + "@B:follows": "D" + }] + `, + }, + { + message: "get correct reverse co-follows", + query: `[{"id": null, "!follows": {"id": "C"}, "@A:!follows": "D"}]`, + expect: ` + [{ + "id": "B", + "!follows": {"id": "C"}, + "@A:!follows": "D" + }] + `, + }, +} + +func runQuery(g []*graph.Triple, query string) interface{} { + s := makeTestSession(g) + c := make(chan interface{}, 5) + go s.ExecInput(query, c, -1) + for result := range c { + s.BuildJson(result) + } + result, _ := s.GetJson() + return result +} + +func TestMQL(t *testing.T) { + for _, test := range testQueries { + got := runQuery(simpleGraph, test.query) + var expect interface{} + json.Unmarshal([]byte(test.expect), &expect) + if !reflect.DeepEqual(got, expect) { + b, err := json.MarshalIndent(got, "", " ") + if err != nil { + t.Fatalf("unexpected JSON marshal error", err) + } + t.Errorf("Failed to %s, got: %s expected: %s", test.message, b, test.expect) + } + } +} From 03fb6e367a644b0023ad450ced32b0df41f51b7d Mon Sep 17 00:00:00 2001 From: kortschak Date: Thu, 3 Jul 2014 18:59:20 +0930 Subject: [PATCH 3/4] Remove dependency on goconvey --- nquads/nquads_test.go | 199 ++++++++++++++++++++++++-------------------------- 1 file changed, 97 insertions(+), 102 deletions(-) diff --git a/nquads/nquads_test.go b/nquads/nquads_test.go index a8a83bc..3fdfc22 100644 --- a/nquads/nquads_test.go +++ b/nquads/nquads_test.go @@ -15,117 +15,112 @@ package nquads import ( + "reflect" "testing" - . "github.com/smartystreets/goconvey/convey" - "github.com/google/cayley/graph" ) -func TestParsingNTriples(t *testing.T) { - Convey("When parsing", t, func() { - Convey("It should not parse invalid triples", func() { - x := Parse("invalid") - So(x, ShouldBeNil) - }) - Convey("It should not parse comments", func() { - x := Parse("# nominally valid triple .") - So(x, ShouldBeNil) - }) - Convey("It should parse simple triples", func() { - x := Parse("this is valid .") - So(x, ShouldNotBeNil) - So(x.Subject, ShouldEqual, "this") - }) - Convey("It should parse quoted triples", func() { - x := Parse("this is \"valid too\" .") - So(x, ShouldNotBeNil) - So(x.Object, ShouldEqual, "valid too") - So(x.Provenance, ShouldEqual, "") - }) - Convey("It should parse escaped quoted triples", func() { - x := Parse("he said \"\\\"That's all folks\\\"\" .") - So(x, ShouldNotBeNil) - So(x.Object, ShouldEqual, "\"That's all folks\"") - So(x.Provenance, ShouldEqual, "") - }) +var testNTriples = []struct { + message string + input string + expect *graph.Triple +}{ + // NTriple tests. + { + message: "not parse invalid triples", + input: "invalid", + expect: nil, + }, + { + message: "not parse comments", + input: "# nominally valid triple .", + expect: nil, + }, + { + message: "parse simple triples", + input: "this is valid .", + expect: &graph.Triple{"this", "is", "valid", ""}, + }, + { + message: "parse quoted triples", + input: `this is "valid too" .`, + expect: &graph.Triple{"this", "is", "valid too", ""}, + }, + { + message: "parse escaped quoted triples", + input: `he said "\"That's all folks\"" .`, + expect: &graph.Triple{"he", "said", `"That's all folks"`, ""}, + }, + { + message: "parse an example real triple", + input: `":/guid/9202a8c04000641f80000000010c843c" "name" "George Morris" .`, + expect: &graph.Triple{":/guid/9202a8c04000641f80000000010c843c", "name", "George Morris", ""}, + }, + { + message: "parse a pathologically spaced triple", + input: "foo is \"\\tA big tough\\r\\nDeal\\\\\" .", + expect: &graph.Triple{"foo", "is", "\tA big tough\r\nDeal\\", ""}, + }, - Convey("It should parse an example real triple", func() { - x := Parse("\":/guid/9202a8c04000641f80000000010c843c\" \"name\" \"George Morris\" .") - So(x, ShouldNotBeNil) - So(x.Object, ShouldEqual, "George Morris") - So(x.Provenance, ShouldEqual, "") - }) + // NQuad tests. + { + message: "parse a simple quad", + input: "this is valid quad .", + expect: &graph.Triple{"this", "is", "valid", "quad"}, + }, + { + message: "parse a quoted quad", + input: `this is valid "quad thing" .`, + expect: &graph.Triple{"this", "is", "valid", "quad thing"}, + }, + { + message: "parse crazy escaped quads", + input: `"\"this" "\"is" "\"valid" "\"quad thing".`, + expect: &graph.Triple{`"this`, `"is`, `"valid`, `"quad thing`}, + }, - Convey("It should parse a pathologically spaced triple", func() { - x := Parse("foo is \"\\tA big tough\\r\\nDeal\\\\\" .") - So(x, ShouldNotBeNil) - So(x.Object, ShouldEqual, "\tA big tough\r\nDeal\\") - So(x.Provenance, ShouldEqual, "") - }) - - Convey("It should parse a simple quad", func() { - x := Parse("this is valid quad .") - So(x, ShouldNotBeNil) - So(x.Object, ShouldEqual, "valid") - So(x.Provenance, ShouldEqual, "quad") - }) - - Convey("It should parse a quoted quad", func() { - x := Parse("this is valid \"quad thing\" .") - So(x, ShouldNotBeNil) - So(x.Object, ShouldEqual, "valid") - So(x.Provenance, ShouldEqual, "quad thing") - }) - - Convey("It should parse crazy escaped quads", func() { - x := Parse("\"\\\"this\" \"\\\"is\" \"\\\"valid\" \"\\\"quad thing\".") - So(x, ShouldNotBeNil) - So(x.Subject, ShouldEqual, "\"this") - So(x.Predicate, ShouldEqual, "\"is") - So(x.Object, ShouldEqual, "\"valid") - So(x.Provenance, ShouldEqual, "\"quad thing") - }) - }) + // NTriple official tests. + { + message: "handle simple case with comments", + input: " . # comment", + expect: &graph.Triple{"http://example/s", "http://example/p", "http://example/o", ""}, + }, + { + message: "handle simple case with comments", + input: " _:o . # comment", + expect: &graph.Triple{"http://example/s", "http://example/p", "_:o", ""}, + }, + { + message: "handle simple case with comments", + input: " \"o\" . # comment", + expect: &graph.Triple{"http://example/s", "http://example/p", "o", ""}, + }, + { + message: "handle simple case with comments", + input: " \"o\"^^ . # comment", + expect: &graph.Triple{"http://example/s", "http://example/p", "o", ""}, + }, + { + message: "handle simple case with comments", + input: " \"o\"@en . # comment", + expect: &graph.Triple{"http://example/s", "http://example/p", "o", ""}, + }, } -func TestParsingNTriplesOfficial(t *testing.T) { - Convey("When using some public test cases...", t, func() { - Convey("It should handle some simple cases with comments", func() { - var x *graph.Triple - x = Parse(" . # comment") - So(x, ShouldNotBeNil) - So(x.Subject, ShouldEqual, "http://example/s") - So(x.Predicate, ShouldEqual, "http://example/p") - So(x.Object, ShouldEqual, "http://example/o") - So(x.Provenance, ShouldEqual, "") - x = Parse(" _:o . # comment") - So(x, ShouldNotBeNil) - So(x.Subject, ShouldEqual, "http://example/s") - So(x.Predicate, ShouldEqual, "http://example/p") - So(x.Object, ShouldEqual, "_:o") - So(x.Provenance, ShouldEqual, "") - x = Parse(" \"o\" . # comment") - So(x, ShouldNotBeNil) - So(x.Object, ShouldEqual, "o") - So(x.Provenance, ShouldEqual, "") - x = Parse(" \"o\"^^ . # comment") - So(x, ShouldNotBeNil) - So(x.Object, ShouldEqual, "o") - So(x.Provenance, ShouldEqual, "") - x = Parse(" \"o\"@en . # comment") - So(x, ShouldNotBeNil) - So(x.Object, ShouldEqual, "o") - So(x.Provenance, ShouldEqual, "") - }) - }) -} - -func BenchmarkParser(b *testing.B) { - for n := 0; n < b.N; n++ { - x := Parse(" \"object of some real\\tlength\"@en . # comment") - if x.Object != "object of some real\tlength" { - b.Fail() +func TestParse(t *testing.T) { + for _, test := range testNTriples { + got := Parse(test.input) + if !reflect.DeepEqual(got, test.expect) { + t.Errorf("Failed to %s, %q, got:%q expect:%q", test.message, test.input, got, test.expect) } } } + +var result *graph.Triple + +func BenchmarkParser(b *testing.B) { + for n := 0; n < b.N; n++ { + result = Parse(" \"object of some real\\tlength\"@en . # comment") + } +} From 859164d71432a41292d9af58f762ab08463a2e42 Mon Sep 17 00:00:00 2001 From: kortschak Date: Thu, 3 Jul 2014 20:25:59 +0930 Subject: [PATCH 4/4] Remove goconvey dependency --- graph/sexp/parser_test.go | 98 ++++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/graph/sexp/parser_test.go b/graph/sexp/parser_test.go index 4ae9c57..78c3a88 100644 --- a/graph/sexp/parser_test.go +++ b/graph/sexp/parser_test.go @@ -17,8 +17,6 @@ package sexp import ( "testing" - . "github.com/smartystreets/goconvey/convey" - "github.com/google/cayley/graph" "github.com/google/cayley/graph/memstore" ) @@ -26,41 +24,55 @@ import ( func TestBadParse(t *testing.T) { str := ParseString("()") if str != "" { - t.Errorf("It parsed! Got \"%s\"", str) + t.Errorf("Unexpected parse result, got:%q", str) } } -func TestParseSexpWithMemstore(t *testing.T) { - Convey("With a Memstore", t, func() { - ts := memstore.NewTripleStore() +var testQueries = []struct { + message string + add *graph.Triple + query string + typ string + expect string +}{ + { + message: "get a single triple linkage", + add: &graph.Triple{"i", "can", "win", ""}, + query: "($a (:can \"win\"))", + typ: "and", + expect: "i", + }, + { + message: "get a single triple linkage", + add: &graph.Triple{"i", "can", "win", ""}, + query: "(\"i\" (:can $a))", + typ: "and", + expect: "i", + }, +} - Convey("It should parse an empty query", func() { - it := BuildIteratorTreeForQuery(ts, "()") - So(it.Type(), ShouldEqual, "null") - }) - - Convey("It should get a single triple linkage", func() { - ts.AddTriple(&graph.Triple{"i", "can", "win", ""}) - query := "($a (:can \"win\"))" - So(len(query), ShouldEqual, 17) - it := BuildIteratorTreeForQuery(ts, query) - So(it.Type(), ShouldEqual, "and") - out, ok := it.Next() - So(ok, ShouldBeTrue) - So(out, ShouldEqual, ts.ValueOf("i")) - }) - - Convey("It can get an internal linkage", func() { - ts.AddTriple(&graph.Triple{"i", "can", "win", ""}) - query := "(\"i\" (:can $a))" - it := BuildIteratorTreeForQuery(ts, query) - So(it.Type(), ShouldEqual, "and") - out, ok := it.Next() - So(ok, ShouldBeTrue) - So(out, ShouldEqual, ts.ValueOf("i")) - }) - - }) +func TestMemstoreBackedSexp(t *testing.T) { + ts := memstore.NewTripleStore() + it := BuildIteratorTreeForQuery(ts, "()") + if it.Type() != "null" { + t.Errorf(`Incorrect type for empty query, got:%q expect: "null"`, it.Type()) + } + for _, test := range testQueries { + if test.add != nil { + ts.AddTriple(test.add) + } + it := BuildIteratorTreeForQuery(ts, test.query) + if it.Type() != test.typ { + t.Errorf("Incorrect type for %s, got:%q expect %q", test.message, it.Type(), test.expect) + } + got, ok := it.Next() + if !ok { + t.Errorf("Failed to %s", test.message) + } + if expect := ts.ValueOf(test.expect); got != expect { + t.Errorf("Incorrect result for %s, got:%v expect %v", test.message, got, expect) + } + } } func TestTreeConstraintParse(t *testing.T) { @@ -72,7 +84,7 @@ func TestTreeConstraintParse(t *testing.T) { "($a (:is :good))))" it := BuildIteratorTreeForQuery(ts, query) if it.Type() != "and" { - t.Error("Odd iterator tree. Got: %s", it.DebugString(0)) + t.Error("Odd iterator tree, got: %s", it.DebugString(0)) } out, ok := it.Next() if !ok { @@ -105,12 +117,18 @@ func TestTreeConstraintTagParse(t *testing.T) { func TestMultipleConstraintParse(t *testing.T) { ts := memstore.NewTripleStore() - ts.AddTriple(&graph.Triple{"i", "like", "food", ""}) - ts.AddTriple(&graph.Triple{"i", "like", "beer", ""}) - ts.AddTriple(&graph.Triple{"you", "like", "beer", ""}) - query := "($a \n" + - "(:like :beer)\n" + - "(:like \"food\"))" + for _, tv := range []*graph.Triple{ + {"i", "like", "food", ""}, + {"i", "like", "beer", ""}, + {"you", "like", "beer", ""}, + } { + ts.AddTriple(tv) + } + query := `( + $a + (:like :beer) + (:like "food") + )` it := BuildIteratorTreeForQuery(ts, query) if it.Type() != "and" { t.Error("Odd iterator tree. Got: %s", it.DebugString(0))