Merge pull request #262 from neonstalwart/string-comparison-iterator

add string comparison to value comparison iterator
This commit is contained in:
Barak Michener 2015-07-31 17:12:38 -04:00
commit 13640290ce
3 changed files with 148 additions and 13 deletions

View file

@ -47,11 +47,18 @@ func (qs *store) NodesAllIterator() graph.Iterator { return &Null{} }
func (qs *store) QuadsAllIterator() graph.Iterator { return &Null{} } func (qs *store) QuadsAllIterator() graph.Iterator { return &Null{} }
func (qs *store) NameOf(v graph.Value) string { func (qs *store) NameOf(v graph.Value) string {
i := v.(int) switch v.(type) {
if i < 0 || i >= len(qs.data) { case int:
i := v.(int)
if i < 0 || i >= len(qs.data) {
return ""
}
return qs.data[i]
case string:
return v.(string)
default:
return "" return ""
} }
return qs.data[i]
} }
func (qs *store) Size() int64 { return 0 } func (qs *store) Size() int64 { return 0 }

View file

@ -70,7 +70,6 @@ func (it *Comparison) UID() uint64 {
// Here's the non-boilerplate part of the ValueComparison iterator. Given a value // Here's the non-boilerplate part of the ValueComparison iterator. Given a value
// and our operator, determine whether or not we meet the requirement. // and our operator, determine whether or not we meet the requirement.
func (it *Comparison) doComparison(val graph.Value) bool { func (it *Comparison) doComparison(val graph.Value) bool {
//TODO(barakmich): Implement string comparison.
nodeStr := it.qs.NameOf(val) nodeStr := it.qs.NameOf(val)
switch cVal := it.val.(type) { switch cVal := it.val.(type) {
case int: case int:
@ -86,6 +85,8 @@ func (it *Comparison) doComparison(val graph.Value) bool {
return false return false
} }
return RunIntOp(intVal, it.op, cVal) return RunIntOp(intVal, it.op, cVal)
case string:
return RunStrOp(nodeStr, it.op, cVal)
default: default:
return true return true
} }
@ -110,6 +111,21 @@ func RunIntOp(a int64, op Operator, b int64) bool {
} }
} }
func RunStrOp(a string, op Operator, b string) bool {
switch op {
case compareLT:
return a < b
case compareLTE:
return a <= b
case compareGT:
return a > b
case compareGTE:
return a >= b
default:
panic("Unknown operator type")
}
}
func (it *Comparison) Reset() { func (it *Comparison) Reset() {
it.subIt.Reset() it.subIt.Reset()
} }

View file

