owpengram-server/internal/compat/layerwire/inbound_test.go

115 lines
4.1 KiB
Go

package layerwire
import "testing"
// TestInboundUpgradeTableWellFormed checks every inbound upgrade maps an old id
// to a real canonical method id, and that the old id is genuinely historical
// (not already a canonical constructor).
func TestInboundUpgradeTableWellFormed(t *testing.T) {
if len(inboundMethodUpgrades) == 0 {
t.Fatal("inboundMethodUpgrades is empty")
}
for oldID, newID := range inboundMethodUpgrades {
cl := canonical.byCRC[newID]
if cl == nil {
t.Errorf("upgrade target %#08x is not a canonical constructor", newID)
continue
}
if !cl.isFunc {
t.Errorf("upgrade target %s (%#08x) is not a method", cl.name, newID)
}
if oldID == newID {
t.Errorf("%s: old id equals canonical id %#08x", cl.name, oldID)
}
if prev := canonical.byCRC[oldID]; prev != nil {
t.Errorf("old id %#08x collides with canonical %s", oldID, prev.name)
}
}
}
// TestClientMethodAliasesWellFormed checks every hand-maintained client-drift
// alias maps to a real canonical method, and is reachable via UpgradeMethodCRC.
func TestClientMethodAliasesWellFormed(t *testing.T) {
for oldID, newID := range clientMethodAliases {
cl := canonical.byCRC[newID]
if cl == nil || !cl.isFunc {
t.Errorf("alias target %#08x is not a canonical method", newID)
}
if _, ok := inboundMethodUpgrades[oldID]; ok {
t.Errorf("alias %#08x duplicates a generated upgrade entry", oldID)
}
if got, ok := UpgradeMethodCRC(oldID); !ok || got != newID {
t.Errorf("UpgradeMethodCRC(%#08x) = (%#08x,%v), want (%#08x,true)", oldID, got, ok, newID)
}
}
}
// TestInboundDriftCoverage is the inbound drift gate: it statically proves every
// client-drift constructor in client-drift.tl can be upgraded to its canonical
// method — shared fields match (or have a converter), canonical-only required
// fields are defaultable, and renamed fields are mapped. Adding a TL line that
// isn't auto-upgradable fails here, telling the author exactly what converter or
// rename to declare (instead of discovering it at runtime).
func TestInboundDriftCoverage(t *testing.T) {
defaultable := map[wireKind]bool{
kindInt: true, kindLong: true, kindDouble: true, kindInt128: true, kindInt256: true,
kindBytes: true, kindString: true, kindBool: true, kindVector: true, kindVectorBare: true,
}
for crc, old := range driftModel.byCRC {
target := canonical.byName[old.name]
if target == nil {
t.Errorf("drift %s (%#08x): no canonical method of that name", old.name, crc)
continue
}
oldHas := map[string]*fieldLayout{}
for i := range old.fields {
oldHas[old.fields[i].name] = &old.fields[i]
}
for i := range target.fields {
nf := &target.fields[i]
if nf.isFlags {
continue
}
oldName := nf.name
if m, ok := driftFieldRenames[old.name+"\x00"+nf.name]; ok {
oldName = m
}
if of, ok := oldHas[oldName]; ok {
if typeSig(of) != typeSig(nf) && fieldConverters[typeSig(of)+"->"+typeSig(nf)] == nil {
t.Errorf("drift %s: field %q needs converter %s->%s", old.name, nf.name, typeSig(of), typeSig(nf))
}
continue
}
if nf.conditional() || nf.kind == kindTrue {
continue // optional canonical-only field — left absent
}
if !defaultable[nf.kind] {
t.Errorf("drift %s: canonical-only required field %q (kind %d) is not defaultable; declare a transform", old.name, nf.name, nf.kind)
}
}
}
}
// TestInboundUpgradeSendMessage validates the full chain for the highest-value
// method: a layer-220 client's messages.sendMessage id upgrades to the 227 id.
func TestInboundUpgradeSendMessage(t *testing.T) {
m220 := loadLayerModel(t, 220)
old, ok := m220.byName["messages.sendMessage"]
if !ok {
t.Fatal("messages.sendMessage missing from layer-220 schema")
}
canon, ok := canonical.byName["messages.sendMessage"]
if !ok {
t.Fatal("messages.sendMessage missing from canonical schema")
}
if old.crc == canon.crc {
t.Skip("sendMessage unchanged 220->227; nothing to upgrade")
}
newID, ok := UpgradeMethodCRC(old.crc)
if !ok {
t.Fatalf("sendMessage@220 (%#08x) not in upgrade table", old.crc)
}
if newID != canon.crc {
t.Fatalf("sendMessage upgrade = %#08x, want canonical %#08x", newID, canon.crc)
}
}