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.
DateKeys/internal/testkit/notevectors.go

86 lines
3.2 KiB

package testkit
import (
"encoding/hex"
"errors"
"fmt"
"strings"
datekeys "g.activething.com/go/DateKeys"
"g.activething.com/go/DateKeys/extension"
)
// NoteVectorFile is testdata/vectors/note.json: the data of the public note
// (spec v0.11, §24.1), the extension datekeys.note of PUBLIC_HEADER, and what
// a writer and a reader do with it. A writer writes a note only when Result
// is ResultOK, and otherwise refuses it with Detail; a reader shows it only
// then, and otherwise treats it as unusable and says so.
type NoteVectorFile struct {
Spec string `json:"spec"`
Description string `json:"description"`
Notes []NoteVector `json:"notes"`
}
// NoteVector is the data of a note in hexadecimal, its result and, when it
// fails, the text of the rule it breaks, without its prefix and its code.
type NoteVector struct {
Name string `json:"name"`
Data string `json:"data"`
Result string `json:"result"`
Detail string `json:"detail,omitempty"`
}
// NoteResult checks the data of a note with the rules of §24.1, and returns
// its result and the detail of a failure.
func NoteResult(data []byte) (string, string) {
err := extension.CheckNote(string(data))
if err == nil {
return ResultOK, ""
}
if !errors.Is(err, datekeys.ErrExtensionDataInvalid) {
return Result(err), err.Error()
}
return Result(err), strings.TrimSuffix(err.Error(), ": "+datekeys.ErrExtensionDataInvalid.Code())
}
// NoteVectors computes testdata/vectors/note.json, and fails if a vector does
// not get the result it is written for.
func NoteVectors() (NoteVectorFile, error) {
f := NoteVectorFile{
Spec: SpecVersion,
Description: "The data of the public note, datekeys.note version 1 in the noncritical array of PUBLIC_HEADER (spec §24.1): " +
"the text in UTF-8, from 1 to 1024 bytes, that meets the rules of the declared author of §29.6. See testdata/README.md.",
}
bad := datekeys.ErrExtensionDataInvalid.Code()
var errs []error
for _, c := range []struct {
name string
data []byte
want string
}{
{"a note", []byte("Cartas del viaje a Lisboa"), ResultOK},
{"letters that are not ASCII and an emoji", []byte("Ñandú, año 2026 \U0001F30D"), ResultOK},
{"1024 bytes", []byte(strings.Repeat("a", 1024)), ResultOK},
{"an emoji with VS16, which the whitelist admits", []byte("\u2764\ufe0f"), ResultOK},
{"no byte", []byte{}, bad},
{"1025 bytes", []byte(strings.Repeat("a", 1025)), bad},
{"a tab", []byte("a\tb"), bad},
{"a line feed", []byte("a\nb"), bad},
{"a space at the start", []byte(" a"), bad},
{"a space at the end", []byte("a "), bad},
{"a bidi override", []byte("a\u202eb"), bad},
{"a zero width space, ignorable", []byte("a\u200bb"), bad},
{"a byte order mark at the start", []byte("\ufeffHola"), bad},
{"a byte that is not UTF-8", []byte{'a', 0xff}, bad},
{"the UTF-8 of a lone surrogate", []byte{0xed, 0xa0, 0x80}, bad},
{"a noncharacter", []byte("a\ufffeb"), bad},
} {
got, detail := NoteResult(c.data)
if got != c.want {
errs = append(errs, fmt.Errorf("note %q: %s, want %s", c.name, got, c.want))
}
f.Notes = append(f.Notes, NoteVector{Name: c.name, Data: hex.EncodeToString(c.data), Result: got, Detail: detail})
}
return f, errors.Join(errs...)
}

Powered by TurnKey Linux.