Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update tests for unions; several fixes #75

Merged
merged 4 commits into from
Sep 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions schema/gen/go/genUnion.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,13 @@ func (g unionGenerator) EmitNodeMethodMapIterator(w io.Writer) {
switch itr.n.tag {
{{- range $i, $member := .Type.Members }}
case {{ add $i 1 }}:
return &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}, &itr.n.x{{ add $i 1 }}, nil
k, v = &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}, &itr.n.x{{ add $i 1 }}
{{- end}}
{{- else if (eq (.AdjCfg.UnionMemlayout .Type) "interface") }}
switch n2 := itr.n.x.(type) {
{{- range $member := .Type.Members }}
case {{ $member | TypeSymbol }}:
return &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}, n2, nil
k, v = &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}, n2
{{- end}}
{{- end}}
default:
Expand Down Expand Up @@ -324,6 +324,7 @@ func (g unionBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {
default:
panic("unreachable")
}
na.ca = 0
na.cm = schema.Maybe_Absent
}
`, w, g.AdjCfg, g)
Expand Down
5 changes: 3 additions & 2 deletions schema/gen/go/genUnionReprKeyed.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ func (g unionReprKeyedReprGenerator) EmitNodeMethodMapIterator(w io.Writer) {
switch itr.n.tag {
{{- range $i, $member := .Type.Members }}
case {{ add $i 1 }}:
return &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial, itr.n.x{{ add $i 1 }}.Representation(), nil
k, v = &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial, itr.n.x{{ add $i 1 }}.Representation()
{{- end}}
{{- else if (eq (.AdjCfg.UnionMemlayout .Type) "interface") }}
switch n2 := itr.n.x.(type) {
{{- range $member := .Type.Members }}
case {{ $member | TypeSymbol }}:
return &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial, n2.Representation(), nil
k, v = &memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial, n2.Representation()
{{- end}}
{{- end}}
default:
Expand Down Expand Up @@ -235,6 +235,7 @@ func (g unionReprKeyedReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {
default:
panic("unreachable")
}
na.ca = 0
na.cm = schema.Maybe_Absent
}
`, w, g.AdjCfg, g)
Expand Down
1 change: 1 addition & 0 deletions schema/gen/go/genUnionReprKinded.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ func (g unionReprKindedReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer)
default:
panic("unreachable")
}
na.ca = 0
}
`, w, g.AdjCfg, g)
}
Expand Down
68 changes: 37 additions & 31 deletions schema/gen/go/testUnionsKinded_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ package gengo
import (
"testing"

. "github.com/warpfork/go-wish"

"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/fluent"
"github.com/ipld/go-ipld-prime/must"
"github.com/ipld/go-ipld-prime/schema"
)

Expand Down Expand Up @@ -35,36 +31,46 @@ func TestUnionKinded(t *testing.T) {
}),
))

// These are the same *type-level* as in TestUnionKeyedComplexChildren,
// but (of course) have very different representations.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been entertaining the thought of putting some methods on this testcase structure so that one can "derive" variations of them with only some fields changed, which could be useful for tests like this that poke at variations in representation.

Could be a future work thing.

specs := []testcase{
{
name: "InhabitantA",
typeJson: `{"String":"whee"}`,
reprJson: `"whee"`,
typePoints: []testcasePoint{
{"", ipld.ReprKind_Map},
{"String", "whee"},
//{"SmolStruct", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
},
reprPoints: []testcasePoint{
{"", ipld.ReprKind_String},
{"", "whee"},
},
},
{
name: "InhabitantB",
typeJson: `{"SmolStruct":{"s":"whee"}}`,
reprJson: `{"q":"whee"}`,
typePoints: []testcasePoint{
{"", ipld.ReprKind_Map},
//{"String", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
{"SmolStruct", ipld.ReprKind_Map},
{"SmolStruct/s", "whee"},
},
reprPoints: []testcasePoint{
{"", ipld.ReprKind_Map},
{"q", "whee"},
},
},
}

test := func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
np := getPrototypeByName("WheeUnion")
nrp := getPrototypeByName("WheeUnion.Repr")
var n schema.TypedNode
t.Run("typed-create", func(t *testing.T) {
n = fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {
na.AssembleEntry("SmolStruct").CreateMap(1, func(na fluent.MapAssembler) {
na.AssembleEntry("s").AssignString("whee")
})
}).(schema.TypedNode)
t.Run("typed-read", func(t *testing.T) {
Require(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 1)
n2 := must.Node(n.LookupByString("SmolStruct"))
Require(t, n2.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, must.String(must.Node(n2.LookupByString("s"))), ShouldEqual, "whee")
})
t.Run("repr-read", func(t *testing.T) {
nr := n.Representation()
Require(t, nr.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, nr.Length(), ShouldEqual, 1)
Wish(t, must.String(must.Node(nr.LookupByString("q"))), ShouldEqual, "whee")
})
})
t.Run("repr-create", func(t *testing.T) {
nr := fluent.MustBuildMap(nrp, 1, func(na fluent.MapAssembler) {
na.AssembleEntry("q").AssignString("whee")
})
Wish(t, n, ShouldEqual, nr)
})
for _, tcase := range specs {
tcase.Test(t, np, nrp)
}
}

t.Run("union-using-embed", func(t *testing.T) {
Expand Down
206 changes: 148 additions & 58 deletions schema/gen/go/testUnions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ package gengo
import (
"testing"

. "github.com/warpfork/go-wish"

"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/fluent"
"github.com/ipld/go-ipld-prime/must"
"github.com/ipld/go-ipld-prime/schema"
)

Expand All @@ -28,32 +24,45 @@ func TestUnionKeyed(t *testing.T) {
}),
))

specs := []testcase{
{
name: "InhabitantA",
typeJson: `{"String":"whee"}`,
reprJson: `{"a":"whee"}`,
typePoints: []testcasePoint{
{"", ipld.ReprKind_Map},
{"String", "whee"},
//{"Strung", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
},
reprPoints: []testcasePoint{
{"", ipld.ReprKind_Map},
{"a", "whee"},
//{"b", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
},
},
{
name: "InhabitantB",
typeJson: `{"Strung":"whee"}`,
reprJson: `{"b":"whee"}`,
typePoints: []testcasePoint{
{"", ipld.ReprKind_Map},
//{"String", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
{"Strung", "whee"},
},
reprPoints: []testcasePoint{
{"", ipld.ReprKind_Map},
//{"a", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
{"b", "whee"},
},
},
}

test := func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
np := getPrototypeByName("StrStr")
nrp := getPrototypeByName("StrStr.Repr")
var n schema.TypedNode
t.Run("typed-create", func(t *testing.T) {
n = fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {
na.AssembleEntry("Strung").AssignString("whee")
}).(schema.TypedNode)
t.Run("typed-read", func(t *testing.T) {
Require(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 1)
Wish(t, must.String(must.Node(n.LookupByString("Strung"))), ShouldEqual, "whee")
})
t.Run("repr-read", func(t *testing.T) {
nr := n.Representation()
Require(t, nr.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, nr.Length(), ShouldEqual, 1)
Wish(t, must.String(must.Node(nr.LookupByString("b"))), ShouldEqual, "whee")
})
})
t.Run("repr-create", func(t *testing.T) {
nr := fluent.MustBuildMap(nrp, 2, func(na fluent.MapAssembler) {
na.AssembleEntry("b").AssignString("whee")
})
Wish(t, n, ShouldEqual, nr)
})
for _, tcase := range specs {
tcase.Test(t, np, nrp)
}
}

t.Run("union-using-embed", func(t *testing.T) {
Expand Down Expand Up @@ -107,40 +116,47 @@ func TestUnionKeyedComplexChildren(t *testing.T) {
}),
))

specs := []testcase{
{
name: "InhabitantA",
typeJson: `{"String":"whee"}`,
reprJson: `{"a":"whee"}`,
typePoints: []testcasePoint{
{"", ipld.ReprKind_Map},
{"String", "whee"},
//{"SmolStruct", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: link to the issue in these TODOs? that way when the issue gets fixed, it's trivial to find the spots that can be improved

},
reprPoints: []testcasePoint{
{"", ipld.ReprKind_Map},
{"a", "whee"},
//{"b", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
},
},
{
name: "InhabitantB",
typeJson: `{"SmolStruct":{"s":"whee"}}`,
reprJson: `{"b":{"q":"whee"}}`,
typePoints: []testcasePoint{
{"", ipld.ReprKind_Map},
//{"String", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
{"SmolStruct", ipld.ReprKind_Map},
{"SmolStruct/s", "whee"},
},
reprPoints: []testcasePoint{
{"", ipld.ReprKind_Map},
//{"a", ipld.ErrNotExists{}}, // TODO: need better error typing from traversal package.
{"b", ipld.ReprKind_Map},
{"b/q", "whee"},
},
},
}

test := func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
np := getPrototypeByName("WheeUnion")
nrp := getPrototypeByName("WheeUnion.Repr")
var n schema.TypedNode
t.Run("typed-create", func(t *testing.T) {
n = fluent.MustBuildMap(np, 1, func(na fluent.MapAssembler) {
na.AssembleEntry("SmolStruct").CreateMap(1, func(na fluent.MapAssembler) {
na.AssembleEntry("s").AssignString("whee")
})
}).(schema.TypedNode)
t.Run("typed-read", func(t *testing.T) {
Require(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, n.Length(), ShouldEqual, 1)
n2 := must.Node(n.LookupByString("SmolStruct"))
Require(t, n2.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, must.String(must.Node(n2.LookupByString("s"))), ShouldEqual, "whee")
})
t.Run("repr-read", func(t *testing.T) {
nr := n.Representation()
Require(t, nr.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, nr.Length(), ShouldEqual, 1)
n2 := must.Node(nr.LookupByString("b"))
Require(t, n2.ReprKind(), ShouldEqual, ipld.ReprKind_Map)
Wish(t, must.String(must.Node(n2.LookupByString("q"))), ShouldEqual, "whee")
})
})
t.Run("repr-create", func(t *testing.T) {
nr := fluent.MustBuildMap(nrp, 2, func(na fluent.MapAssembler) {
na.AssembleEntry("b").CreateMap(1, func(na fluent.MapAssembler) {
na.AssembleEntry("q").AssignString("whee")
})
})
Wish(t, n, ShouldEqual, nr)
})
for _, tcase := range specs {
tcase.Test(t, np, nrp)
}
}

t.Run("union-using-embed", func(t *testing.T) {
Expand All @@ -162,3 +178,77 @@ func TestUnionKeyedComplexChildren(t *testing.T) {
})
})
}

// TestUnionKeyedReset puts a union inside a list, so that we can use the list's reuse of assembler as a test of the assembler's reset feature.
// The value inside the union is also more complex than a scalar value so that we test resetting gets passed down, too.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so that we test that resetting...

I'm pretty sure, but not 100% sure :)

func TestUnionKeyedReset(t *testing.T) {
ts := schema.TypeSystem{}
ts.Init()
adjCfg := &AdjunctCfg{}
ts.Accumulate(schema.SpawnString("String"))
ts.Accumulate(schema.SpawnStruct("SmolStruct",
[]schema.StructField{
schema.SpawnStructField("s", "String", false, false),
},
schema.SpawnStructRepresentationMap(map[string]string{
"s": "q",
}),
))
ts.Accumulate(schema.SpawnUnion("WheeUnion",
[]schema.TypeName{
"String",
"SmolStruct",
},
schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{
"a": "String",
"b": "SmolStruct",
}),
))
ts.Accumulate(schema.SpawnList("OuterList",
"WheeUnion", false,
))

specs := []testcase{
{
typeJson: `[{"SmolStruct":{"s":"one"}}, {"SmolStruct":{"s":"two"}}, {"String":"three"}]`,
reprJson: `[{"b":{"q":"one"}}, {"b":{"q":"two"}}, {"a":"three"}]`,
typePoints: []testcasePoint{
{"0/SmolStruct/s", "one"},
{"1/SmolStruct/s", "two"},
{"2/String", "three"},
},
reprPoints: []testcasePoint{
{"0/b/q", "one"},
{"1/b/q", "two"},
{"2/a", "three"},
},
},
}

test := func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These setup blocks (this and a dozen or so lines below) are getting somewhat redundant. It might soon be time to try to extract something here.

I've been wary to do this prematurely, and it'll be a bit tricky because reasons for doing distinct gen invocation are various (e.g. in these tests, it's always poking CfgUnionMemlayout; but that's not true in other tests which don't show up in this diff). But it's getting to the point it might be worth some looking into soon.

np := getPrototypeByName("OuterList")
nrp := getPrototypeByName("OuterList.Repr")
for _, tcase := range specs {
tcase.Test(t, np, nrp)
}
}

t.Run("union-using-embed", func(t *testing.T) {
Copy link
Contributor

@mvdan mvdan Sep 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking some more, but these should be CamelCase for the sake of consistency. There are some examples in https://golang.org/pkg/testing/ too.

adjCfg.CfgUnionMemlayout = map[schema.TypeName]string{"WheeUnion": "embedAll"}

prefix := "union-keyed-reset-using-embed"
pkgName := "main"
genAndCompileAndTest(t, prefix, pkgName, ts, adjCfg, func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
test(t, getPrototypeByName)
})
})
t.Run("union-using-interface", func(t *testing.T) {
adjCfg.CfgUnionMemlayout = map[schema.TypeName]string{"WheeUnion": "interface"}

prefix := "union-keyed-reset-using-interface"
pkgName := "main"
genAndCompileAndTest(t, prefix, pkgName, ts, adjCfg, func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype) {
test(t, getPrototypeByName)
})
})
}