using System.Collections.Generic; using AcDream.App; namespace AcDream.App.Tests; /// /// Unit tests for startup-time parsing. /// Behavior-preservation only: every assertion locks in the exact /// boolean / numeric / nullability semantics from the env reads that /// previously lived in GameWindow.cs. /// public sealed class RuntimeOptionsTests { private const string AnyDatDir = "C:/Users/test/dats"; private static Func Env(Dictionary values) => name => values.TryGetValue(name, out var v) ? v : null; private static Func EmptyEnv() => _ => null; [Fact] public void Defaults_AllSafeOff_WhenEnvironmentIsEmpty() { var opts = RuntimeOptions.Parse(AnyDatDir, EmptyEnv()); Assert.Equal(AnyDatDir, opts.DatDir); Assert.False(opts.LiveMode); Assert.Equal("127.0.0.1", opts.LiveHost); Assert.Equal(9000, opts.LivePort); Assert.Null(opts.LiveUser); Assert.Null(opts.LivePass); Assert.False(opts.DevTools); Assert.False(opts.DumpMoveTruth); Assert.False(opts.NoAudio); Assert.False(opts.EnableSkyPesDebug); Assert.Equal(-1, opts.HidePartIndex); // Default-on: RetailCloseDegrades is true unless explicitly disabled. Assert.True(opts.RetailCloseDegrades); Assert.False(opts.DumpSceneryZ); Assert.Null(opts.LegacyStreamRadius); Assert.False(opts.HasLiveCredentials); } [Fact] public void LiveMode_Set_ExactlyByValue1() { Assert.True(RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_LIVE"] = "1" })).LiveMode); Assert.False(RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_LIVE"] = "0" })).LiveMode); Assert.False(RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_LIVE"] = "true" })).LiveMode); Assert.False(RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_LIVE"] = "" })).LiveMode); } [Fact] public void LiveHostAndPort_FallBackToDefaults_WhenUnsetOrInvalid() { var withDefaults = RuntimeOptions.Parse(AnyDatDir, EmptyEnv()); Assert.Equal("127.0.0.1", withDefaults.LiveHost); Assert.Equal(9000, withDefaults.LivePort); var withOverrides = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_TEST_HOST"] = "play.example.com", ["ACDREAM_TEST_PORT"] = "9123", })); Assert.Equal("play.example.com", withOverrides.LiveHost); Assert.Equal(9123, withOverrides.LivePort); // Non-numeric port falls back to default; we don't throw at parse time. var withBadPort = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_TEST_PORT"] = "abc" })); Assert.Equal(9000, withBadPort.LivePort); } [Fact] public void LiveUserPass_NullWhenEmptyOrUnset() { var emptyValues = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_TEST_USER"] = "", ["ACDREAM_TEST_PASS"] = "", })); Assert.Null(emptyValues.LiveUser); Assert.Null(emptyValues.LivePass); var realValues = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_TEST_USER"] = "testaccount", ["ACDREAM_TEST_PASS"] = "testpassword", })); Assert.Equal("testaccount", realValues.LiveUser); Assert.Equal("testpassword", realValues.LivePass); } [Fact] public void HasLiveCredentials_RequiresLiveModeAndBothUserAndPass() { // Live mode off → no credentials regardless of user/pass. var noLive = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_TEST_USER"] = "u", ["ACDREAM_TEST_PASS"] = "p", })); Assert.False(noLive.HasLiveCredentials); // Live mode on but missing user → no credentials. var missingUser = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_LIVE"] = "1", ["ACDREAM_TEST_PASS"] = "p", })); Assert.False(missingUser.HasLiveCredentials); // Live mode on but missing pass → no credentials. var missingPass = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_LIVE"] = "1", ["ACDREAM_TEST_USER"] = "u", })); Assert.False(missingPass.HasLiveCredentials); // All three present → credentials available. var ok = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_LIVE"] = "1", ["ACDREAM_TEST_USER"] = "u", ["ACDREAM_TEST_PASS"] = "p", })); Assert.True(ok.HasLiveCredentials); } [Fact] public void HidePartIndex_MinusOneWhenUnset_ParsesIntegers() { Assert.Equal(-1, RuntimeOptions.Parse(AnyDatDir, EmptyEnv()).HidePartIndex); Assert.Equal(7, RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_HIDE_PART"] = "7" })).HidePartIndex); // Invalid → fall back to -1 (preserves the int.TryParse failure semantics). Assert.Equal(-1, RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_HIDE_PART"] = "abc" })).HidePartIndex); } [Fact] public void RetailCloseDegrades_DefaultOn_ExceptWhenValueIsExactlyZero() { // Unset → on. Assert.True(RuntimeOptions.Parse(AnyDatDir, EmptyEnv()).RetailCloseDegrades); // Exactly "0" → off. Matches the pre-refactor semantics: // !string.Equals(env, "0", StringComparison.Ordinal) Assert.False(RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_RETAIL_CLOSE_DEGRADES"] = "0", })).RetailCloseDegrades); // Any other value → on (including "1", "false", "True"). The original // code only checked for the literal "0"; preserve that. Assert.True(RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_RETAIL_CLOSE_DEGRADES"] = "1", })).RetailCloseDegrades); Assert.True(RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_RETAIL_CLOSE_DEGRADES"] = "false", })).RetailCloseDegrades); } [Fact] public void LegacyStreamRadius_NullWhenUnsetOrInvalid_ParsesNonNegativeIntegers() { Assert.Null(RuntimeOptions.Parse(AnyDatDir, EmptyEnv()).LegacyStreamRadius); Assert.Null(RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_STREAM_RADIUS"] = "abc" })).LegacyStreamRadius); // Negative values are filtered out by the pre-refactor `sr >= 0` guard. Assert.Null(RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_STREAM_RADIUS"] = "-3" })).LegacyStreamRadius); Assert.Equal(0, RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_STREAM_RADIUS"] = "0" })).LegacyStreamRadius); Assert.Equal(5, RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_STREAM_RADIUS"] = "5" })).LegacyStreamRadius); Assert.Equal(12, RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_STREAM_RADIUS"] = "12" })).LegacyStreamRadius); } [Fact] public void DiagnosticFlags_RespectExactValueOne() { var allOn = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_DEVTOOLS"] = "1", ["ACDREAM_DUMP_MOVE_TRUTH"] = "1", ["ACDREAM_NO_AUDIO"] = "1", ["ACDREAM_ENABLE_SKY_PES"] = "1", ["ACDREAM_DUMP_SCENERY_Z"] = "1", })); Assert.True(allOn.DevTools); Assert.True(allOn.DumpMoveTruth); Assert.True(allOn.NoAudio); Assert.True(allOn.EnableSkyPesDebug); Assert.True(allOn.DumpSceneryZ); // Any non-"1" value leaves them off, matching the // string.Equals(env, "1", StringComparison.Ordinal) check. var anyOther = RuntimeOptions.Parse(AnyDatDir, Env(new() { ["ACDREAM_DEVTOOLS"] = "true", ["ACDREAM_DUMP_MOVE_TRUTH"] = "yes", ["ACDREAM_NO_AUDIO"] = "2", ["ACDREAM_ENABLE_SKY_PES"] = "on", ["ACDREAM_DUMP_SCENERY_Z"] = " 1", })); Assert.False(anyOther.DevTools); Assert.False(anyOther.DumpMoveTruth); Assert.False(anyOther.NoAudio); Assert.False(anyOther.EnableSkyPesDebug); Assert.False(anyOther.DumpSceneryZ); } [Fact] public void Parse_RejectsNullDatDirOrEnv() { Assert.Throws(() => RuntimeOptions.Parse(null!, EmptyEnv())); Assert.Throws(() => RuntimeOptions.Parse(AnyDatDir, null!)); } }