tpl/collections: Unwrap any interface value in sort and where

Hugo `0.55.0` introduced some new interface types for `Page` etc.

This worked great in general, but there were cases where this would fail in `where` and `sort`.

One such example would be sorting by `MenuItem.Page.Date` where `Page` on `MenuItem` was a small subset of the bigger `page.Page` interface.

This commit fixes that by unwrapping such interface values.

Fixes #5989
This commit is contained in:
Bjørn Erik Pedersen
2019-05-27 22:57:57 +02:00
parent fad183c4ae
commit 8d898ad667
4 changed files with 153 additions and 22 deletions

View File

@@ -38,13 +38,31 @@ func TestWhere(t *testing.T) {
d5 := d4.Add(1 * time.Hour)
d6 := d5.Add(1 * time.Hour)
for i, test := range []struct {
type testt struct {
seq interface{}
key interface{}
op string
match interface{}
expect interface{}
}{
}
createTestVariants := func(test testt) []testt {
testVariants := []testt{test}
if islice := ToTstXIs(test.seq); islice != nil {
variant := test
variant.seq = islice
expect := ToTstXIs(test.expect)
if expect != nil {
variant.expect = expect
}
testVariants = append(testVariants, variant)
}
return testVariants
}
for i, test := range []testt{
{
seq: []map[int]string{
{1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"},
@@ -216,6 +234,24 @@ func TestWhere(t *testing.T) {
{"foo": &TstX{A: "c", B: "d"}},
},
},
{
seq: []TstXIHolder{
{&TstX{A: "a", B: "b"}}, {&TstX{A: "c", B: "d"}}, {&TstX{A: "e", B: "f"}},
},
key: "XI.TstRp", match: "rc",
expect: []TstXIHolder{
{&TstX{A: "c", B: "d"}},
},
},
{
seq: []TstXIHolder{
{&TstX{A: "a", B: "b"}}, {&TstX{A: "c", B: "d"}}, {&TstX{A: "e", B: "f"}},
},
key: "XI.A", match: "e",
expect: []TstXIHolder{
{&TstX{A: "e", B: "f"}},
},
},
{
seq: []map[string]Mid{
{"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}},
@@ -522,28 +558,33 @@ func TestWhere(t *testing.T) {
},
},
} {
t.Run(fmt.Sprintf("test case %d for key %s", i, test.key), func(t *testing.T) {
var results interface{}
var err error
if len(test.op) > 0 {
results, err = ns.Where(test.seq, test.key, test.op, test.match)
} else {
results, err = ns.Where(test.seq, test.key, test.match)
}
if b, ok := test.expect.(bool); ok && !b {
if err == nil {
t.Errorf("[%d] Where didn't return an expected error", i)
testVariants := createTestVariants(test)
for j, test := range testVariants {
name := fmt.Sprintf("[%d/%d] %T %s %s", i, j, test.seq, test.op, test.key)
t.Run(name, func(t *testing.T) {
var results interface{}
var err error
if len(test.op) > 0 {
results, err = ns.Where(test.seq, test.key, test.op, test.match)
} else {
results, err = ns.Where(test.seq, test.key, test.match)
}
} else {
if err != nil {
t.Errorf("[%d] failed: %s", i, err)
if b, ok := test.expect.(bool); ok && !b {
if err == nil {
t.Fatalf("[%d] Where didn't return an expected error", i)
}
} else {
if err != nil {
t.Fatalf("[%d] failed: %s", i, err)
}
if !reflect.DeepEqual(results, test.expect) {
t.Fatalf("Where clause matching %v with %v in seq %v (%T),\ngot\n%v (%T) but expected\n%v (%T)", test.key, test.match, test.seq, test.seq, results, results, test.expect, test.expect)
}
}
if !reflect.DeepEqual(results, test.expect) {
t.Errorf("[%d] Where clause matching %v with %v, got %v but expected %v", i, test.key, test.match, results, test.expect)
}
}
})
})
}
}
var err error