mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
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.
289 lines
6.0 KiB
Go
289 lines
6.0 KiB
Go
package mhfcourse
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
)
|
|
|
|
func TestCourses(t *testing.T) {
|
|
courses := Courses()
|
|
|
|
if len(courses) != 32 {
|
|
t.Errorf("Courses() len = %d, want 32", len(courses))
|
|
}
|
|
|
|
for i, course := range courses {
|
|
if course.ID != uint16(i) {
|
|
t.Errorf("Courses()[%d].ID = %d, want %d", i, course.ID, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCourseValue(t *testing.T) {
|
|
tests := []struct {
|
|
id uint16
|
|
want uint32
|
|
}{
|
|
{0, 1},
|
|
{1, 2},
|
|
{2, 4},
|
|
{3, 8},
|
|
{4, 16},
|
|
{5, 32},
|
|
{10, 1024},
|
|
{20, 1048576},
|
|
{31, 2147483648},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run("", func(t *testing.T) {
|
|
c := Course{ID: tt.id}
|
|
got := c.Value()
|
|
if got != tt.want {
|
|
t.Errorf("Course{ID: %d}.Value() = %d, want %d", tt.id, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCourseValueIsPowerOf2(t *testing.T) {
|
|
for i := uint16(0); i < 32; i++ {
|
|
c := Course{ID: i}
|
|
val := c.Value()
|
|
expected := uint32(math.Pow(2, float64(i)))
|
|
if val != expected {
|
|
t.Errorf("Course{ID: %d}.Value() = %d, want %d (2^%d)", i, val, expected, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCourseAliases(t *testing.T) {
|
|
tests := []struct {
|
|
id uint16
|
|
wantLen int
|
|
contains string
|
|
}{
|
|
{1, 2, "Trial"},
|
|
{2, 2, "HunterLife"},
|
|
{3, 3, "Extra"},
|
|
{6, 1, "Premium"},
|
|
{8, 4, "Assist"},
|
|
{26, 4, "NetCafe"},
|
|
{29, 1, "Free"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run("", func(t *testing.T) {
|
|
c := Course{ID: tt.id}
|
|
aliases := c.Aliases()
|
|
|
|
if len(aliases) != tt.wantLen {
|
|
t.Errorf("Course{ID: %d}.Aliases() len = %d, want %d", tt.id, len(aliases), tt.wantLen)
|
|
}
|
|
|
|
found := false
|
|
for _, alias := range aliases {
|
|
if alias == tt.contains {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("Course{ID: %d}.Aliases() should contain %q", tt.id, tt.contains)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCourseAliasesUnknown(t *testing.T) {
|
|
// Test IDs without aliases
|
|
unknownIDs := []uint16{13, 14, 15, 16, 17, 18, 19}
|
|
|
|
for _, id := range unknownIDs {
|
|
c := Course{ID: id}
|
|
aliases := c.Aliases()
|
|
if aliases != nil {
|
|
t.Errorf("Course{ID: %d}.Aliases() = %v, want nil", id, aliases)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCourseExists(t *testing.T) {
|
|
courses := []Course{
|
|
{ID: 1},
|
|
{ID: 5},
|
|
{ID: 10},
|
|
}
|
|
|
|
tests := []struct {
|
|
id uint16
|
|
want bool
|
|
}{
|
|
{1, true},
|
|
{5, true},
|
|
{10, true},
|
|
{0, false},
|
|
{2, false},
|
|
{99, false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run("", func(t *testing.T) {
|
|
got := CourseExists(tt.id, courses)
|
|
if got != tt.want {
|
|
t.Errorf("CourseExists(%d, courses) = %v, want %v", tt.id, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCourseExistsEmptySlice(t *testing.T) {
|
|
var courses []Course
|
|
|
|
if CourseExists(1, courses) {
|
|
t.Error("CourseExists(1, nil) should return false")
|
|
}
|
|
}
|
|
|
|
func TestGetCourseStruct(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
rights uint32
|
|
wantMinLen int
|
|
shouldHave []uint16
|
|
shouldNotHave []uint16
|
|
}{
|
|
{
|
|
name: "zero rights",
|
|
rights: 0,
|
|
wantMinLen: 1, // Always includes ID: 1 (Trial)
|
|
shouldHave: []uint16{1},
|
|
},
|
|
{
|
|
name: "HunterLife course",
|
|
rights: 4, // 2^2 = 4 for ID 2
|
|
wantMinLen: 2,
|
|
shouldHave: []uint16{1, 2},
|
|
},
|
|
{
|
|
name: "multiple courses",
|
|
rights: 6, // 2^1 + 2^2 = 2 + 4 = 6 for IDs 1 and 2
|
|
wantMinLen: 2,
|
|
shouldHave: []uint16{1, 2},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
courses, _ := GetCourseStruct(tt.rights)
|
|
|
|
if len(courses) < tt.wantMinLen {
|
|
t.Errorf("GetCourseStruct(%d) len = %d, want >= %d", tt.rights, len(courses), tt.wantMinLen)
|
|
}
|
|
|
|
for _, id := range tt.shouldHave {
|
|
if !CourseExists(id, courses) {
|
|
t.Errorf("GetCourseStruct(%d) should have course ID %d", tt.rights, id)
|
|
}
|
|
}
|
|
|
|
for _, id := range tt.shouldNotHave {
|
|
if CourseExists(id, courses) {
|
|
t.Errorf("GetCourseStruct(%d) should not have course ID %d", tt.rights, id)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetCourseStructReturnsRights(t *testing.T) {
|
|
// GetCourseStruct returns the recalculated rights value
|
|
_, rights := GetCourseStruct(0)
|
|
|
|
// Should at least include the Trial course (ID: 1, Value: 2)
|
|
if rights < 2 {
|
|
t.Errorf("GetCourseStruct(0) rights = %d, want >= 2", rights)
|
|
}
|
|
}
|
|
|
|
func TestGetCourseStructNetCafeCourses(t *testing.T) {
|
|
// Test that course 26 (NetCafe) adds course 25 (CAFE_SP)
|
|
courses, _ := GetCourseStruct(Course{ID: 26}.Value())
|
|
|
|
if !CourseExists(25, courses) {
|
|
t.Error("GetCourseStruct with course 26 should add course 25")
|
|
}
|
|
if !CourseExists(30, courses) {
|
|
t.Error("GetCourseStruct with course 26 should add course 30")
|
|
}
|
|
}
|
|
|
|
func TestGetCourseStructNCourse(t *testing.T) {
|
|
// Test that course 9 (N) adds course 30
|
|
courses, _ := GetCourseStruct(Course{ID: 9}.Value())
|
|
|
|
if !CourseExists(30, courses) {
|
|
t.Error("GetCourseStruct with course 9 should add course 30")
|
|
}
|
|
}
|
|
|
|
func TestCourseExpiry(t *testing.T) {
|
|
// Test that courses returned by GetCourseStruct have expiry set
|
|
courses, _ := GetCourseStruct(4) // HunterLife
|
|
|
|
for _, c := range courses {
|
|
// Course ID 1 is always added without expiry in some cases
|
|
if c.ID != 1 && c.ID != 25 && c.ID != 30 {
|
|
if c.Expiry.IsZero() {
|
|
// Note: expiry is only set for courses extracted from rights
|
|
// This behavior is expected
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAllCoursesHaveValidValues(t *testing.T) {
|
|
courses := Courses()
|
|
|
|
for _, c := range courses {
|
|
val := c.Value()
|
|
// Verify value is a power of 2
|
|
if val == 0 || (val&(val-1)) != 0 {
|
|
t.Errorf("Course{ID: %d}.Value() = %d is not a power of 2", c.ID, val)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestKnownAliasesExist(t *testing.T) {
|
|
knownCourses := map[string]uint16{
|
|
"Trial": 1,
|
|
"HunterLife": 2,
|
|
"Extra": 3,
|
|
"Mobile": 5,
|
|
"Premium": 6,
|
|
"Assist": 8,
|
|
"Hiden": 10,
|
|
"NetCafe": 26,
|
|
"Free": 29,
|
|
}
|
|
|
|
for name, expectedID := range knownCourses {
|
|
t.Run(name, func(t *testing.T) {
|
|
c := Course{ID: expectedID}
|
|
aliases := c.Aliases()
|
|
|
|
found := false
|
|
for _, alias := range aliases {
|
|
if alias == name {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
t.Errorf("Course ID %d should have alias %q, got %v", expectedID, name, aliases)
|
|
}
|
|
})
|
|
}
|
|
}
|