@ -23,6 +23,7 @@ import (
) )
var simpleStore = &store{data: []string{"0", "1", "2", "3", "4", "5"}} var simpleStore = &store{data: []string{"0", "1", "2", "3", "4", "5"}}
var stringStore = &store{data: []string{"foo", "bar", "baz", "echo"}}
func simpleFixedIterator() *Fixed { func simpleFixedIterator() *Fixed {
f := NewFixed(Identity) f := NewFixed(Identity)
@ -32,42 +33,92 @@ func simpleFixedIterator() *Fixed {
return f return f
} }
func stringFixedIterator() *Fixed {
f := NewFixed(Identity)
for _, value := range stringStore.data {
f.Add(value)
}
return f
}
var comparisonTests = []struct { var comparisonTests = []struct {
message string message string
operand graph.Value operand graph.Value
operator Operator operator Operator
expect []string expect []string
qs graph.QuadStore
iterator func() *Fixed
}{ }{
{ {
message: "successful int64 less than comparison", message: "successful int64 less than comparison",
operand: int64(3), operand: int64(3),
operator: compareLT, operator: compareLT,
expect: []string{"0", "1", "2"}, expect: []string{"0", "1", "2"},
qs: simpleStore,
iterator: simpleFixedIterator,
}, },
{ {
message: "empty int64 less than comparison", message: "empty int64 less than comparison",
operand: int64(0), operand: int64(0),
operator: compareLT, operator: compareLT,
expect: nil, expect: nil,
qs: simpleStore,
iterator: simpleFixedIterator,
}, },
{ {
message: "successful int64 greater than comparison", message: "successful int64 greater than comparison",
operand: int64(2), operand: int64(2),
operator: compareGT, operator: compareGT,
expect: []string{"3", "4"}, expect: []string{"3", "4"},
qs: simpleStore,
iterator: simpleFixedIterator,
}, },
{ {
message: "successful int64 greater than or equal comparison", message: "successful int64 greater than or equal comparison",
operand: int64(2), operand: int64(2),
operator: compareGTE, operator: compareGTE,
expect: []string{"2", "3", "4"}, expect: []string{"2", "3", "4"},
qs: simpleStore,
iterator: simpleFixedIterator,
},
{
message: "successful string less than comparison",
operand: "echo",
operator: compareLT,
expect: []string{"bar", "baz"},
qs: stringStore,
iterator: stringFixedIterator,
},
{
message: "empty string less than comparison",
operand: "",
operator: compareLT,
expect: nil,
qs: stringStore,
iterator: stringFixedIterator,
},
{
message: "successful string greater than comparison",
operand: "echo",
operator: compareGT,
expect: []string{"foo"},
qs: stringStore,
iterator: stringFixedIterator,
},
{
message: "successful string greater than or equal comparison",
operand: "echo",
operator: compareGTE,
expect: []string{"foo", "echo"},
qs: stringStore,
iterator: stringFixedIterator,
}, },
} }
func TestValueComparison(t *testing.T) { func TestValueComparison(t *testing.T) {
for _, test := range comparisonTests { for _, test := range comparisonTests {
qs := simpleStore qs := test.qs
vc := NewComparison(simpleFixedIterator(), test.operator, test.operand, qs) vc := NewComparison(test.iterator(), test.operator, test.operand, qs)
var got []string var got []string
for vc.Next() { for vc.Next() {
@ -84,52 +135,113 @@ var vciContainsTests = []struct {
operator Operator operator Operator
check graph.Value check graph.Value
expect bool expect bool
qs graph.QuadStore
val graph.Value
iterator func() *Fixed
}{ }{
{ {
message: "1 is less than 2", message: "1 is less than 2",
operator: compareGTE, operator: compareGTE,
check: 1, check: 1,
expect: false, expect: false,
qs: simpleStore,
val: int64(2),
iterator: simpleFixedIterator,
}, },
{ {
message: "2 is greater than or equal to 2", message: "2 is greater than or equal to 2",
operator: compareGTE, operator: compareGTE,
check: 2, check: 2,
expect: true, expect: true,
qs: simpleStore,
val: int64(2),
iterator: simpleFixedIterator,
}, },
{ {
message: "3 is greater than or equal to 2", message: "3 is greater than or equal to 2",
operator: compareGTE, operator: compareGTE,
check: 3, check: 3,
expect: true, expect: true,
qs: simpleStore,
val: int64(2),
iterator: simpleFixedIterator,
}, },
{ {
message: "5 is absent from iterator", message: "5 is absent from iterator",
operator: compareGTE, operator: compareGTE,
check: 5, check: 5,
expect: false, expect: false,
qs: simpleStore,
val: int64(2),
iterator: simpleFixedIterator,
},
{
message: "foo is greater than or equal to echo",
operator: compareGTE,
check: "foo",
expect: true,
qs: stringStore,
val: "echo",
iterator: stringFixedIterator,
},
{
message: "echo is greater than or equal to echo",
operator: compareGTE,
check: "echo",
expect: true,
qs: stringStore,
val: "echo",
iterator: stringFixedIterator,
},
{
message: "foo is missing from the iterator",
operator: compareLTE,
check: "foo",
expect: false,
qs: stringStore,
val: "echo",
iterator: stringFixedIterator,
}, },
} }
func TestVCIContains(t *testing.T) { func TestVCIContains(t *testing.T) {
for _, test := range vciContainsTests { for _, test := range vciContainsTests {
vc := NewComparison(simpleFixedIterator(), test.operator, int64(2), simpleStore) vc := NewComparison(test.iterator(), test.operator, test.val, test.qs)
if vc.Contains(test.check) != test.expect { if vc.Contains(test.check) != test.expect {
t.Errorf("Failed to show %s", test.message) t.Errorf("Failed to show %s", test.message)
} }
} }
} }
var comparisonIteratorTests = []struct {
message string
qs graph.QuadStore
val graph.Value
}{
{
message: "2 is absent from iterator",
qs: simpleStore,
val: int64(2),
},
{
message: "'missing' is absent from iterator",
qs: stringStore,
val: "missing",
},
}
func TestComparisonIteratorErr(t *testing.T) { func TestComparisonIteratorErr(t *testing.T) {
wantErr := errors.New("unique") wantErr := errors.New("unique")
errIt := newTestIterator(false, wantErr) errIt := newTestIterator(false, wantErr)
vc := NewComparison(errIt, compareLT, int64(2), simpleStore) for _, test := range comparisonIteratorTests {
vc := NewComparison(errIt, compareLT, test.val, test.qs)
if vc.Next() != false { if vc.Next() != false {
t.Errorf("Comparison iterator did not pass through initial 'false'") t.Errorf("Comparison iterator did not pass through initial 'false': %s", test.message)
} }
if vc.Err() != wantErr { if vc.Err() != wantErr {
t.Errorf("Comparison iterator did not pass through underlying Err") t.Errorf("Comparison iterator did not pass through underlying Err: %s", test.message)
}
} }
} }