You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
3.3 KiB
105 lines
3.3 KiB
package extension_test
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
datekeys "github.com/datekeys/datekeys-go"
|
|
"github.com/datekeys/datekeys-go/extension"
|
|
)
|
|
|
|
func ext(t *testing.T, id string, v uint64, data any) extension.Extension {
|
|
t.Helper()
|
|
if data == nil {
|
|
return extension.Extension{ID: id, Version: v}
|
|
}
|
|
e, err := extension.New(id, v, data)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return e
|
|
}
|
|
|
|
func TestEncodeSortsCanonically(t *testing.T) {
|
|
in := []extension.Extension{ext(t, "org.b", 1, nil), ext(t, "org.a", 2, "x"), ext(t, "Z", 9, nil), ext(t, "org.aa", 1, 7)}
|
|
w, err := extension.Encode(in)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var order []string
|
|
for _, e := range w {
|
|
order = append(order, e.ID)
|
|
}
|
|
// Bytewise UTF-8 order: uppercase before lowercase, prefixes first.
|
|
if got := []string{"Z", "org.a", "org.aa", "org.b"}; !equal(order, got) {
|
|
t.Fatalf("order %v, want %v", order, got)
|
|
}
|
|
if w, _ := extension.Encode(nil); w != nil {
|
|
t.Fatal("empty array must encode to nil so that the key is omitted")
|
|
}
|
|
back, err := extension.Decode(w)
|
|
if err != nil || len(back) != 4 || back[1].ID != "org.a" || string(back[1].Data) != "\x61\x78" {
|
|
t.Fatalf("decode: %+v %v", back, err)
|
|
}
|
|
}
|
|
|
|
func TestEncodeRejects(t *testing.T) {
|
|
for name, in := range map[string][]extension.Extension{
|
|
"same id twice": {ext(t, "org.a", 1, nil), ext(t, "org.a", 2, nil)},
|
|
"empty id": {ext(t, "", 1, nil)},
|
|
"invalid UTF-8 id": {{ID: "org.\xff", Version: 1}},
|
|
"non-canonical data": {{ID: "org.a", Version: 1, Data: []byte{0x18, 0x01}}},
|
|
"data with two items": {{ID: "org.a", Version: 1, Data: []byte{0x01, 0x02}}},
|
|
"data with a tag": {{ID: "org.a", Version: 1, Data: []byte{0xc1, 0x01}}},
|
|
} {
|
|
if _, err := extension.Encode(in); !errors.Is(err, datekeys.ErrNonCanonicalCBOR) {
|
|
t.Errorf("%s: %v", name, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDecodeRejects(t *testing.T) {
|
|
for name, in := range map[string][]extension.Wire{
|
|
"out of order": {{ID: "org.b", Version: 1}, {ID: "org.a", Version: 1}},
|
|
"versions out of order": {{ID: "org.a", Version: 2}, {ID: "org.a", Version: 1}},
|
|
"repeated id": {{ID: "org.a", Version: 1}, {ID: "org.a", Version: 2}},
|
|
"non-canonical data": {{ID: "org.a", Version: 1, Data: []byte{0xf9, 0x3c, 0x00, 0x00}}},
|
|
} {
|
|
if _, err := extension.Decode(in); !errors.Is(err, datekeys.ErrNonCanonicalCBOR) {
|
|
t.Errorf("%s: %v", name, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCrossArrayRules(t *testing.T) {
|
|
crit := []extension.Extension{ext(t, "org.a", 1, nil)}
|
|
non := []extension.Extension{ext(t, "org.a", 2, nil)}
|
|
if err := extension.CheckDisjoint(crit, non); !errors.Is(err, datekeys.ErrNonCanonicalCBOR) {
|
|
t.Fatalf("id in both arrays: %v", err)
|
|
}
|
|
if err := extension.CheckCritical(crit, nil); !errors.Is(err, datekeys.ErrExtensionCriticalUnknown) {
|
|
t.Fatalf("unknown critical accepted by the base protocol: %v", err)
|
|
}
|
|
if err := extension.CheckCritical(crit, extension.Set{"org.a": {2}}); !errors.Is(err, datekeys.ErrExtensionCriticalUnknown) {
|
|
t.Fatalf("other version accepted: %v", err)
|
|
}
|
|
if err := extension.CheckCritical(crit, extension.Set{"org.a": {1}}); err != nil {
|
|
t.Fatalf("known critical rejected: %v", err)
|
|
}
|
|
if err := extension.CheckCritical(nil, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func equal(a, b []string) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
for i := range a {
|
|
if a[i] != b[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|