Commit b832b762 authored by Daniel Martí's avatar Daniel Martí

node/tests: cover yet more interface methods

Including LookupBySegment and LookupByNode for both maps and lists, but
also As<T> for the representation form of all scalar kinds.

While at it, expand the interface implementation assertions, too.

Note that we had to make the node/basic tests external,
for the sake of testing LookupByNode without inserting an import cycle.
parent dab6ec7c
package basicnode
package basicnode_test
import (
"testing"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/node/tests"
)
func TestAnyBeingString(t *testing.T) {
tests.SpecTestString(t, Prototype__Any{})
tests.SpecTestString(t, basicnode.Prototype__Any{})
}
func TestAnyBeingMapStrInt(t *testing.T) {
tests.SpecTestMapStrInt(t, Prototype__Any{})
tests.SpecTestMapStrInt(t, basicnode.Prototype__Any{})
}
func TestAnyBeingMapStrMapStrInt(t *testing.T) {
tests.SpecTestMapStrMapStrInt(t, Prototype__Any{})
tests.SpecTestMapStrMapStrInt(t, basicnode.Prototype__Any{})
}
package basicnode
package basicnode_test
import (
"testing"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/node/tests"
)
func BenchmarkSpec_Walk_Map3StrInt(b *testing.B) {
tests.BenchmarkSpec_Walk_Map3StrInt(b, Prototype__Any{})
tests.BenchmarkSpec_Walk_Map3StrInt(b, basicnode.Prototype__Any{})
}
func BenchmarkSpec_Walk_MapNStrMap3StrInt(b *testing.B) {
tests.BenchmarkSpec_Walk_MapNStrMap3StrInt(b, Prototype__Any{})
tests.BenchmarkSpec_Walk_MapNStrMap3StrInt(b, basicnode.Prototype__Any{})
}
package basicnode
package basicnode_test
import (
"testing"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/node/tests"
)
func TestList(t *testing.T) {
tests.SpecTestListString(t, Prototype__List{})
tests.SpecTestListString(t, basicnode.Prototype__List{})
}
package basicnode
package basicnode_test
import (
"testing"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/node/tests"
)
func TestMap(t *testing.T) {
tests.SpecTestMapStrInt(t, Prototype__Map{})
tests.SpecTestMapStrMapStrInt(t, Prototype__Map{})
tests.SpecTestMapStrListStr(t, Prototype__Map{})
tests.SpecTestMapStrInt(t, basicnode.Prototype__Map{})
tests.SpecTestMapStrMapStrInt(t, basicnode.Prototype__Map{})
tests.SpecTestMapStrListStr(t, basicnode.Prototype__Map{})
}
func BenchmarkMapStrInt_3n_AssembleStandard(b *testing.B) {
tests.SpecBenchmarkMapStrInt_3n_AssembleStandard(b, Prototype__Map{})
tests.SpecBenchmarkMapStrInt_3n_AssembleStandard(b, basicnode.Prototype__Map{})
}
func BenchmarkMapStrInt_3n_AssembleEntry(b *testing.B) {
tests.SpecBenchmarkMapStrInt_3n_AssembleEntry(b, Prototype__Map{})
tests.SpecBenchmarkMapStrInt_3n_AssembleEntry(b, basicnode.Prototype__Map{})
}
func BenchmarkMapStrInt_3n_Iteration(b *testing.B) {
tests.SpecBenchmarkMapStrInt_3n_Iteration(b, Prototype__Map{})
tests.SpecBenchmarkMapStrInt_3n_Iteration(b, basicnode.Prototype__Map{})
}
func BenchmarkMapStrInt_25n_AssembleStandard(b *testing.B) {
tests.SpecBenchmarkMapStrInt_25n_AssembleStandard(b, Prototype__Map{})
tests.SpecBenchmarkMapStrInt_25n_AssembleStandard(b, basicnode.Prototype__Map{})
}
func BenchmarkMapStrInt_25n_AssembleEntry(b *testing.B) {
tests.SpecBenchmarkMapStrInt_25n_AssembleEntry(b, Prototype__Map{})
tests.SpecBenchmarkMapStrInt_25n_AssembleEntry(b, basicnode.Prototype__Map{})
}
func BenchmarkMapStrInt_25n_Iteration(b *testing.B) {
tests.SpecBenchmarkMapStrInt_25n_Iteration(b, Prototype__Map{})
tests.SpecBenchmarkMapStrInt_25n_Iteration(b, basicnode.Prototype__Map{})
}
func BenchmarkSpec_Marshal_Map3StrInt(b *testing.B) {
tests.BenchmarkSpec_Marshal_Map3StrInt(b, Prototype__Map{})
tests.BenchmarkSpec_Marshal_Map3StrInt(b, basicnode.Prototype__Map{})
}
func BenchmarkSpec_Marshal_Map3StrInt_CodecNull(b *testing.B) {
tests.BenchmarkSpec_Marshal_Map3StrInt_CodecNull(b, Prototype__Map{})
tests.BenchmarkSpec_Marshal_Map3StrInt_CodecNull(b, basicnode.Prototype__Map{})
}
func BenchmarkSpec_Marshal_MapNStrMap3StrInt(b *testing.B) {
tests.BenchmarkSpec_Marshal_MapNStrMap3StrInt(b, Prototype__Map{})
tests.BenchmarkSpec_Marshal_MapNStrMap3StrInt(b, basicnode.Prototype__Map{})
}
func BenchmarkSpec_Unmarshal_Map3StrInt(b *testing.B) {
tests.BenchmarkSpec_Unmarshal_Map3StrInt(b, Prototype__Map{})
tests.BenchmarkSpec_Unmarshal_Map3StrInt(b, basicnode.Prototype__Map{})
}
func BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b *testing.B) {
tests.BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b, Prototype__Map{})
tests.BenchmarkSpec_Unmarshal_MapNStrMap3StrInt(b, basicnode.Prototype__Map{})
}
package basicnode
package basicnode_test
import (
"testing"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/node/tests"
)
func TestString(t *testing.T) {
tests.SpecTestString(t, Prototype__String{})
tests.SpecTestString(t, basicnode.Prototype__String{})
}
......@@ -175,20 +175,35 @@ func prototype(goType reflect.Type, schemaType schema.Type) ipld.NodePrototype {
return &_prototype{schemaType: schemaType, goType: goType}
}
// Assert that we implement all the interfaces as expected.
// Grouped by the interfaces to implement, roughly.
var (
_ ipld.NodePrototype = (*_prototype)(nil)
_ TypedPrototype = (*_prototype)(nil)
_ ipld.NodePrototype = (*_prototypeRepr)(nil)
_ ipld.Node = (*_node)(nil)
_ schema.TypedNode = (*_node)(nil)
_ ipld.Node = (*_nodeRepr)(nil)
_ ipld.NodeBuilder = (*_builder)(nil)
_ ipld.NodeAssembler = (*_assembler)(nil)
_ ipld.NodeBuilder = (*_builderRepr)(nil)
_ ipld.NodeAssembler = (*_assemblerRepr)(nil)
_ ipld.MapAssembler = (*_structAssembler)(nil)
_ ipld.MapIterator = (*_structIterator)(nil)
_ ipld.MapAssembler = (*_structAssemblerRepr)(nil)
_ ipld.MapIterator = (*_structIteratorRepr)(nil)
_ ipld.ListAssembler = (*_listAssembler)(nil)
_ ipld.ListIterator = (*_listIterator)(nil)
_ ipld.ListAssembler = (*_listAssemblerRepr)(nil)
_ ipld.MapAssembler = (*_unionAssembler)(nil)
_ ipld.MapIterator = (*_unionIterator)(nil)
_ ipld.MapAssembler = (*_unionAssemblerRepr)(nil)
_ ipld.MapIterator = (*_unionIteratorRepr)(nil)
)
type _prototype struct {
......@@ -211,12 +226,6 @@ type TypedPrototype interface {
Representation() ipld.NodePrototype
}
type TypedAssembler interface {
ipld.NodeAssembler
Representation() ipld.NodeAssembler
}
func (w *_prototype) Representation() ipld.NodePrototype {
return (*_prototypeRepr)(w)
}
......@@ -352,10 +361,6 @@ func (w *_node) LookupByString(key string) (ipld.Node, error) {
}
}
func (w *_node) LookupByNode(key ipld.Node) (ipld.Node, error) {
panic("TODO: LookupByNode")
}
func (w *_node) LookupByIndex(idx int64) (ipld.Node, error) {
switch typ := w.schemaType.(type) {
case *schema.TypeList:
......@@ -379,7 +384,43 @@ func (w *_node) LookupByIndex(idx int64) (ipld.Node, error) {
}
func (w *_node) LookupBySegment(seg ipld.PathSegment) (ipld.Node, error) {
panic("TODO: LookupBySegment")
switch w.Kind() {
case ipld.Kind_Map:
return w.LookupByString(seg.String())
case ipld.Kind_List:
idx, err := seg.Index()
if err != nil {
return nil, err
}
return w.LookupByIndex(idx)
}
return nil, ipld.ErrWrongKind{
TypeName: w.schemaType.Name().String(),
MethodName: "LookupBySegment",
// TODO
}
}
func (w *_node) LookupByNode(key ipld.Node) (ipld.Node, error) {
switch w.Kind() {
case ipld.Kind_Map:
s, err := key.AsString()
if err != nil {
return nil, err
}
return w.LookupByString(s)
case ipld.Kind_List:
i, err := key.AsInt()
if err != nil {
return nil, err
}
return w.LookupByIndex(i)
}
return nil, ipld.ErrWrongKind{
TypeName: w.schemaType.Name().String(),
MethodName: "LookupByNode",
// TODO
}
}
func (w *_node) MapIterator() ipld.MapIterator {
......
......@@ -150,15 +150,6 @@ func (w *_nodeRepr) LookupByString(key string) (ipld.Node, error) {
}
}
func (w *_nodeRepr) LookupByNode(key ipld.Node) (ipld.Node, error) {
return nil, ipld.ErrWrongKind{
TypeName: w.schemaType.Name().String(),
MethodName: "LookupByNode",
AppropriateKind: ipld.KindSet_JustList,
// TODO
}
}
func (w *_nodeRepr) LookupByIndex(idx int64) (ipld.Node, error) {
switch stg := reprStrategy(w.schemaType).(type) {
case schema.StructRepresentation_Tuple:
......@@ -181,6 +172,16 @@ func (w *_nodeRepr) LookupByIndex(idx int64) (ipld.Node, error) {
}
func (w *_nodeRepr) LookupBySegment(seg ipld.PathSegment) (ipld.Node, error) {
switch w.Kind() {
case ipld.Kind_Map:
return w.LookupByString(seg.String())
case ipld.Kind_List:
idx, err := seg.Index()
if err != nil {
return nil, err
}
return w.LookupByIndex(idx)
}
return nil, ipld.ErrWrongKind{
TypeName: w.schemaType.Name().String(),
MethodName: "LookupBySegment",
......@@ -188,6 +189,28 @@ func (w *_nodeRepr) LookupBySegment(seg ipld.PathSegment) (ipld.Node, error) {
}
}
func (w *_nodeRepr) LookupByNode(key ipld.Node) (ipld.Node, error) {
switch w.Kind() {
case ipld.Kind_Map:
s, err := key.AsString()
if err != nil {
return nil, err
}
return w.LookupByString(s)
case ipld.Kind_List:
i, err := key.AsInt()
if err != nil {
return nil, err
}
return w.LookupByIndex(i)
}
return nil, ipld.ErrWrongKind{
TypeName: w.schemaType.Name().String(),
MethodName: "LookupByNode",
// TODO
}
}
func (w *_nodeRepr) MapIterator() ipld.MapIterator {
if stg, ok := reprStrategy(w.schemaType).(schema.UnionRepresentation_Kinded); ok {
w = w.asKinded(stg, ipld.Kind_Map)
......@@ -397,6 +420,10 @@ type _assemblerRepr struct {
nullable bool
}
func assemblerRepr(am ipld.NodeAssembler) *_assemblerRepr {
return (*_assemblerRepr)(am.(*_assembler))
}
func (w *_assemblerRepr) asKinded(stg schema.UnionRepresentation_Kinded, kind ipld.Kind) *_assemblerRepr {
name := stg.GetMember(kind)
members := w.schemaType.(*schema.TypeUnion).Members()
......@@ -473,16 +500,31 @@ func (w *_assemblerRepr) AssignNull() error {
}
}
func (w *_assemblerRepr) AssignBool(bool) error {
panic("TODO: AssignBool")
func (w *_assemblerRepr) AssignBool(b bool) error {
switch stg := reprStrategy(w.schemaType).(type) {
case nil:
return (*_assembler)(w).AssignBool(b)
default:
panic(fmt.Sprintf("TODO: %T", stg))
}
}
func (w *_assemblerRepr) AssignInt(i int64) error {
panic("TODO")
switch stg := reprStrategy(w.schemaType).(type) {
case nil:
return (*_assembler)(w).AssignInt(i)
default:
panic(fmt.Sprintf("TODO: %T", stg))
}
}
func (w *_assemblerRepr) AssignFloat(float64) error {
panic("TODO: AssignFloat")
func (w *_assemblerRepr) AssignFloat(f float64) error {
switch stg := reprStrategy(w.schemaType).(type) {
case nil:
return (*_assembler)(w).AssignFloat(f)
default:
panic(fmt.Sprintf("TODO: %T", stg))
}
}
func (w *_assemblerRepr) AssignString(s string) error {
......@@ -502,7 +544,7 @@ func (w *_assemblerRepr) AssignString(s string) error {
if err != nil {
return err
}
entryAsm = entryAsm.(TypedAssembler).Representation()
entryAsm = assemblerRepr(entryAsm)
if err := entryAsm.AssignString(parts[i]); err != nil {
return err
}
......@@ -558,15 +600,30 @@ func (w *_assemblerRepr) AssignString(s string) error {
}
func (w *_assemblerRepr) AssignBytes(p []byte) error {
panic("TODO")
switch stg := reprStrategy(w.schemaType).(type) {
case nil:
return (*_assembler)(w).AssignBytes(p)
default:
panic(fmt.Sprintf("TODO: %T", stg))
}
}
func (w *_assemblerRepr) AssignLink(link ipld.Link) error {
panic("TODO")
switch stg := reprStrategy(w.schemaType).(type) {
case nil:
return (*_assembler)(w).AssignLink(link)
default:
panic(fmt.Sprintf("TODO: %T", stg))
}
}
func (w *_assemblerRepr) AssignNode(node ipld.Node) error {
panic("TODO")
switch stg := reprStrategy(w.schemaType).(type) {
case nil:
return (*_assembler)(w).AssignNode(node)
default:
panic(fmt.Sprintf("TODO: %T", stg))
}
}
func (w *_assemblerRepr) Prototype() ipld.NodePrototype {
......@@ -592,7 +649,7 @@ func (w *_structAssemblerRepr) AssembleValue() ipld.NodeAssembler {
w.curKey.val.SetString(revKey)
valAsm := (*_structAssembler)(w).AssembleValue()
valAsm = valAsm.(TypedAssembler).Representation()
valAsm = assemblerRepr(valAsm)
return valAsm
default:
panic(fmt.Sprintf("TODO: %T", stg))
......@@ -693,7 +750,7 @@ func (w *_listStructAssemblerRepr) AssembleValue() ipld.NodeAssembler {
if err != nil {
panic(err) // TODO: probably return an assembler that always errors?
}
entryAsm = entryAsm.(TypedAssembler).Representation()
entryAsm = assemblerRepr(entryAsm)
return entryAsm
default:
panic(fmt.Sprintf("TODO: %T", stg))
......@@ -748,7 +805,7 @@ func (w *_unionAssemblerRepr) AssembleValue() ipld.NodeAssembler {
w.curKey.val.SetString(revKey)
valAsm := (*_unionAssembler)(w).AssembleValue()
valAsm = valAsm.(TypedAssembler).Representation()
valAsm = assemblerRepr(valAsm)
return valAsm
default:
panic(fmt.Sprintf("TODO: %T", stg))
......
......@@ -8,6 +8,7 @@ import (
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/fluent"
"github.com/ipld/go-ipld-prime/must"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/schema"
)
......@@ -33,8 +34,13 @@ func SchemaTestListsContainingMaybe(t *testing.T, engine Engine) {
t.Run("typed-read", func(t *testing.T) {
Require(t, n.Kind(), ShouldEqual, ipld.Kind_List)
Wish(t, n.Length(), ShouldEqual, int64(2))
Wish(t, must.String(must.Node(n.LookupByIndex(0))), ShouldEqual, "1")
Wish(t, must.String(must.Node(n.LookupByIndex(1))), ShouldEqual, "2")
Wish(t, must.String(must.Node(n.LookupBySegment(ipld.PathSegmentOfInt(0)))), ShouldEqual, "1")
Wish(t, must.String(must.Node(n.LookupByNode(basicnode.NewInt(0)))), ShouldEqual, "1")
_, err := n.LookupByIndex(3)
Wish(t, err, ShouldBeSameTypeAs, ipld.ErrNotExists{})
})
......@@ -42,8 +48,13 @@ func SchemaTestListsContainingMaybe(t *testing.T, engine Engine) {
nr := n.Representation()
Require(t, nr.Kind(), ShouldEqual, ipld.Kind_List)
Wish(t, nr.Length(), ShouldEqual, int64(2))
Wish(t, must.String(must.Node(nr.LookupByIndex(0))), ShouldEqual, "1")
Wish(t, must.String(must.Node(nr.LookupByIndex(1))), ShouldEqual, "2")
Wish(t, must.String(must.Node(n.LookupBySegment(ipld.PathSegmentOfInt(0)))), ShouldEqual, "1")
Wish(t, must.String(must.Node(n.LookupByNode(basicnode.NewInt(0)))), ShouldEqual, "1")
_, err := n.LookupByIndex(3)
Wish(t, err, ShouldBeSameTypeAs, ipld.ErrNotExists{})
})
......
......@@ -52,57 +52,60 @@ func SchemaTestScalars(t *testing.T, engine Engine) {
// We test each of the five scalar prototypes in subtests.
for _, testProto := range tests {
np := engine.PrototypeByName(testProto.name)
// For each prototype, we try assigning all scalar values.
for _, testAssign := range tests {
// For both the regular node and its repr version,
// getting the right value for the kind should work.
for _, useRepr := range []bool{false, true} {
// We try both AssignKind and AssignNode.
for _, useAssignNode := range []bool{false, true} {
testName := fmt.Sprintf("%s-Assign%s", testProto.name, testAssign.name)
if useAssignNode {
testName = fmt.Sprintf("%s-AssignNode-%s", testProto.name, testAssign.name)
}
t.Run(testName, func(t *testing.T) {
nb := np.NewBuilder()
// Assigning null, a list, or a map, should always fail.
err := nb.AssignNull()
qt.Assert(t, err, qt.Not(qt.IsNil))
_, err = nb.BeginMap(-1)
qt.Assert(t, err, qt.Not(qt.IsNil))
_, err = nb.BeginList(-1)
qt.Assert(t, err, qt.Not(qt.IsNil))
// Assigning the right value for the kind should succeed.
protoName := testProto.name
if useRepr {
protoName += ".Repr"
}
np := engine.PrototypeByName(protoName)
// For each prototype, we try assigning all scalar values.
for _, testAssign := range tests {
// We try both AssignKind and AssignNode.
for _, useAssignNode := range []bool{false, true} {
testName := fmt.Sprintf("%s-Assign%s", protoName, testAssign.name)
if useAssignNode {
np2 := engine.PrototypeByName(testAssign.name)
nb2 := np2.NewBuilder()
qt.Assert(t, assignValue(nb2, testAssign.value), qt.IsNil)
n2 := nb2.Build()
err = nb.AssignNode(n2)
} else {
err = assignValue(nb, testAssign.value)
testName = fmt.Sprintf("%s-AssignNode-%s", protoName, testAssign.name)
}
if testAssign.kind == testProto.kind {
qt.Assert(t, err, qt.IsNil)
} else {
t.Run(testName, func(t *testing.T) {
nb := np.NewBuilder()
// Assigning null, a list, or a map, should always fail.
err := nb.AssignNull()
qt.Assert(t, err, qt.Not(qt.IsNil))
_, err = nb.BeginMap(-1)
qt.Assert(t, err, qt.Not(qt.IsNil))
_, err = nb.BeginList(-1)
qt.Assert(t, err, qt.Not(qt.IsNil))
// Assign something anyway, just so we can Build later.
err := assignValue(nb, testProto.value)
qt.Assert(t, err, qt.IsNil)
}
// Assigning the right value for the kind should succeed.
if useAssignNode {
np2 := engine.PrototypeByName(testAssign.name)
nb2 := np2.NewBuilder()
qt.Assert(t, assignValue(nb2, testAssign.value), qt.IsNil)
n2 := nb2.Build()
err = nb.AssignNode(n2)
} else {
err = assignValue(nb, testAssign.value)
}
if testAssign.kind == testProto.kind {
qt.Assert(t, err, qt.IsNil)
} else {
qt.Assert(t, err, qt.Not(qt.IsNil))
n := nb.Build()
// Assign something anyway, just so we can Build later.
err := assignValue(nb, testProto.value)
qt.Assert(t, err, qt.IsNil)
}
n := nb.Build()
// For both the regular node and its repr version,
// getting the right value for the kind should work.
for _, n := range []ipld.Node{
n,
n.(schema.TypedNode).Representation(),
} {
var gotValue interface{}
err = nil
switch testAssign.kind {
......@@ -138,8 +141,8 @@ func SchemaTestScalars(t *testing.T, engine Engine) {
qt.Assert(t, n.Length(), qt.Equals, int64(-1))
qt.Assert(t, n.IsAbsent(), qt.IsFalse)
qt.Assert(t, n.IsNull(), qt.IsFalse)
}
})
})
}
}
}
}
......
......@@ -8,6 +8,7 @@ import (
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/fluent"
"github.com/ipld/go-ipld-prime/must"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/schema"
)
......@@ -101,16 +102,32 @@ func SchemaTestStructNesting(t *testing.T, engine Engine) {
t.Run("typed-read", func(t *testing.T) {
Require(t, n.Kind(), ShouldEqual, ipld.Kind_Map)
Wish(t, n.Length(), ShouldEqual, int64(1))
n2 := must.Node(n.LookupByString("x"))
Require(t, n2.Kind(), ShouldEqual, ipld.Kind_Map)
n2Seg := must.Node(n.LookupBySegment(ipld.PathSegmentOfString("x")))
Wish(t, ipld.DeepEqual(n2, n2Seg), ShouldEqual, true)
n2Node := must.Node(n.LookupByNode(basicnode.NewString("x")))
Wish(t, ipld.DeepEqual(n2, n2Node), ShouldEqual, true)
Wish(t, must.String(must.Node(n2.LookupByString("s"))), ShouldEqual, "woo")
})
t.Run("repr-read", func(t *testing.T) {
nr := n.Representation()
Require(t, nr.Kind(), ShouldEqual, ipld.Kind_Map)
Wish(t, nr.Length(), ShouldEqual, int64(1))
n2 := must.Node(nr.LookupByString("r"))
Require(t, n2.Kind(), ShouldEqual, ipld.Kind_Map)
n2Seg := must.Node(nr.LookupBySegment(ipld.PathSegmentOfString("r")))
Wish(t, ipld.DeepEqual(n2, n2Seg), ShouldEqual, true)
n2Node := must.Node(nr.LookupByNode(basicnode.NewString("r")))
Wish(t, ipld.DeepEqual(n2, n2Node), ShouldEqual, true)
Wish(t, must.String(must.Node(n2.LookupByString("q"))), ShouldEqual, "woo")
})
})
......
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