niko_trust/pkg/tce/vectors_test.go
Niko Marmeladkov 3bf13fa488 Public SDK packages, proxy-aware rate limits, service login recipe
- internal/{address,identity,protocol,tce,transport,verify} -> pkg/ so
  external Go projects can import the verified core; invariant tests
  updated for the new paths
- Config.TrustProxy: key rate limiting by X-Forwarded-For when the relay
  sits behind a reverse proxy (off by default, header never trusted
  otherwise)
- examples/service + examples/approve: complete passwordless login round
  trip (mint request -> wallet approves -> local verify), run live in CI
- docs/SERVICE-GUIDE.md: the integration recipe
2026-08-26 12:49:54 +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)
}
}
}