mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
test: add unit tests for core packages
Add comprehensive test coverage for: - common/token: token generation and RNG tests - common/stringsupport: string encoding, CSV operations - common/byteframe: binary read/write operations - common/mhfcourse: course/subscription logic - network/crypt_packet: packet header parsing - network/binpacket: binary packet round-trips - network/mhfpacket: packet interface and opcode mapping - config: configuration struct and loading - server/entranceserver: response building - server/signserver: response ID constants - server/signv2server: HTTP endpoint validation - server/channelserver: session, semaphore, and handler tests All tests pass with race detector enabled.
This commit is contained in:
341
common/stringsupport/string_convert_test.go
Normal file
341
common/stringsupport/string_convert_test.go
Normal file
@@ -0,0 +1,341 @@
|
||||
package stringsupport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/encoding/japanese"
|
||||
)
|
||||
|
||||
func TestStringConverterDecode(t *testing.T) {
|
||||
sc := &StringConverter{Encoding: japanese.ShiftJIS}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input []byte
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{"empty", []byte{}, "", false},
|
||||
{"ascii", []byte("Hello"), "Hello", false},
|
||||
{"japanese hello", []byte{0x82, 0xb1, 0x82, 0xf1, 0x82, 0xc9, 0x82, 0xbf, 0x82, 0xcd}, "こんにちは", false},
|
||||
{"mixed", []byte{0x41, 0x42, 0x43}, "ABC", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := sc.Decode(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Decode() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Decode() = %q, want %q", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringConverterEncode(t *testing.T) {
|
||||
sc := &StringConverter{Encoding: japanese.ShiftJIS}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want []byte
|
||||
wantErr bool
|
||||
}{
|
||||
{"empty", "", []byte{}, false},
|
||||
{"ascii", "Hello", []byte("Hello"), false},
|
||||
{"japanese hello", "こんにちは", []byte{0x82, 0xb1, 0x82, 0xf1, 0x82, 0xc9, 0x82, 0xbf, 0x82, 0xcd}, false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := sc.Encode(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Encode() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !bytes.Equal(got, tt.want) {
|
||||
t.Errorf("Encode() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringConverterMustDecode(t *testing.T) {
|
||||
sc := &StringConverter{Encoding: japanese.ShiftJIS}
|
||||
|
||||
// Valid input should not panic
|
||||
result := sc.MustDecode([]byte("Hello"))
|
||||
if result != "Hello" {
|
||||
t.Errorf("MustDecode() = %q, want %q", result, "Hello")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringConverterMustEncode(t *testing.T) {
|
||||
sc := &StringConverter{Encoding: japanese.ShiftJIS}
|
||||
|
||||
// Valid input should not panic
|
||||
result := sc.MustEncode("Hello")
|
||||
if !bytes.Equal(result, []byte("Hello")) {
|
||||
t.Errorf("MustEncode() = %v, want %v", result, []byte("Hello"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUTF8ToSJIS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want []byte
|
||||
}{
|
||||
{"empty", "", []byte{}},
|
||||
{"ascii", "ABC", []byte("ABC")},
|
||||
{"japanese", "こんにちは", []byte{0x82, 0xb1, 0x82, 0xf1, 0x82, 0xc9, 0x82, 0xbf, 0x82, 0xcd}},
|
||||
{"mixed", "Hello世界", []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x90, 0xa2, 0x8a, 0x45}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := UTF8ToSJIS(tt.input)
|
||||
if !bytes.Equal(got, tt.want) {
|
||||
t.Errorf("UTF8ToSJIS(%q) = %v, want %v", tt.input, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSJISToUTF8(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []byte
|
||||
want string
|
||||
}{
|
||||
{"empty", []byte{}, ""},
|
||||
{"ascii", []byte("ABC"), "ABC"},
|
||||
{"japanese", []byte{0x82, 0xb1, 0x82, 0xf1, 0x82, 0xc9, 0x82, 0xbf, 0x82, 0xcd}, "こんにちは"},
|
||||
{"mixed", []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x90, 0xa2, 0x8a, 0x45}, "Hello世界"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := SJISToUTF8(tt.input)
|
||||
if got != tt.want {
|
||||
t.Errorf("SJISToUTF8(%v) = %q, want %q", tt.input, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUTF8ToSJISRoundTrip(t *testing.T) {
|
||||
tests := []string{
|
||||
"Hello",
|
||||
"ABC123",
|
||||
"こんにちは",
|
||||
"テスト",
|
||||
"モンスターハンター",
|
||||
}
|
||||
|
||||
for _, input := range tests {
|
||||
t.Run(input, func(t *testing.T) {
|
||||
encoded := UTF8ToSJIS(input)
|
||||
decoded := SJISToUTF8(encoded)
|
||||
if decoded != input {
|
||||
t.Errorf("Round trip failed: %q -> %v -> %q", input, encoded, decoded)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPaddedString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
size uint
|
||||
transform bool
|
||||
wantLen int
|
||||
wantEnd byte
|
||||
}{
|
||||
{"empty ascii", "", 10, false, 10, 0},
|
||||
{"short ascii", "Hi", 10, false, 10, 0},
|
||||
{"exact ascii", "1234567890", 10, false, 10, 0},
|
||||
{"empty sjis", "", 10, true, 10, 0},
|
||||
{"short sjis", "Hi", 10, true, 10, 0},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := PaddedString(tt.input, tt.size, tt.transform)
|
||||
if len(got) != tt.wantLen {
|
||||
t.Errorf("PaddedString() len = %d, want %d", len(got), tt.wantLen)
|
||||
}
|
||||
if got[len(got)-1] != tt.wantEnd {
|
||||
t.Errorf("PaddedString() last byte = %d, want %d", got[len(got)-1], tt.wantEnd)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPaddedStringContent(t *testing.T) {
|
||||
// Verify the content is correctly placed at the beginning
|
||||
result := PaddedString("ABC", 10, false)
|
||||
|
||||
if result[0] != 'A' || result[1] != 'B' || result[2] != 'C' {
|
||||
t.Errorf("PaddedString() content mismatch: got %v", result[:3])
|
||||
}
|
||||
|
||||
// Rest should be zeros (except last which is forced to 0)
|
||||
for i := 3; i < 10; i++ {
|
||||
if result[i] != 0 {
|
||||
t.Errorf("PaddedString() byte at %d = %d, want 0", i, result[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSVAdd(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
csv string
|
||||
v int
|
||||
want string
|
||||
}{
|
||||
{"empty add", "", 5, "5"},
|
||||
{"add to existing", "1,2,3", 4, "1,2,3,4"},
|
||||
{"add duplicate", "1,2,3", 2, "1,2,3"},
|
||||
{"add to single", "1", 2, "1,2"},
|
||||
{"add zero", "", 0, "0"},
|
||||
{"add negative", "1,2", -5, "1,2,-5"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := CSVAdd(tt.csv, tt.v)
|
||||
if got != tt.want {
|
||||
t.Errorf("CSVAdd(%q, %d) = %q, want %q", tt.csv, tt.v, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSVRemove(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
csv string
|
||||
v int
|
||||
want string
|
||||
}{
|
||||
{"remove from middle", "1,2,3", 2, "1,3"},
|
||||
{"remove first", "1,2,3", 1, "3,2"},
|
||||
{"remove last", "1,2,3", 3, "1,2"},
|
||||
{"remove only", "5", 5, ""},
|
||||
{"remove nonexistent", "1,2,3", 99, "1,2,3"},
|
||||
{"remove from empty", "", 5, ""},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := CSVRemove(tt.csv, tt.v)
|
||||
if got != tt.want {
|
||||
t.Errorf("CSVRemove(%q, %d) = %q, want %q", tt.csv, tt.v, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSVContains(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
csv string
|
||||
v int
|
||||
want bool
|
||||
}{
|
||||
{"contains first", "1,2,3", 1, true},
|
||||
{"contains middle", "1,2,3", 2, true},
|
||||
{"contains last", "1,2,3", 3, true},
|
||||
{"not contains", "1,2,3", 99, false},
|
||||
{"empty csv", "", 5, false},
|
||||
{"single contains", "5", 5, true},
|
||||
{"single not contains", "5", 3, false},
|
||||
{"contains zero", "0,1,2", 0, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := CSVContains(tt.csv, tt.v)
|
||||
if got != tt.want {
|
||||
t.Errorf("CSVContains(%q, %d) = %v, want %v", tt.csv, tt.v, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSVLength(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
csv string
|
||||
want int
|
||||
}{
|
||||
{"empty", "", 0},
|
||||
{"single", "5", 1},
|
||||
{"two", "1,2", 2},
|
||||
{"three", "1,2,3", 3},
|
||||
{"many", "1,2,3,4,5,6,7,8,9,10", 10},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := CSVLength(tt.csv)
|
||||
if got != tt.want {
|
||||
t.Errorf("CSVLength(%q) = %d, want %d", tt.csv, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSVElems(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
csv string
|
||||
want []int
|
||||
}{
|
||||
{"empty", "", nil},
|
||||
{"single", "5", []int{5}},
|
||||
{"multiple", "1,2,3", []int{1, 2, 3}},
|
||||
{"with zero", "0,1,2", []int{0, 1, 2}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := CSVElems(tt.csv)
|
||||
if len(got) != len(tt.want) {
|
||||
t.Errorf("CSVElems(%q) len = %d, want %d", tt.csv, len(got), len(tt.want))
|
||||
return
|
||||
}
|
||||
for i := range got {
|
||||
if got[i] != tt.want[i] {
|
||||
t.Errorf("CSVElems(%q)[%d] = %d, want %d", tt.csv, i, got[i], tt.want[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSVAddRemoveRoundTrip(t *testing.T) {
|
||||
csv := ""
|
||||
csv = CSVAdd(csv, 1)
|
||||
csv = CSVAdd(csv, 2)
|
||||
csv = CSVAdd(csv, 3)
|
||||
|
||||
if !CSVContains(csv, 1) || !CSVContains(csv, 2) || !CSVContains(csv, 3) {
|
||||
t.Error("CSVAdd did not add all elements")
|
||||
}
|
||||
|
||||
csv = CSVRemove(csv, 2)
|
||||
if CSVContains(csv, 2) {
|
||||
t.Error("CSVRemove did not remove element")
|
||||
}
|
||||
if CSVLength(csv) != 2 {
|
||||
t.Errorf("CSVLength after remove = %d, want 2", CSVLength(csv))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user