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) NameOf(v graph.Value) string {
i := v.(int)
if i < 0 || i >= len(qs.data) {
switch v.(type) {
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 qs.data[i]
}
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
// and our operator, determine whether or not we meet the requirement.
func (it *Comparison) doComparison(val graph.Value) bool {
//TODO(barakmich): Implement string comparison.
nodeStr := it.qs.NameOf(val)
switch cVal := it.val.(type) {
case int:
@ -86,6 +85,8 @@ func (it *Comparison) doComparison(val graph.Value) bool {
return false
}
return RunIntOp(intVal, it.op, cVal)
case string:
return RunStrOp(nodeStr, it.op, cVal)
default:
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() {
it.subIt.Reset()
}

View file

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