Commit c590adc1 authored by hannahhoward's avatar hannahhoward

test(selectors): add selector unit tests

Adds unit test of each type of selector to check parsing and functionality. Also includes some fixes
discovered while creating unit tests
parent 94020ba3
package selector
import (
"fmt"
"testing"
"github.com/ipld/go-ipld-prime/fluent"
ipldfree "github.com/ipld/go-ipld-prime/impl/free"
. "github.com/warpfork/go-wish"
)
func TestParseExploreAll(t *testing.T) {
fnb := fluent.WrapNodeBuilder(ipldfree.NodeBuilder()) // just for the other fixture building
t.Run("parsing non map node should error", func(t *testing.T) {
sn := fnb.CreateInt(0)
_, err := ParseExploreAll(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: selector body must be a map"))
})
t.Run("parsing map node without next field should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {})
_, err := ParseExploreAll(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: next field must be present in ExploreAll selector"))
})
t.Run("parsing map node without next field with invalid selector node should return child's error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateInt(0))
})
_, err := ParseExploreAll(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: selector is a keyed union and thus must be a map"))
})
t.Run("parsing map node with next field with valid selector node should parse", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
s, err := ParseExploreAll(sn)
Wish(t, err, ShouldEqual, nil)
Wish(t, s, ShouldEqual, ExploreAll{Matcher{}})
})
}
......@@ -45,7 +45,10 @@ func ParseExploreFields(n ipld.Node) (Selector, error) {
return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map")
}
fields, err := n.TraverseField(fieldsKey)
if err != nil || fields.ReprKind() != ipld.ReprKind_Map {
if err != nil {
return nil, fmt.Errorf("selector spec parse rejected: fields in ExploreFields selector must be present")
}
if fields.ReprKind() != ipld.ReprKind_Map {
return nil, fmt.Errorf("selector spec parse rejected: fields in ExploreFields selector must be a map")
}
x := ExploreFields{
......
package selector
import (
"fmt"
"testing"
"github.com/ipld/go-ipld-prime/fluent"
ipldfree "github.com/ipld/go-ipld-prime/impl/free"
. "github.com/warpfork/go-wish"
)
func TestParseExploreFields(t *testing.T) {
fnb := fluent.WrapNodeBuilder(ipldfree.NodeBuilder()) // just for the other fixture building
t.Run("parsing non map node should error", func(t *testing.T) {
sn := fnb.CreateInt(0)
_, err := ParseExploreFields(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: selector body must be a map"))
})
t.Run("parsing map node without fields value should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {})
_, err := ParseExploreFields(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: fields in ExploreFields selector must be present"))
})
t.Run("parsing map node with fields value that is not a map should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(fieldsKey), vnb.CreateString("cheese"))
})
_, err := ParseExploreFields(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: fields in ExploreFields selector must be a map"))
})
t.Run("parsing map node with selector node in fields that is invalid should return child's error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(fieldsKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString("applesauce"), vnb.CreateInt(0))
}))
})
_, err := ParseExploreFields(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: selector is a keyed union and thus must be a map"))
})
t.Run("parsing map node with fields value that is map of only valid selector node should parse", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(fieldsKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString("applesauce"), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
}))
})
s, err := ParseExploreFields(sn)
Wish(t, err, ShouldEqual, nil)
Wish(t, s, ShouldEqual, ExploreFields{map[string]Selector{"applesauce": Matcher{}}, []PathSegment{PathSegmentString{S: "applesauce"}}})
})
}
......@@ -21,12 +21,15 @@ func (s ExploreIndex) Interests() []PathSegment {
// Explore returns the node's selector if
// the path matches the index the index for this selector or nil if not
func (s ExploreIndex) Explore(n ipld.Node, p PathSegment) Selector {
if n.ReprKind() != ipld.ReprKind_List {
return nil
}
expectedIndex, expectedErr := p.Index()
actualIndex, actualErr := s.interest[0].Index()
if expectedErr == nil && actualErr == nil && expectedIndex == actualIndex {
return s.next
if expectedErr != nil || actualErr != nil || expectedIndex != actualIndex {
return nil
}
return nil
return s.next
}
// Decide always returns false because this is not a matcher
......@@ -41,12 +44,12 @@ func ParseExploreIndex(n ipld.Node) (Selector, error) {
return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map")
}
indexNode, err := n.TraverseField(indexKey)
if err != nil || indexNode.ReprKind() != ipld.ReprKind_Int {
return nil, fmt.Errorf("selector spec parse rejected: index field must an int in ExploreIndex selector")
if err != nil {
return nil, fmt.Errorf("selector spec parse rejected: index field must be present in ExploreIndex selector")
}
indexValue, err := indexNode.AsInt()
if err != nil {
return nil, fmt.Errorf("selector spec parse rejected: index field must an int in ExploreIndex selector")
return nil, fmt.Errorf("selector spec parse rejected: index field must be a number in ExploreIndex selector")
}
next, err := n.TraverseField(nextSelectorKey)
if err != nil {
......
package selector
import (
"fmt"
"testing"
ipld "github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/fluent"
ipldfree "github.com/ipld/go-ipld-prime/impl/free"
. "github.com/warpfork/go-wish"
)
func TestParseExploreIndex(t *testing.T) {
fnb := fluent.WrapNodeBuilder(ipldfree.NodeBuilder()) // just for the other fixture building
t.Run("parsing non map node should error", func(t *testing.T) {
sn := fnb.CreateInt(0)
_, err := ParseExploreIndex(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: selector body must be a map"))
})
t.Run("parsing map node without next field should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(indexKey), vnb.CreateInt(2))
})
_, err := ParseExploreIndex(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: next field must be present in ExploreIndex selector"))
})
t.Run("parsing map node without index field should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
_, err := ParseExploreIndex(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: index field must be present in ExploreIndex selector"))
})
t.Run("parsing map node with index field that is not an int should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(indexKey), vnb.CreateString("cheese"))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
_, err := ParseExploreIndex(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: index field must be a number in ExploreIndex selector"))
})
t.Run("parsing map node with next field with invalid selector node should return child's error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(indexKey), vnb.CreateInt(2))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateInt(0))
})
_, err := ParseExploreIndex(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: selector is a keyed union and thus must be a map"))
})
t.Run("parsing map node with next field with valid selector node should parse", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(indexKey), vnb.CreateInt(2))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
s, err := ParseExploreIndex(sn)
Wish(t, err, ShouldEqual, nil)
Wish(t, s, ShouldEqual, ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 2}}})
})
}
func TestExploreIndexExplore(t *testing.T) {
fnb := fluent.WrapNodeBuilder(ipldfree.NodeBuilder()) // just for the other fixture building
s := ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 3}}}
t.Run("exploring should return nil unless node is a list", func(t *testing.T) {
n := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {})
returnedSelector := s.Explore(n, PathSegmentInt{I: 3})
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return nil when given a path segment with a different index", func(t *testing.T) {
n := fnb.CreateList(func(lb fluent.ListBuilder, vnb fluent.NodeBuilder) {
lb.AppendAll([]ipld.Node{fnb.CreateInt(0), fnb.CreateInt(1), fnb.CreateInt(2), fnb.CreateInt(3)})
})
returnedSelector := s.Explore(n, PathSegmentInt{I: 2})
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return nil when given a path segment that isn't an index", func(t *testing.T) {
n := fnb.CreateList(func(lb fluent.ListBuilder, vnb fluent.NodeBuilder) {
lb.AppendAll([]ipld.Node{fnb.CreateInt(0), fnb.CreateInt(1), fnb.CreateInt(2), fnb.CreateInt(3)})
})
returnedSelector := s.Explore(n, PathSegmentString{S: "cheese"})
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return the next selector when given a path segment with the right index", func(t *testing.T) {
n := fnb.CreateList(func(lb fluent.ListBuilder, vnb fluent.NodeBuilder) {
lb.AppendAll([]ipld.Node{fnb.CreateInt(0), fnb.CreateInt(1), fnb.CreateInt(2), fnb.CreateInt(3)})
})
returnedSelector := s.Explore(n, PathSegmentInt{I: 3})
Wish(t, returnedSelector, ShouldEqual, Matcher{})
})
}
......@@ -22,6 +22,9 @@ func (s ExploreRange) Interests() []PathSegment {
// Explore returns the node's selector if
// the path matches an index in the range of this selector
func (s ExploreRange) Explore(n ipld.Node, p PathSegment) Selector {
if n.ReprKind() != ipld.ReprKind_List {
return nil
}
index, err := p.Index()
if err != nil {
return nil
......@@ -44,20 +47,23 @@ func ParseExploreRange(n ipld.Node) (Selector, error) {
return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map")
}
startNode, err := n.TraverseField(startKey)
if err != nil || startNode.ReprKind() != ipld.ReprKind_Int {
return nil, fmt.Errorf("selector spec parse rejected: start field must an int in ExploreRange selector")
if err != nil {
return nil, fmt.Errorf("selector spec parse rejected: start field must be present in ExploreRange selector")
}
startValue, err := startNode.AsInt()
if err != nil {
return nil, fmt.Errorf("selector spec parse rejected: start field must an int in ExploreRange selector")
return nil, fmt.Errorf("selector spec parse rejected: start field must be a number in ExploreRange selector")
}
endNode, err := n.TraverseField(endKey)
if err != nil || endNode.ReprKind() != ipld.ReprKind_Int {
return nil, fmt.Errorf("selector spec parse rejected: end field must an int in ExploreRange selector")
if err != nil {
return nil, fmt.Errorf("selector spec parse rejected: end field must be present in ExploreRange selector")
}
endValue, err := endNode.AsInt()
if err != nil {
return nil, fmt.Errorf("selector spec parse rejected: end field must an int in ExploreRange selector")
return nil, fmt.Errorf("selector spec parse rejected: end field must be a number in ExploreRange selector")
}
if startValue >= endValue {
return nil, fmt.Errorf("selector spec parse rejected: end field must be greater than start field in ExploreRange selector")
}
next, err := n.TraverseField(nextSelectorKey)
if err != nil {
......
package selector
import (
"fmt"
"testing"
ipld "github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/fluent"
ipldfree "github.com/ipld/go-ipld-prime/impl/free"
. "github.com/warpfork/go-wish"
)
func TestParseExploreRange(t *testing.T) {
fnb := fluent.WrapNodeBuilder(ipldfree.NodeBuilder()) // just for the other fixture building
t.Run("parsing non map node should error", func(t *testing.T) {
sn := fnb.CreateInt(0)
_, err := ParseExploreRange(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: selector body must be a map"))
})
t.Run("parsing map node without next field should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(startKey), vnb.CreateInt(2))
mb.Insert(knb.CreateString(endKey), vnb.CreateInt(3))
})
_, err := ParseExploreRange(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: next field must be present in ExploreRange selector"))
})
t.Run("parsing map node without start field should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(endKey), vnb.CreateInt(3))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
_, err := ParseExploreRange(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: start field must be present in ExploreRange selector"))
})
t.Run("parsing map node with start field that is not an int should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(startKey), vnb.CreateString("cheese"))
mb.Insert(knb.CreateString(endKey), vnb.CreateInt(3))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
_, err := ParseExploreRange(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: start field must be a number in ExploreRange selector"))
})
t.Run("parsing map node without end field should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(startKey), vnb.CreateInt(2))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
_, err := ParseExploreRange(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: end field must be present in ExploreRange selector"))
})
t.Run("parsing map node with end field that is not an int should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(startKey), vnb.CreateInt(2))
mb.Insert(knb.CreateString(endKey), vnb.CreateString("cheese"))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
_, err := ParseExploreRange(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: end field must be a number in ExploreRange selector"))
})
t.Run("parsing map node where end is not greater than start should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(startKey), vnb.CreateInt(3))
mb.Insert(knb.CreateString(endKey), vnb.CreateInt(2))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
_, err := ParseExploreRange(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: end field must be greater than start field in ExploreRange selector"))
})
t.Run("parsing map node with next field with invalid selector node should return child's error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(startKey), vnb.CreateInt(2))
mb.Insert(knb.CreateString(endKey), vnb.CreateInt(3))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateInt(0))
})
_, err := ParseExploreRange(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: selector is a keyed union and thus must be a map"))
})
t.Run("parsing map node with next field with valid selector node should parse", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(startKey), vnb.CreateInt(2))
mb.Insert(knb.CreateString(endKey), vnb.CreateInt(3))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
})
s, err := ParseExploreRange(sn)
Wish(t, err, ShouldEqual, nil)
Wish(t, s, ShouldEqual, ExploreRange{Matcher{}, map[int]struct{}{2: struct{}{}}, []PathSegment{PathSegmentInt{I: 2}}})
})
}
func TestExploreRangeExplore(t *testing.T) {
fnb := fluent.WrapNodeBuilder(ipldfree.NodeBuilder()) // just for the other fixture building
s := ExploreRange{Matcher{}, map[int]struct{}{3: struct{}{}}, []PathSegment{PathSegmentInt{I: 3}}}
t.Run("exploring should return nil unless node is a list", func(t *testing.T) {
n := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {})
returnedSelector := s.Explore(n, PathSegmentInt{I: 3})
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return nil when given a path segment out of range", func(t *testing.T) {
n := fnb.CreateList(func(lb fluent.ListBuilder, vnb fluent.NodeBuilder) {
lb.AppendAll([]ipld.Node{fnb.CreateInt(0), fnb.CreateInt(1), fnb.CreateInt(2), fnb.CreateInt(3)})
})
returnedSelector := s.Explore(n, PathSegmentInt{I: 2})
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return nil when given a path segment that isn't an index", func(t *testing.T) {
n := fnb.CreateList(func(lb fluent.ListBuilder, vnb fluent.NodeBuilder) {
lb.AppendAll([]ipld.Node{fnb.CreateInt(0), fnb.CreateInt(1), fnb.CreateInt(2), fnb.CreateInt(3)})
})
returnedSelector := s.Explore(n, PathSegmentString{S: "cheese"})
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("exploring should return the next selector when given a path segment with index in range", func(t *testing.T) {
n := fnb.CreateList(func(lb fluent.ListBuilder, vnb fluent.NodeBuilder) {
lb.AppendAll([]ipld.Node{fnb.CreateInt(0), fnb.CreateInt(1), fnb.CreateInt(2), fnb.CreateInt(3)})
})
returnedSelector := s.Explore(n, PathSegmentInt{I: 3})
Wish(t, returnedSelector, ShouldEqual, Matcher{})
})
}
......@@ -48,7 +48,7 @@ func (s ExploreUnion) Explore(n ipld.Node, p PathSegment) Selector {
for _, member := range s.Members {
resultSelector := member.Explore(n, p)
if resultSelector != nil {
nonNilResults = append(nonNilResults, member)
nonNilResults = append(nonNilResults, resultSelector)
}
}
if len(nonNilResults) == 0 {
......
package selector
import (
"fmt"
"testing"
ipld "github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/fluent"
ipldfree "github.com/ipld/go-ipld-prime/impl/free"
. "github.com/warpfork/go-wish"
)
func TestParseExploreUnion(t *testing.T) {
fnb := fluent.WrapNodeBuilder(ipldfree.NodeBuilder()) // just for the other fixture building
t.Run("parsing non list node should error", func(t *testing.T) {
sn := fnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {})
_, err := ParseExploreUnion(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: explore union selector must be a list"))
})
t.Run("parsing list node where one node is invalid should return child's error", func(t *testing.T) {
sn := fnb.CreateList(func(lb fluent.ListBuilder, vnb fluent.NodeBuilder) {
lb.Append(vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
lb.Append(vnb.CreateInt(2))
})
_, err := ParseExploreUnion(sn)
Wish(t, err, ShouldEqual, fmt.Errorf("selector spec parse rejected: selector is a keyed union and thus must be a map"))
})
t.Run("parsing map node with next field with valid selector node should parse", func(t *testing.T) {
sn := fnb.CreateList(func(lb fluent.ListBuilder, vnb fluent.NodeBuilder) {
lb.Append(vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
lb.Append(vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(exploreIndexKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(indexKey), vnb.CreateInt(2))
mb.Insert(knb.CreateString(nextSelectorKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {
mb.Insert(knb.CreateString(matcherKey), vnb.CreateMap(func(mb fluent.MapBuilder, knb fluent.NodeBuilder, vnb fluent.NodeBuilder) {}))
}))
}))
}))
})
s, err := ParseExploreUnion(sn)
Wish(t, err, ShouldEqual, nil)
Wish(t, s, ShouldEqual, ExploreUnion{[]Selector{Matcher{}, ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 2}}}}})
})
}
func TestExploreUnionExplore(t *testing.T) {
fnb := fluent.WrapNodeBuilder(ipldfree.NodeBuilder()) // just for the other fixture building
n := fnb.CreateList(func(lb fluent.ListBuilder, vnb fluent.NodeBuilder) {
lb.AppendAll([]ipld.Node{fnb.CreateInt(0), fnb.CreateInt(1), fnb.CreateInt(2), fnb.CreateInt(3)})
})
t.Run("exploring should return nil if all member selectors return nil when explored", func(t *testing.T) {
s := ExploreUnion{[]Selector{Matcher{}, ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 2}}}}}
returnedSelector := s.Explore(n, PathSegmentInt{I: 3})
Wish(t, returnedSelector, ShouldEqual, nil)
})
t.Run("if exactly one member selector returns a non-nil selector when explored, exploring should return that value", func(t *testing.T) {
s := ExploreUnion{[]Selector{Matcher{}, ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 2}}}}}
returnedSelector := s.Explore(n, PathSegmentInt{I: 2})
Wish(t, returnedSelector, ShouldEqual, Matcher{})
})
t.Run("exploring should return a new union selector if more than one member selector returns a non nil selector when explored", func(t *testing.T) {
s := ExploreUnion{[]Selector{
Matcher{},
ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 2}}},
ExploreRange{Matcher{}, map[int]struct{}{2: struct{}{}}, []PathSegment{PathSegmentInt{I: 2}}},
ExploreFields{map[string]Selector{"applesauce": Matcher{}}, []PathSegment{PathSegmentString{S: "applesauce"}}},
}}
returnedSelector := s.Explore(n, PathSegmentInt{I: 2})
Wish(t, returnedSelector, ShouldEqual, ExploreUnion{[]Selector{Matcher{}, Matcher{}}})
})
}
func TestExploreUnionInterests(t *testing.T) {
t.Run("if any member selector is high-cardinality, interests should be high-cardinality", func(t *testing.T) {
s := ExploreUnion{[]Selector{
ExploreAll{Matcher{}},
Matcher{},
ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 2}}},
}}
Wish(t, s.Interests(), ShouldEqual, []PathSegment(nil))
})
t.Run("if no member selector is high-cardinality, interests should be combination of member selectors interests", func(t *testing.T) {
s := ExploreUnion{[]Selector{
ExploreFields{map[string]Selector{"applesauce": Matcher{}}, []PathSegment{PathSegmentString{S: "applesauce"}}},
Matcher{},
ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 2}}},
}}
Wish(t, s.Interests(), ShouldEqual, []PathSegment{PathSegmentString{S: "applesauce"}, PathSegmentInt{I: 2}})
})
}
func TestExploreUnionDecide(t *testing.T) {
fnb := fluent.WrapNodeBuilder(ipldfree.NodeBuilder()) // just for the other fixture building
n := fnb.CreateInt(2)
t.Run("if any member selector returns true, decide should be true", func(t *testing.T) {
s := ExploreUnion{[]Selector{
ExploreAll{Matcher{}},
Matcher{},
ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 2}}},
}}
Wish(t, s.Decide(n), ShouldEqual, true)
})
t.Run("if no member selector returns true, decide should be false", func(t *testing.T) {
s := ExploreUnion{[]Selector{
ExploreFields{map[string]Selector{"applesauce": Matcher{}}, []PathSegment{PathSegmentString{S: "applesauce"}}},
ExploreAll{Matcher{}},
ExploreIndex{Matcher{}, []PathSegment{PathSegmentInt{I: 2}}},
}}
Wish(t, s.Decide(n), ShouldEqual, false)
})
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment