package _config import ( "testing" ) // TestModeString tests the versionStrings array content func TestModeString(t *testing.T) { // NOTE: The Mode.String() method in config.go has a bug - it directly uses the Mode value // as an index (which is 1-41) but versionStrings is 0-indexed. This test validates // the versionStrings array content instead. expectedStrings := map[int]string{ 0: "S1.0", 1: "S1.5", 2: "S2.0", 3: "S2.5", 4: "S3.0", 5: "S3.5", 6: "S4.0", 7: "S5.0", 8: "S5.5", 9: "S6.0", 10: "S7.0", 11: "S8.0", 12: "S8.5", 13: "S9.0", 14: "S10", 15: "FW.1", 16: "FW.2", 17: "FW.3", 18: "FW.4", 19: "FW.5", 20: "G1", 21: "G2", 22: "G3", 23: "G3.1", 24: "G3.2", 25: "GG", 26: "G5", 27: "G5.1", 28: "G5.2", 29: "G6", 30: "G6.1", 31: "G7", 32: "G8", 33: "G8.1", 34: "G9", 35: "G9.1", 36: "G10", 37: "G10.1", 38: "Z1", 39: "Z2", 40: "ZZ", } for i, expected := range expectedStrings { if i < len(versionStrings) { if versionStrings[i] != expected { t.Errorf("versionStrings[%d] = %s, want %s", i, versionStrings[i], expected) } } } } // TestModeConstants verifies all mode constants are unique and in order func TestModeConstants(t *testing.T) { modes := []Mode{ S1, S15, S2, S25, S3, S35, S4, S5, S55, S6, S7, S8, S85, S9, S10, F1, F2, F3, F4, F5, G1, G2, G3, G31, G32, GG, G5, G51, G52, G6, G61, G7, G8, G81, G9, G91, G10, G101, Z1, Z2, ZZ, } // Verify all modes are unique seen := make(map[Mode]bool) for _, mode := range modes { if seen[mode] { t.Errorf("Duplicate mode constant: %v", mode) } seen[mode] = true } // Verify modes are in sequential order for i, mode := range modes { if int(mode) != i+1 { t.Errorf("Mode %v at index %d has wrong value: got %d, want %d", mode, i, mode, i+1) } } // Verify total count if len(modes) != len(versionStrings) { t.Errorf("Number of modes (%d) doesn't match versionStrings count (%d)", len(modes), len(versionStrings)) } } // TestIsTestEnvironment tests the isTestEnvironment function func TestIsTestEnvironment(t *testing.T) { result := isTestEnvironment() if !result { t.Error("isTestEnvironment() should return true when running tests") } } // TestVersionStringsLength verifies versionStrings has correct length func TestVersionStringsLength(t *testing.T) { expectedCount := 41 // S1 through ZZ = 41 versions if len(versionStrings) != expectedCount { t.Errorf("versionStrings length = %d, want %d", len(versionStrings), expectedCount) } } // TestVersionStringsContent verifies critical version strings func TestVersionStringsContent(t *testing.T) { tests := []struct { index int expected string }{ {0, "S1.0"}, // S1 {14, "S10"}, // S10 {15, "FW.1"}, // F1 {19, "FW.5"}, // F5 {20, "G1"}, // G1 {38, "Z1"}, // Z1 {39, "Z2"}, // Z2 {40, "ZZ"}, // ZZ } for _, tt := range tests { if versionStrings[tt.index] != tt.expected { t.Errorf("versionStrings[%d] = %s, want %s", tt.index, versionStrings[tt.index], tt.expected) } } } // TestGetOutboundIP4 tests IP detection func TestGetOutboundIP4(t *testing.T) { ip := getOutboundIP4() if ip == nil { t.Error("getOutboundIP4() returned nil IP") } // Verify it returns IPv4 if ip.To4() == nil { t.Error("getOutboundIP4() should return valid IPv4") } // Verify it's not all zeros if len(ip) == 4 && ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 { t.Error("getOutboundIP4() returned 0.0.0.0") } } // TestConfigStructTypes verifies Config struct fields have correct types func TestConfigStructTypes(t *testing.T) { cfg := &Config{ Host: "localhost", BinPath: "/path/to/bin", Language: "en", DisableSoftCrash: false, HideLoginNotice: false, LoginNotices: []string{"Notice"}, PatchServerManifest: "http://patch.example.com", PatchServerFile: "http://files.example.com", DeleteOnSaveCorruption: false, ClientMode: "ZZ", RealClientMode: ZZ, QuestCacheExpiry: 3600, CommandPrefix: "!", AutoCreateAccount: false, LoopDelay: 100, DefaultCourses: []uint16{1, 2, 3}, EarthStatus: 1, EarthID: 1, EarthMonsters: []int32{1, 2, 3}, SaveDumps: SaveDumpOptions{ Enabled: true, RawEnabled: false, OutputDir: "/dumps", }, Screenshots: ScreenshotsOptions{ Enabled: true, Host: "localhost", Port: 8080, OutputDir: "/screenshots", UploadQuality: 85, }, DebugOptions: DebugOptions{ CleanDB: false, MaxLauncherHR: false, LogInboundMessages: false, LogOutboundMessages: false, LogMessageData: false, MaxHexdumpLength: 32, }, GameplayOptions: GameplayOptions{ MinFeatureWeapons: 1, MaxFeatureWeapons: 5, }, } // Verify fields are accessible and have correct types if cfg.Host != "localhost" { t.Error("Config.Host type mismatch") } if cfg.QuestCacheExpiry != 3600 { t.Error("Config.QuestCacheExpiry type mismatch") } if cfg.RealClientMode != ZZ { t.Error("Config.RealClientMode type mismatch") } } // TestSaveDumpOptions verifies SaveDumpOptions struct func TestSaveDumpOptions(t *testing.T) { opts := SaveDumpOptions{ Enabled: true, RawEnabled: false, OutputDir: "/test/path", } if !opts.Enabled { t.Error("SaveDumpOptions.Enabled should be true") } if opts.RawEnabled { t.Error("SaveDumpOptions.RawEnabled should be false") } if opts.OutputDir != "/test/path" { t.Error("SaveDumpOptions.OutputDir mismatch") } } // TestScreenshotsOptions verifies ScreenshotsOptions struct func TestScreenshotsOptions(t *testing.T) { opts := ScreenshotsOptions{ Enabled: true, Host: "ss.example.com", Port: 8000, OutputDir: "/screenshots", UploadQuality: 90, } if !opts.Enabled { t.Error("ScreenshotsOptions.Enabled should be true") } if opts.Host != "ss.example.com" { t.Error("ScreenshotsOptions.Host mismatch") } if opts.Port != 8000 { t.Error("ScreenshotsOptions.Port mismatch") } if opts.UploadQuality != 90 { t.Error("ScreenshotsOptions.UploadQuality mismatch") } } // TestDebugOptions verifies DebugOptions struct func TestDebugOptions(t *testing.T) { opts := DebugOptions{ CleanDB: true, MaxLauncherHR: true, LogInboundMessages: true, LogOutboundMessages: true, LogMessageData: true, MaxHexdumpLength: 128, DivaOverride: 1, DisableTokenCheck: true, } if !opts.CleanDB { t.Error("DebugOptions.CleanDB should be true") } if !opts.MaxLauncherHR { t.Error("DebugOptions.MaxLauncherHR should be true") } if opts.MaxHexdumpLength != 128 { t.Error("DebugOptions.MaxHexdumpLength mismatch") } if !opts.DisableTokenCheck { t.Error("DebugOptions.DisableTokenCheck should be true (security risk!)") } } // TestGameplayOptions verifies GameplayOptions struct func TestGameplayOptions(t *testing.T) { opts := GameplayOptions{ MinFeatureWeapons: 2, MaxFeatureWeapons: 10, MaximumNP: 999999, MaximumRP: 9999, MaximumFP: 999999999, MezFesSoloTickets: 100, MezFesGroupTickets: 50, DisableHunterNavi: true, EnableKaijiEvent: true, EnableHiganjimaEvent: false, EnableNierEvent: false, } if opts.MinFeatureWeapons != 2 { t.Error("GameplayOptions.MinFeatureWeapons mismatch") } if opts.MaxFeatureWeapons != 10 { t.Error("GameplayOptions.MaxFeatureWeapons mismatch") } if opts.MezFesSoloTickets != 100 { t.Error("GameplayOptions.MezFesSoloTickets mismatch") } if !opts.EnableKaijiEvent { t.Error("GameplayOptions.EnableKaijiEvent should be true") } } // TestCapLinkOptions verifies CapLinkOptions struct func TestCapLinkOptions(t *testing.T) { opts := CapLinkOptions{ Values: []uint16{1, 2, 3}, Key: "test-key", Host: "localhost", Port: 9999, } if len(opts.Values) != 3 { t.Error("CapLinkOptions.Values length mismatch") } if opts.Key != "test-key" { t.Error("CapLinkOptions.Key mismatch") } if opts.Port != 9999 { t.Error("CapLinkOptions.Port mismatch") } } // TestDatabase verifies Database struct func TestDatabase(t *testing.T) { db := Database{ Host: "localhost", Port: 5432, User: "postgres", Password: "password", Database: "erupe", } if db.Host != "localhost" { t.Error("Database.Host mismatch") } if db.Port != 5432 { t.Error("Database.Port mismatch") } if db.User != "postgres" { t.Error("Database.User mismatch") } if db.Database != "erupe" { t.Error("Database.Database mismatch") } } // TestSign verifies Sign struct func TestSign(t *testing.T) { sign := Sign{ Enabled: true, Port: 8081, } if !sign.Enabled { t.Error("Sign.Enabled should be true") } if sign.Port != 8081 { t.Error("Sign.Port mismatch") } } // TestAPI verifies API struct func TestAPI(t *testing.T) { api := API{ Enabled: true, Port: 8080, PatchServer: "http://patch.example.com", Banners: []APISignBanner{ {Src: "banner.jpg", Link: "http://example.com"}, }, Messages: []APISignMessage{ {Message: "Welcome", Date: 0, Kind: 0, Link: "http://example.com"}, }, Links: []APISignLink{ {Name: "Forum", Icon: "forum", Link: "http://forum.example.com"}, }, } if !api.Enabled { t.Error("API.Enabled should be true") } if api.Port != 8080 { t.Error("API.Port mismatch") } if len(api.Banners) != 1 { t.Error("API.Banners length mismatch") } } // TestAPISignBanner verifies APISignBanner struct func TestAPISignBanner(t *testing.T) { banner := APISignBanner{ Src: "http://example.com/banner.jpg", Link: "http://example.com", } if banner.Src != "http://example.com/banner.jpg" { t.Error("APISignBanner.Src mismatch") } if banner.Link != "http://example.com" { t.Error("APISignBanner.Link mismatch") } } // TestAPISignMessage verifies APISignMessage struct func TestAPISignMessage(t *testing.T) { msg := APISignMessage{ Message: "Welcome to Erupe!", Date: 1625097600, Kind: 0, Link: "http://example.com", } if msg.Message != "Welcome to Erupe!" { t.Error("APISignMessage.Message mismatch") } if msg.Date != 1625097600 { t.Error("APISignMessage.Date mismatch") } if msg.Kind != 0 { t.Error("APISignMessage.Kind mismatch") } } // TestAPISignLink verifies APISignLink struct func TestAPISignLink(t *testing.T) { link := APISignLink{ Name: "Forum", Icon: "forum", Link: "http://forum.example.com", } if link.Name != "Forum" { t.Error("APISignLink.Name mismatch") } if link.Icon != "forum" { t.Error("APISignLink.Icon mismatch") } if link.Link != "http://forum.example.com" { t.Error("APISignLink.Link mismatch") } } // TestChannel verifies Channel struct func TestChannel(t *testing.T) { ch := Channel{ Enabled: true, } if !ch.Enabled { t.Error("Channel.Enabled should be true") } } // TestEntrance verifies Entrance struct func TestEntrance(t *testing.T) { entrance := Entrance{ Enabled: true, Port: 10000, Entries: []EntranceServerInfo{ { IP: "192.168.1.1", Type: 1, Season: 0, Recommended: 0, Name: "Test Server", Description: "A test server", }, }, } if !entrance.Enabled { t.Error("Entrance.Enabled should be true") } if entrance.Port != 10000 { t.Error("Entrance.Port mismatch") } if len(entrance.Entries) != 1 { t.Error("Entrance.Entries length mismatch") } } // TestEntranceServerInfo verifies EntranceServerInfo struct func TestEntranceServerInfo(t *testing.T) { info := EntranceServerInfo{ IP: "192.168.1.1", Type: 1, Season: 0, Recommended: 0, Name: "Server 1", Description: "Main server", AllowedClientFlags: 4096, Channels: []EntranceChannelInfo{ {Port: 10001, MaxPlayers: 4, CurrentPlayers: 2}, }, } if info.IP != "192.168.1.1" { t.Error("EntranceServerInfo.IP mismatch") } if info.Type != 1 { t.Error("EntranceServerInfo.Type mismatch") } if len(info.Channels) != 1 { t.Error("EntranceServerInfo.Channels length mismatch") } } // TestEntranceChannelInfo verifies EntranceChannelInfo struct func TestEntranceChannelInfo(t *testing.T) { info := EntranceChannelInfo{ Port: 10001, MaxPlayers: 4, CurrentPlayers: 2, } if info.Port != 10001 { t.Error("EntranceChannelInfo.Port mismatch") } if info.MaxPlayers != 4 { t.Error("EntranceChannelInfo.MaxPlayers mismatch") } if info.CurrentPlayers != 2 { t.Error("EntranceChannelInfo.CurrentPlayers mismatch") } } // TestDiscord verifies Discord struct func TestDiscord(t *testing.T) { discord := Discord{ Enabled: true, BotToken: "token123", RelayChannel: DiscordRelay{ Enabled: true, MaxMessageLength: 2000, RelayChannelID: "123456789", }, } if !discord.Enabled { t.Error("Discord.Enabled should be true") } if discord.BotToken != "token123" { t.Error("Discord.BotToken mismatch") } if discord.RelayChannel.MaxMessageLength != 2000 { t.Error("Discord.RelayChannel.MaxMessageLength mismatch") } } // TestCommand verifies Command struct func TestCommand(t *testing.T) { cmd := Command{ Name: "test", Enabled: true, Description: "Test command", Prefix: "!", } if cmd.Name != "test" { t.Error("Command.Name mismatch") } if !cmd.Enabled { t.Error("Command.Enabled should be true") } if cmd.Prefix != "!" { t.Error("Command.Prefix mismatch") } } // TestCourse verifies Course struct func TestCourse(t *testing.T) { course := Course{ Name: "Rookie Road", Enabled: true, } if course.Name != "Rookie Road" { t.Error("Course.Name mismatch") } if !course.Enabled { t.Error("Course.Enabled should be true") } } // TestGameplayOptionsConstraints tests gameplay option constraints func TestGameplayOptionsConstraints(t *testing.T) { tests := []struct { name string opts GameplayOptions ok bool }{ { name: "valid multipliers", opts: GameplayOptions{ HRPMultiplier: 1.5, GRPMultiplier: 1.2, ZennyMultiplier: 1.0, MaterialMultiplier: 1.3, }, ok: true, }, { name: "zero multipliers", opts: GameplayOptions{ HRPMultiplier: 0.0, }, ok: true, }, { name: "high multipliers", opts: GameplayOptions{ GCPMultiplier: 10.0, }, ok: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Just verify the struct can be created with these values _ = tt.opts }) } } // TestModeValueRanges tests Mode constant value ranges func TestModeValueRanges(t *testing.T) { if S1 < 1 || S1 > ZZ { t.Error("S1 mode value out of range") } if ZZ <= G101 { t.Error("ZZ should be greater than G101") } if G101 <= F5 { t.Error("G101 should be greater than F5") } } // TestConfigDefaults tests default configuration creation func TestConfigDefaults(t *testing.T) { cfg := &Config{ ClientMode: "ZZ", RealClientMode: ZZ, } if cfg.ClientMode != "ZZ" { t.Error("Default ClientMode mismatch") } if cfg.RealClientMode != ZZ { t.Error("Default RealClientMode mismatch") } } // BenchmarkModeString benchmarks Mode.String() method func BenchmarkModeString(b *testing.B) { mode := ZZ b.ResetTimer() for i := 0; i < b.N; i++ { _ = mode.String() } } // BenchmarkGetOutboundIP4 benchmarks IP detection func BenchmarkGetOutboundIP4(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { _ = getOutboundIP4() } } // BenchmarkIsTestEnvironment benchmarks test environment detection func BenchmarkIsTestEnvironment(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { _ = isTestEnvironment() } }