niko_trust/internal/tce/vectors_test.go
Niko Marmeladkov 9d66003689
Initial commit: signed-object trust relay, verifier, and docs
- server: relay storing signed objects (PUT/GET), per-IP rate limiting,
  per-subject quota (1000), one-response-per-request, pagination,
  /v1/healthz /v1/readyz /v1/metrics
- verify: signature-verifying trust evaluator; every object is checked via
  env.Verify(), approvals via VerifyApprovalResponse, revocations via
  VerifyRevocationOf; k-of-n approval quorum
- docs: TRUST-MODEL.md and API.md describing issuer-anchored signatures and
  the endpoint/status-code contract
- tests: server, verify, and ratelimit packages
2026-08-12 22:36:49 +03:00

94 lines
2.7 KiB
Go

package tce
import (
"encoding/json"
"os"
"strings"
"testing"
)
// vectorsPath is the location of the frozen vector file relative to the
// package's test working directory.
const vectorsPath = "../../testdata/vectors/tce_vectors.json"
type vectorFile struct {
TceVersion int `json:"tce_version"`
NumberCanonicalization struct {
Accept map[string]string `json:"accept"`
Reject map[string]string `json:"reject"`
} `json:"number_canonicalization"`
}
func loadVectors(t *testing.T) *vectorFile {
t.Helper()
b, err := os.ReadFile(vectorsPath)
if err != nil {
t.Fatalf("read vectors: %v", err)
}
var vf vectorFile
if err := json.Unmarshal(b, &vf); err != nil {
t.Fatalf("parse vectors: %v", err)
}
return &vf
}
// TestNumberCanonicalizationVectors runs the frozen number vectors from the
// reference implementation: every accepted token must canonicalize to exactly
// the reference output, and every rejected token must be refused.
func TestNumberCanonicalizationVectors(t *testing.T) {
vf := loadVectors(t)
accept := vf.NumberCanonicalization.Accept
reject := vf.NumberCanonicalization.Reject
if len(accept) != 28 {
t.Errorf("expect 28 accepted tokens, got %d", len(accept))
}
if len(reject) != 18 {
t.Errorf("expect 18 rejected tokens, got %d", len(reject))
}
for token, want := range accept {
got, err := CanonicalNumber(token)
if err != nil {
t.Errorf("CanonicalNumber(%q): %v", token, err)
continue
}
if got != want {
t.Errorf("CanonicalNumber(%q) = %q, want %q", token, got, want)
}
}
for token, reason := range reject {
if strings.Contains(reason, "ERROR") {
t.Errorf("reference said %q is accepted but it is in the reject list", token)
}
if _, err := CanonicalNumber(token); err == nil {
t.Errorf("CanonicalNumber(%q) accepted, but the reference refuses it (%s)", token, reason)
}
}
}
// TestCanonicalNumberIdempotence pins the §5.1 properties that make the
// encoding canonical: canonicalizing an already canonical token is a no-op,
// and every accepted token yields an accepted, further-canonical result.
func TestCanonicalNumberIdempotence(t *testing.T) {
for _, token := range []string{
"0", "1", "-1", "1.5", "0.001", "12345678901234567890",
"999999999999999999999999", "0.000000000000000001", "-0.000000000000000001",
} {
c, err := CanonicalNumber(token)
if err != nil {
t.Fatalf("CanonicalNumber(%q): %v", token, err)
}
again, err := CanonicalNumber(c)
if err != nil {
t.Fatalf("canonical form %q does not canonicalize: %v", c, err)
}
if again != c {
t.Fatalf("canonical form not fixed point: %q -> %q", c, again)
}
if !IsCanonicalNumber(c) {
t.Fatalf("IsCanonicalNumber(%q) = false", c)
}
}
}