go-lns/pkg/primitives/view_test.go
Virgil bc1d37e2dc feat(primitives): preserve name undo order
Co-authored-by: Virgil <virgil@lethean.io>
2026-04-02 03:20:17 +00:00

156 lines
3.4 KiB
Go

// SPDX-License-Identifier: EUPL-1.2
package primitives
import (
"bytes"
"testing"
)
type stubNameStateDB struct {
state *NameState
err error
}
func (db stubNameStateDB) GetNameState(hash Hash) (*NameState, error) {
if db.err != nil {
return nil, db.err
}
if db.state == nil {
return nil, nil
}
cp := db.state.Clone()
cp.NameHash = hash
return &cp, nil
}
func TestNameViewGetNameState(t *testing.T) {
var hash Hash
hash[0] = 0x42
view := NewNameView()
db := stubNameStateDB{
state: &NameState{Name: []byte("example"), Height: 7},
}
ns, err := view.GetNameStateSync(db, hash)
if err != nil {
t.Fatalf("GetNameStateSync returned error: %v", err)
}
if ns == nil {
t.Fatal("GetNameStateSync returned nil state")
}
if ns.NameHash != hash {
t.Fatalf("GetNameStateSync returned hash %x, want %x", ns.NameHash, hash)
}
ns2, err := view.GetNameState(db, hash)
if err != nil {
t.Fatalf("GetNameState returned error: %v", err)
}
if ns2 != ns {
t.Fatal("GetNameState should return the cached state")
}
missingHash := Hash{0x99}
empty, err := view.GetNameState(nil, missingHash)
if err != nil {
t.Fatalf("GetNameState(nil) returned error: %v", err)
}
if empty == nil || empty.NameHash != missingHash {
t.Fatal("GetNameState(nil) should create an empty state with the requested hash")
}
}
func TestNameUndoRoundTrip(t *testing.T) {
var hash Hash
hash[0] = 0x51
view := NewNameView()
ns := &NameState{NameHash: hash, Name: []byte("example"), Height: 10}
ns.setValue(123)
view.names[hash] = ns
undo := view.ToNameUndo()
if len(undo.Names) != 1 {
t.Fatalf("ToNameUndo produced %d entries, want 1", len(undo.Names))
}
encoded, err := undo.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary returned error: %v", err)
}
if got := undo.GetSize(); got != len(encoded) {
t.Fatalf("GetSize() = %d, want %d", got, len(encoded))
}
var decoded NameUndo
if err := decoded.UnmarshalBinary(encoded); err != nil {
t.Fatalf("UnmarshalBinary returned error: %v", err)
}
if len(decoded.Names) != 1 {
t.Fatalf("decoded undo has %d entries, want 1", len(decoded.Names))
}
if decoded.Names[0].NameHash != hash {
t.Fatalf("decoded hash %x, want %x", decoded.Names[0].NameHash, hash)
}
if !bytes.Equal(decoded.Names[0].Delta.MarshalMust(t), undo.Names[0].Delta.MarshalMust(t)) {
t.Fatal("decoded delta did not match the original")
}
}
func TestNameUndoPreservesInsertionOrder(t *testing.T) {
view := NewNameView()
var firstHash Hash
firstHash[0] = 0x01
var secondHash Hash
secondHash[0] = 0x02
first, err := view.GetNameStateSync(nil, firstHash)
if err != nil {
t.Fatalf("GetNameStateSync(first) returned error: %v", err)
}
first.setValue(11)
second, err := view.GetNameStateSync(nil, secondHash)
if err != nil {
t.Fatalf("GetNameStateSync(second) returned error: %v", err)
}
second.setValue(22)
undo := view.ToNameUndo()
if len(undo.Names) != 2 {
t.Fatalf("ToNameUndo produced %d entries, want 2", len(undo.Names))
}
if undo.Names[0].NameHash != firstHash {
t.Fatalf("first undo entry hash = %x, want %x", undo.Names[0].NameHash, firstHash)
}
if undo.Names[1].NameHash != secondHash {
t.Fatalf("second undo entry hash = %x, want %x", undo.Names[1].NameHash, secondHash)
}
}
func (d NameDelta) MarshalMust(t *testing.T) []byte {
t.Helper()
data, err := d.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary returned error: %v", err)
}
return data
}