RegionIO/internal/nbt/nbt_test.go
Master290 a7bb9496ae Initial commit: RegionIO Minecraft server core (26.1.2/protocol 775)
Vanilla-faithful overworld generator (final_density + multi-noise biomes),
full connection lifecycle (status/login/configuration/play), chunk streaming,
creative block editing, and the protocol/nbt/registry infrastructure.
2026-06-24 00:32:51 +03:00

119 lines
3.4 KiB
Go

package nbt
import (
"bytes"
"reflect"
"testing"
)
// TestGoldenHelloWorld checks the canonical NBT example: a named-root compound
// {"hello world": {"name": "Bananrama"}}.
func TestGoldenHelloWorld(t *testing.T) {
root := NewCompound().Set("name", String("Bananrama"))
got := MarshalNamed("hello world", root)
want := []byte{
0x0a, 0x00, 0x0b, // TAG_Compound, name len 11
'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
0x08, 0x00, 0x04, 'n', 'a', 'm', 'e', // TAG_String, name len 4
0x00, 0x09, // string len 9
'B', 'a', 'n', 'a', 'n', 'r', 'a', 'm', 'a',
0x00, // TAG_End
}
if !bytes.Equal(got, want) {
t.Fatalf("golden mismatch:\n got=%x\nwant=%x", got, want)
}
}
// TestNetworkRootHasNoName verifies the 1.20.2+ network root omits the name.
func TestNetworkRootHasNoName(t *testing.T) {
got := Marshal(NewCompound().Set("a", Byte(1)))
want := []byte{
0x0a, // TAG_Compound (no name)
0x01, 0x00, 0x01, 'a', // TAG_Byte, name len 1
0x01, // value 1
0x00, // TAG_End
}
if !bytes.Equal(got, want) {
t.Fatalf("network root mismatch:\n got=%x\nwant=%x", got, want)
}
}
// TestRoundTrip encodes a richly-nested compound and decodes it back.
func TestRoundTrip(t *testing.T) {
root := NewCompound().
Set("b", Byte(-7)).
Set("s", Short(300)).
Set("i", Int(-123456)).
Set("l", Long(1<<40)).
Set("f", Float(3.5)).
Set("d", Double(-2.25)).
Set("str", String("héllo")).
Set("bytes", ByteArray{1, 2, 3}).
Set("ints", IntArray{10, -20, 30}).
Set("longs", LongArray{1, 2}).
Set("list", List{ElemID: TagInt, Elems: []Tag{Int(1), Int(2), Int(3)}}).
Set("empty", List{ElemID: TagString}).
Set("nested", NewCompound().Set("x", String("y")))
enc := Marshal(root)
dec, err := Unmarshal(enc)
if err != nil {
t.Fatalf("unmarshal: %v", err)
}
reenc := Marshal(dec)
if !bytes.Equal(enc, reenc) {
t.Fatalf("round-trip bytes differ:\n first=%x\nsecond=%x", enc, reenc)
}
}
// TestModifiedUTF8 round-trips strings including NUL and supplementary chars.
func TestModifiedUTF8(t *testing.T) {
cases := []string{
"",
"plain ascii",
"with\x00nul",
"café — français",
"emoji 😀 supplementary",
}
for _, s := range cases {
enc := encodeModifiedUTF8(nil, s)
// NUL must be escaped as 0xC0 0x80, never a literal zero byte.
if bytes.IndexByte(enc, 0) >= 0 {
t.Fatalf("encoding of %q contains a literal NUL byte", s)
}
dec, err := decodeModifiedUTF8(enc)
if err != nil {
t.Fatalf("decode %q: %v", s, err)
}
if dec != s {
t.Fatalf("round-trip mismatch: got %q want %q", dec, s)
}
}
}
// TestDecodeNamedRoundTrip checks the named-format decode path.
func TestDecodeNamedRoundTrip(t *testing.T) {
root := NewCompound().Set("k", Int(42))
enc := MarshalNamed("root", root)
name, dec, err := UnmarshalNamed(enc)
if err != nil {
t.Fatalf("unmarshal named: %v", err)
}
if name != "root" {
t.Fatalf("root name = %q, want %q", name, "root")
}
if !reflect.DeepEqual(Marshal(dec), Marshal(root)) {
t.Fatal("named decode produced different tree")
}
}
// TestTruncatedInput ensures the decoder rejects short buffers without panic.
func TestTruncatedInput(t *testing.T) {
enc := Marshal(NewCompound().Set("x", Long(1)))
for n := 0; n < len(enc); n++ {
if _, err := Unmarshal(enc[:n]); err == nil {
t.Fatalf("expected error decoding %d/%d bytes", n, len(enc))
}
}
}