encoding_test.go

  1package sync
  2
  3import (
  4	"bytes"
  5	"testing"
  6)
  7
  8func TestWriteVarUint(t *testing.T) {
  9	tests := []struct {
 10		name     string
 11		value    uint64
 12		expected []byte
 13	}{
 14		{"zero", 0, []byte{0x00}},
 15		{"one", 1, []byte{0x01}},
 16		{"127 (max single byte)", 127, []byte{0x7f}},
 17		{"128 (two bytes)", 128, []byte{0x80, 0x01}},
 18		{"300 (two bytes)", 300, []byte{0xac, 0x02}},
 19		{"16383 (max two bytes)", 16383, []byte{0xff, 0x7f}},
 20		{"16384 (three bytes)", 16384, []byte{0x80, 0x80, 0x01}},
 21		{"max uint64", 0xffffffffffffffff, []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01}},
 22	}
 23
 24	for _, tt := range tests {
 25		t.Run(tt.name, func(t *testing.T) {
 26			buf := make([]byte, 20)
 27			n := writeVarUint(buf, tt.value)
 28			if !bytes.Equal(buf[:n], tt.expected) {
 29				t.Errorf("writeVarUint(%d) = %v, want %v", tt.value, buf[:n], tt.expected)
 30			}
 31		})
 32	}
 33}
 34
 35func TestReadVarUint(t *testing.T) {
 36	tests := []struct {
 37		name     string
 38		data     []byte
 39		expected uint64
 40		wantErr  bool
 41	}{
 42		{"zero", []byte{0x00}, 0, false},
 43		{"one", []byte{0x01}, 1, false},
 44		{"127", []byte{0x7f}, 127, false},
 45		{"128", []byte{0x80, 0x01}, 128, false},
 46		{"300", []byte{0xac, 0x02}, 300, false},
 47		{"16383", []byte{0xff, 0x7f}, 16383, false},
 48		{"16384", []byte{0x80, 0x80, 0x01}, 16384, false},
 49		{"max uint64", []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01}, 0xffffffffffffffff, false},
 50		{"empty input", []byte{}, 0, true},
 51		{"incomplete continuation", []byte{0x80}, 0, true},
 52	}
 53
 54	for _, tt := range tests {
 55		t.Run(tt.name, func(t *testing.T) {
 56			val, n, err := readVarUint(tt.data)
 57			if (err != nil) != tt.wantErr {
 58				t.Errorf("readVarUint(%v) error = %v, wantErr %v", tt.data, err, tt.wantErr)
 59				return
 60			}
 61			if !tt.wantErr && val != tt.expected {
 62				t.Errorf("readVarUint(%v) = %d, want %d", tt.data, val, tt.expected)
 63			}
 64			if !tt.wantErr && n == 0 {
 65				t.Error("readVarUint should return non-zero bytes read")
 66			}
 67		})
 68	}
 69}
 70
 71func TestEncodeVarByteArray(t *testing.T) {
 72	tests := []struct {
 73		name     string
 74		data     []byte
 75		expected []byte
 76	}{
 77		{"empty", []byte{}, []byte{0}},
 78		{"single byte", []byte{0x01}, []byte{1, 0x01}},
 79		{"multiple bytes", []byte{0x01, 0x02, 0x03}, []byte{3, 0x01, 0x02, 0x03}},
 80		{"longer data", []byte(bytes.Repeat([]byte{0xab}, 100)), append([]byte{100}, bytes.Repeat([]byte{0xab}, 100)...)},
 81	}
 82
 83	for _, tt := range tests {
 84		t.Run(tt.name, func(t *testing.T) {
 85			result := encodeVarByteArray(tt.data)
 86			if !bytes.Equal(result, tt.expected) {
 87				t.Errorf("encodeVarByteArray(%v) = %v, want %v", tt.data, result, tt.expected)
 88			}
 89		})
 90	}
 91}
 92
 93func TestEncodeMessage(t *testing.T) {
 94	tests := []struct {
 95		name     string
 96		msgType  uint8
 97		payload  []byte
 98		expected []byte
 99	}{
100		{"SyncStep1 with empty payload", SyncStep1, []byte{}, []byte{0, 0}},
101		{"SyncStep2 with payload", SyncStep2, []byte{0x01, 0x02}, []byte{1, 2, 0x01, 0x02}},
102		{"Update with empty payload", Update, []byte{}, []byte{2, 0}},
103		{"Update with payload", Update, []byte{0xff, 0xff}, []byte{2, 2, 0xff, 0xff}},
104		{"large payload", SyncStep1, []byte(bytes.Repeat([]byte{0xaa}, 50)), func() []byte {
105			buf := []byte{0, 50}
106			return append(buf, bytes.Repeat([]byte{0xaa}, 50)...)
107		}()},
108	}
109
110	for _, tt := range tests {
111		t.Run(tt.name, func(t *testing.T) {
112			result := encodeMessage(tt.msgType, tt.payload)
113			if !bytes.Equal(result, tt.expected) {
114				t.Errorf("encodeMessage(%d, %v) = %v, want %v", tt.msgType, tt.payload, result, tt.expected)
115			}
116		})
117	}
118}
119
120func TestMessageTypeConstants(t *testing.T) {
121	if SyncStep1 != 0 {
122		t.Errorf("expected SyncStep1=0, got %d", SyncStep1)
123	}
124	if SyncStep2 != 1 {
125		t.Errorf("expected SyncStep2=1, got %d", SyncStep2)
126	}
127	if Update != 2 {
128		t.Errorf("expected Update=2, got %d", Update)
129	}
130}
131
132func TestWriteReadVarUintRoundTrip(t *testing.T) {
133	values := []uint64{0, 1, 127, 128, 300, 16383, 16384, 1000, 100000, 0xffffffff}
134	for _, v := range values {
135		buf := make([]byte, 20)
136		n := writeVarUint(buf, v)
137		val, read, err := readVarUint(buf[:n])
138		if err != nil {
139			t.Errorf("round trip failed for %d: %v", v, err)
140		}
141		if val != v {
142			t.Errorf("round trip: wrote %d, read %d", v, val)
143		}
144		if read != n {
145			t.Errorf("round trip: wrote %d bytes, read %d bytes", n, read)
146		}
147	}
148}
149
150func TestReadVarUintOverflow(t *testing.T) {
151	overflowData := make([]byte, 11)
152	for i := 0; i < 10; i++ {
153		overflowData[i] = 0x80
154	}
155	overflowData[10] = 0x01
156
157	_, _, err := readVarUint(overflowData)
158	if err == nil {
159		t.Error("expected error for varint overflow")
160	}
161}
162
163func TestAppendVarUint(t *testing.T) {
164	tests := []struct {
165		name  string
166		value uint64
167	}{
168		{"zero", 0},
169		{"one", 1},
170		{"127", 127},
171		{"128", 128},
172		{"large", 0xFFFFFFFF},
173	}
174
175	for _, tt := range tests {
176		t.Run(tt.name, func(t *testing.T) {
177			result := appendVarUint(nil, tt.value)
178			val, n, err := readVarUint(result)
179			if err != nil {
180				t.Errorf("appendVarUint failed: %v", err)
181			}
182			if val != tt.value {
183				t.Errorf("appendVarUint(%d) = %d, want %d", tt.value, val, tt.value)
184			}
185			if n != len(result) {
186				t.Errorf("appendVarUint length mismatch: wrote %d, read %d", len(result), n)
187			}
188		})
189	}
190}
191
192func TestAppendVarByteArray(t *testing.T) {
193	tests := []struct {
194		name string
195		data []byte
196	}{
197		{"empty", []byte{}},
198		{"single byte", []byte{0x01}},
199		{"multiple bytes", []byte{0x01, 0x02, 0x03}},
200	}
201
202	for _, tt := range tests {
203		t.Run(tt.name, func(t *testing.T) {
204			result := appendVarByteArray(nil, tt.data)
205			if len(result) < 1 {
206				t.Error("encoded result too short")
207			}
208
209			length, n, err := readVarUint(result)
210			if err != nil {
211				t.Errorf("failed to read length: %v", err)
212			}
213
214			if length != uint64(len(tt.data)) {
215				t.Errorf("length mismatch: got %d, want %d", length, len(tt.data))
216			}
217
218			payload := result[n:]
219			if string(payload) != string(tt.data) {
220				t.Errorf("payload mismatch: got %v, want %v", payload, tt.data)
221			}
222		})
223	}
224}