github.com/cayleygraph/cayley@v0.7.7/query/sexp/parser_test.go (about) 1 // Copyright 2014 The Cayley Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sexp 16 17 import ( 18 "context" 19 "testing" 20 21 "github.com/cayleygraph/cayley/graph" 22 "github.com/cayleygraph/quad" 23 24 "github.com/cayleygraph/cayley/graph/graphtest/testutil" 25 _ "github.com/cayleygraph/cayley/graph/memstore" 26 sh "github.com/cayleygraph/cayley/graph/shape" 27 _ "github.com/cayleygraph/cayley/writer" 28 "github.com/stretchr/testify/require" 29 ) 30 31 func TestBadParse(t *testing.T) { 32 str := ParseString("()") 33 if str != "" { 34 t.Errorf("Unexpected parse result, got:%q", str) 35 } 36 } 37 38 var ( 39 quads1 = []quad.Quad{quad.Make("i", "can", "win", nil)} 40 ) 41 42 var testQueries = []struct { 43 message string 44 add []quad.Quad 45 query string 46 shape sh.Shape 47 expect string 48 tags map[string]string 49 }{ 50 { 51 message: "empty", 52 query: "()", 53 shape: sh.Null{}, 54 }, 55 { 56 message: "get a single quad linkage", 57 add: quads1, 58 query: "($a (:can \"win\"))", 59 shape: sh.Save{ 60 Tags: []string{"$a"}, 61 From: sh.NodesFrom{ 62 Dir: quad.Subject, 63 Quads: sh.Quads{ 64 {Dir: quad.Predicate, Values: lookup("can")}, 65 {Dir: quad.Object, Values: lookup("win")}, 66 }, 67 }, 68 }, 69 expect: "i", 70 }, 71 { 72 message: "get a single quad linkage (internal)", 73 add: quads1, 74 query: "(\"i\" (:can $a))", 75 shape: sh.Intersect{ 76 lookup("i"), 77 sh.NodesFrom{ 78 Dir: quad.Subject, 79 Quads: sh.Quads{ 80 {Dir: quad.Predicate, Values: lookup("can")}, 81 { 82 Dir: quad.Object, Values: sh.Save{ 83 Tags: []string{"$a"}, 84 From: sh.AllNodes{}, 85 }, 86 }, 87 }, 88 }, 89 }, 90 expect: "i", 91 }, 92 { 93 message: "tree constraint", 94 add: []quad.Quad{ 95 quad.Make("i", "like", "food", nil), 96 quad.Make("food", "is", "good", nil), 97 }, 98 query: "(\"i\"\n" + 99 "(:like\n" + 100 "($a (:is :good))))", 101 shape: sh.Intersect{ 102 lookup("i"), 103 sh.NodesFrom{ 104 Dir: quad.Subject, 105 Quads: sh.Quads{ 106 {Dir: quad.Predicate, Values: lookup("like")}, 107 { 108 Dir: quad.Object, Values: sh.Save{ 109 Tags: []string{"$a"}, 110 From: sh.NodesFrom{ 111 Dir: quad.Subject, 112 Quads: sh.Quads{ 113 {Dir: quad.Predicate, Values: lookup("is")}, 114 {Dir: quad.Object, Values: lookup("good")}, 115 }, 116 }, 117 }, 118 }, 119 }, 120 }, 121 }, 122 expect: "i", 123 tags: map[string]string{ 124 "$a": "food", 125 }, 126 }, 127 { 128 message: "multiple constraint", 129 add: []quad.Quad{ 130 quad.Make("i", "like", "food", nil), 131 quad.Make("i", "like", "beer", nil), 132 quad.Make("you", "like", "beer", nil), 133 }, 134 query: `( 135 $a 136 (:like :beer) 137 (:like "food") 138 )`, 139 shape: sh.Save{ 140 Tags: []string{"$a"}, 141 From: sh.Intersect{ 142 sh.NodesFrom{ 143 Dir: quad.Subject, 144 Quads: sh.Quads{ 145 {Dir: quad.Predicate, Values: lookup("like")}, 146 {Dir: quad.Object, Values: lookup("beer")}, 147 }, 148 }, 149 sh.NodesFrom{ 150 Dir: quad.Subject, 151 Quads: sh.Quads{ 152 {Dir: quad.Predicate, Values: lookup("like")}, 153 {Dir: quad.Object, Values: lookup("food")}, 154 }, 155 }, 156 }, 157 }, 158 expect: "i", 159 }, 160 } 161 162 func TestSexp(t *testing.T) { 163 ctx := context.TODO() 164 for _, test := range testQueries { 165 t.Run(test.message, func(t *testing.T) { 166 qs, _ := graph.NewQuadStore("memstore", "", nil) 167 _ = testutil.MakeWriter(t, qs, nil, test.add...) 168 169 s, _ := BuildShape(test.query) 170 require.Equal(t, test.shape, s, "%s\n%#v\nvs\n%#v", test.message, test.shape, s) 171 172 it := BuildIteratorTreeForQuery(qs, test.query) 173 if it.Next(ctx) != (test.expect != "") { 174 t.Errorf("Failed to %s", test.message) 175 } 176 if test.expect != "" { 177 require.Equal(t, qs.ValueOf(quad.StringToValue(test.expect)), it.Result()) 178 179 tags := make(map[string]graph.Ref) 180 it.TagResults(tags) 181 for k, v := range test.tags { 182 name := qs.NameOf(tags[k]) 183 require.Equal(t, v, quad.ToString(name)) 184 } 185 if it.Next(ctx) { 186 t.Error("too many results") 187 } 188 } 189 }) 190 } 191 }