using System.Text.Json; using HSchool.Server.Game; namespace HSchool.Server.Tests; public class SwarmUiSettingsStoreTests { [Fact] public void Resolve_UsesAgeRulePreset() { var config = SwarmUiConfigFile.CreateDefault(); var profile = config.Resolve(8, PortraitKind.Avatar); Assert.Equal("child", profile.PresetId); Assert.Equal(SwarmUiModelDefinition.RealismV25Id, profile.Model); Assert.Equal(8, profile.Steps); Assert.Equal(1, profile.CfgScale); Assert.Equal("euler", profile.Sampler); Assert.Equal("simple", profile.Scheduler); } [Fact] public void Resolve_FallsBackToActivePresetForAdults() { var config = SwarmUiConfigFile.CreateDefault(); var profile = config.Resolve(34, PortraitKind.Full); Assert.Equal("default", profile.PresetId); Assert.Equal(SwarmUiModelDefinition.RealismV25Id, profile.Model); Assert.Equal(8, profile.Steps); Assert.Equal(1, profile.CfgScale); Assert.Equal("euler", profile.Sampler); Assert.Equal("simple", profile.Scheduler); } [Fact] public void Resolve_WithoutOverride_TakesStepsAndCfgFromModel() { var config = new SwarmUiConfigFile { Models = [ new SwarmUiModelDefinition { Id = "m.safetensors", Steps = 9, CfgScale = 2.25 }, ], Presets = [ new SwarmUiPresetDefinition { Id = "default", Label = "Default", Model = "m.safetensors", Avatar = new SwarmUiKindPreset { Width = 512, Height = 512 }, Custom = new SwarmUiKindPreset { Width = 512, Height = 512 }, FullBody = new SwarmUiKindPreset { Width = 512, Height = 512 }, }, ], }; var profile = config.Resolve(20, PortraitKind.Avatar); Assert.Equal(9, profile.Steps); Assert.Equal(2.25, profile.CfgScale); } [Fact] public void ToProfile_JoinsModelAndPresetNegative() { var model = new SwarmUiModelDefinition { Id = "m.safetensors", Negative = "model-neg" }; var preset = new SwarmUiPresetDefinition { Id = "default", Label = "Default", Model = "m.safetensors", Negative = "preset-neg", Avatar = new SwarmUiKindPreset { Width = 512, Height = 512 }, }; var profile = preset.ToProfile(PortraitKind.Avatar, model); Assert.Equal("model-neg, preset-neg", profile.Negative); } [Fact] public void Resolve_PresetOverrideBeatsModelDefaults() { var config = SwarmUiConfigFile.CreateDefault(); var preset = config.Presets[0]; preset.Steps = 12; preset.CfgScale = 3.5; var profile = config.Resolve(34, PortraitKind.Avatar); Assert.Equal(12, profile.Steps); Assert.Equal(3.5, profile.CfgScale); Assert.Equal(0, profile.ClipSkip); } [Fact] public void NormalizeAfterLoad_MigratesLegacyFlatFile() { var config = new SwarmUiConfigFile { Model = "legacy.safetensors", Steps = 12, Positive = "legacy prompt", Avatar = new SwarmUiKindPreset { Width = 640, Height = 640, Positive = "close up." }, }; config.NormalizeAfterLoad(); Assert.Single(config.Presets); Assert.Equal("default", config.Presets[0].Id); Assert.Equal("legacy.safetensors", config.Presets[0].Model); Assert.Equal("legacy prompt", config.Presets[0].Style); Assert.Null(config.Presets[0].Positive); Assert.Null(config.Presets[0].Steps); var model = Assert.Single(config.Models, entry => entry.Id == "legacy.safetensors"); Assert.Equal(12, model.Steps); Assert.Equal("close up.", config.Presets[0].Avatar!.ShotType); Assert.Null(config.Presets[0].Avatar!.Positive); } [Fact] public void NormalizeAfterLoad_LiftsLegacyPresetPositiveIntoStyleAndShotType() { var config = new SwarmUiConfigFile { Presets = [ new SwarmUiPresetDefinition { Id = "default", Label = "Default", Model = "a.safetensors", Steps = 6, CfgScale = 2, Positive = "was base prompt", Negative = "old neg", Avatar = new SwarmUiKindPreset { Width = 512, Height = 512, Positive = "was kind" }, Custom = new SwarmUiKindPreset { Width = 512, Height = 512 }, FullBody = new SwarmUiKindPreset { Width = 512, Height = 768 }, }, ], }; config.NormalizeAfterLoad(); Assert.Equal("was base prompt", config.Presets[0].Style); Assert.Equal("was kind", config.Presets[0].Avatar!.ShotType); Assert.Contains(config.Models, model => model.Id == "a.safetensors"); Assert.Equal("", Assert.Single(config.Models).Positive); } [Fact] public void AllowedModelIds_IntersectsSwarmWithCatalog() { var config = SwarmUiConfigFile.CreateDefault(); var discovery = new SwarmUiDiscovery( true, [ SwarmUiModelDefinition.BabesId, SwarmUiModelDefinition.MuseId, "not-in-config.safetensors", ], [], [], [], []); var allowed = config.AllowedModelIds(discovery); Assert.Equal([SwarmUiModelDefinition.MuseId], allowed); Assert.DoesNotContain("not-in-config.safetensors", allowed); Assert.DoesNotContain(SwarmUiModelDefinition.BabesId, allowed); Assert.DoesNotContain(SwarmUiModelDefinition.DreamShaperId, allowed); } [Fact] public void AllowedModelIds_WhenSwarmOffline_ReturnsCatalog() { var config = SwarmUiConfigFile.CreateDefault(); var allowed = config.AllowedModelIds(SwarmUiDiscovery.Offline); Assert.Equal(config.Models.Select(model => model.Id), allowed); } [Fact] public void Clone_IsIndependentOfTheSource() { var source = SwarmUiConfigFile.CreateDefault(); source.Presets[0].Model = "mutated.safetensors"; source.Models[0].Id = "mutated.safetensors"; var copy = SwarmUiConfigFile.Clone(source); copy.Presets[0].Model = "other.safetensors"; Assert.Equal("mutated.safetensors", source.Presets[0].Model); Assert.Equal("other.safetensors", copy.Presets[0].Model); Assert.Equal(source.ActivePresetId, copy.ActivePresetId); } [Fact] public void CreateDefault_SeedsCatalogModels() { var config = SwarmUiConfigFile.CreateDefault(); var ids = config.Models.Select(model => model.Id).ToList(); Assert.Equal( [SwarmUiModelDefinition.MuseId, SwarmUiModelDefinition.RealismV25Id], ids); Assert.DoesNotContain(SwarmUiModelDefinition.BabesId, ids); Assert.DoesNotContain(SwarmUiModelDefinition.DreamShaperId, ids); Assert.DoesNotContain(SwarmUiModelDefinition.EpicRealismId, ids); Assert.DoesNotContain(SwarmUiModelDefinition.LustifyId, ids); Assert.DoesNotContain("realismByStableYogi_v20TurboGGUF.gguf", ids); var realism = Assert.Single(config.Models, model => model.Id == SwarmUiModelDefinition.RealismV25Id); Assert.Equal(8, realism.Steps); Assert.Equal(1, realism.CfgScale); Assert.Equal("euler", realism.Sampler); Assert.Equal("simple", realism.Scheduler); var muse = Assert.Single(config.Models, model => model.Id == SwarmUiModelDefinition.MuseId); Assert.Equal(8, muse.Steps); Assert.Equal(1, muse.CfgScale); Assert.Equal("euler", muse.Sampler); Assert.Equal("simple", muse.Scheduler); var adult = Assert.Single(config.Presets, preset => preset.Id == "default"); Assert.Equal(SwarmUiModelDefinition.RealismV25Id, adult.Model); Assert.DoesNotContain(":1.4)", adult.Negative, StringComparison.Ordinal); Assert.Contains("photograph", adult.Style, StringComparison.OrdinalIgnoreCase); var child = Assert.Single(config.Presets, preset => preset.Id == "child"); Assert.Equal(SwarmUiModelDefinition.RealismV25Id, child.Model); var ageRule = Assert.Single(config.AgeRules); Assert.Equal(6, ageRule.MinAge); Assert.Equal(11, ageRule.MaxAge); Assert.Equal("child", ageRule.PresetId); } [Theory] [InlineData(6, "child")] [InlineData(11, "child")] [InlineData(5, "default")] [InlineData(12, "default")] public void Resolve_AgeRuleCoversSixThroughElevenInclusive(int age, string presetId) { var config = SwarmUiConfigFile.CreateDefault(); var profile = config.Resolve(age, PortraitKind.Avatar); Assert.Equal(presetId, profile.PresetId); Assert.Equal(SwarmUiModelDefinition.RealismV25Id, profile.Model); } [Fact] public void CreateChild_StyleAndNegativeAreProseWithoutSdWeights() { var child = SwarmUiPresetDefinition.CreateChild(); Assert.NotNull(child.Avatar); Assert.NotNull(child.FullBody); Assert.DoesNotContain("(low quality", child.Style, StringComparison.Ordinal); Assert.DoesNotContain(":1.4)", child.Style, StringComparison.Ordinal); Assert.DoesNotContain("(low quality", child.Negative, StringComparison.Ordinal); Assert.DoesNotContain(":1.4)", child.Negative, StringComparison.Ordinal); Assert.DoesNotContain("(low quality", child.Avatar.ShotType, StringComparison.Ordinal); Assert.DoesNotContain(":1.4)", child.Avatar.ShotType, StringComparison.Ordinal); Assert.DoesNotContain("(low quality", child.FullBody.ShotType, StringComparison.Ordinal); Assert.DoesNotContain(":1.4)", child.FullBody.ShotType, StringComparison.Ordinal); } [Fact] public void SwarmUiJson_MatchesCatalogAndDefaultPresets() { var path = Path.Combine(RepoRoot(), "src", "HSchool.Server", "swarmui.json"); Assert.True(File.Exists(path), path); var loaded = JsonSerializer.Deserialize(File.ReadAllText(path), JsonOptions); if (loaded is null) { Assert.Fail("swarmui.json did not deserialize."); return; } loaded.NormalizeAfterLoad(); var expected = SwarmUiConfigFile.CreateDefault(); Assert.Equal(expected.Models.Select(model => model.Id), loaded.Models.Select(model => model.Id)); Assert.DoesNotContain(loaded.Models, model => model.Id.Contains("v20Turbo", StringComparison.OrdinalIgnoreCase)); for (var i = 0; i < expected.Models.Count; i++) { Assert.Equal(expected.Models[i].Label, loaded.Models[i].Label); Assert.Equal(expected.Models[i].Steps, loaded.Models[i].Steps); Assert.Equal(expected.Models[i].CfgScale, loaded.Models[i].CfgScale); Assert.Equal(expected.Models[i].Sampler, loaded.Models[i].Sampler); Assert.Equal(expected.Models[i].Scheduler, loaded.Models[i].Scheduler); Assert.Equal(expected.Models[i].Seed, loaded.Models[i].Seed); } Assert.Equal(expected.Presets.Select(preset => preset.Id), loaded.Presets.Select(preset => preset.Id)); Assert.Equal(expected.Presets[0].Model, loaded.Presets[0].Model); Assert.Equal(expected.Presets[0].Style, loaded.Presets[0].Style); Assert.Equal(expected.Presets[0].Negative, loaded.Presets[0].Negative); Assert.Equal(expected.Presets[0].Avatar?.ShotType, loaded.Presets[0].Avatar?.ShotType); Assert.Equal(expected.Presets[1].Model, loaded.Presets[1].Model); Assert.Equal(expected.Presets[1].Style, loaded.Presets[1].Style); Assert.Equal(expected.Presets[1].Negative, loaded.Presets[1].Negative); Assert.Equal(expected.Presets[1].Avatar?.ShotType, loaded.Presets[1].Avatar?.ShotType); Assert.Equal(expected.Presets[1].FullBody?.ShotType, loaded.Presets[1].FullBody?.ShotType); } [Fact] public void NormalizeAfterLoad_DoesNotRewriteExistingSdxlCatalog() { var living = new SwarmUiConfigFile { ActivePresetId = "default", Models = [ new SwarmUiModelDefinition { Id = SwarmUiModelDefinition.BabesId, Label = "babes", Steps = 7, CfgScale = 1.5, Sampler = "euler", Scheduler = "normal", }, new SwarmUiModelDefinition { Id = SwarmUiModelDefinition.DreamShaperId, Label = "DreamShaper", Steps = 4, CfgScale = 2, Sampler = "dpmpp_sde", Scheduler = "karras", }, ], Presets = [ new SwarmUiPresetDefinition { Id = "default", Label = "Default", Model = SwarmUiModelDefinition.BabesId, Avatar = new SwarmUiKindPreset { Width = 1024, Height = 1024 }, Custom = new SwarmUiKindPreset { Width = 896, Height = 1152 }, FullBody = new SwarmUiKindPreset { Width = 896, Height = 1152 }, }, new SwarmUiPresetDefinition { Id = "child", Label = "Children", Model = SwarmUiModelDefinition.DreamShaperId, Avatar = new SwarmUiKindPreset { Width = 1024, Height = 1024 }, Custom = new SwarmUiKindPreset { Width = 896, Height = 1152 }, FullBody = new SwarmUiKindPreset { Width = 896, Height = 1152 }, }, ], AgeRules = [new SwarmUiAgeRule { MinAge = 6, MaxAge = 11, PresetId = "child" }], }; living.NormalizeAfterLoad(); Assert.Equal( [SwarmUiModelDefinition.BabesId, SwarmUiModelDefinition.DreamShaperId], living.Models.Select(model => model.Id)); Assert.DoesNotContain(living.Models, model => model.Id == SwarmUiModelDefinition.MuseId); Assert.DoesNotContain(living.Models, model => model.Id == SwarmUiModelDefinition.RealismV25Id); Assert.Equal(SwarmUiModelDefinition.BabesId, living.Presets[0].Model); Assert.Equal(SwarmUiModelDefinition.DreamShaperId, living.Presets[1].Model); Assert.Equal("child", living.Resolve(8, PortraitKind.Avatar).PresetId); Assert.Equal(SwarmUiModelDefinition.DreamShaperId, living.Resolve(8, PortraitKind.Avatar).Model); } [Fact] public void NormalizeAfterLoad_EmptyModelsKeepSdxlPresetIdsInsteadOfKreaCatalog() { var living = new SwarmUiConfigFile { ActivePresetId = "default", Presets = [ new SwarmUiPresetDefinition { Id = "default", Label = "Default", Model = SwarmUiModelDefinition.BabesId, Avatar = new SwarmUiKindPreset { Width = 1024, Height = 1024 }, Custom = new SwarmUiKindPreset { Width = 896, Height = 1152 }, FullBody = new SwarmUiKindPreset { Width = 896, Height = 1152 }, }, new SwarmUiPresetDefinition { Id = "child", Label = "Children", Model = SwarmUiModelDefinition.DreamShaperId, Avatar = new SwarmUiKindPreset { Width = 1024, Height = 1024 }, Custom = new SwarmUiKindPreset { Width = 896, Height = 1152 }, FullBody = new SwarmUiKindPreset { Width = 896, Height = 1152 }, }, ], AgeRules = [new SwarmUiAgeRule { MinAge = 6, MaxAge = 11, PresetId = "child" }], }; living.NormalizeAfterLoad(); Assert.Equal( [SwarmUiModelDefinition.BabesId, SwarmUiModelDefinition.DreamShaperId], living.Models.Select(model => model.Id)); Assert.DoesNotContain(living.Models, model => model.Id == SwarmUiModelDefinition.MuseId); Assert.DoesNotContain(living.Models, model => model.Id == SwarmUiModelDefinition.RealismV25Id); Assert.Equal(SwarmUiModelDefinition.BabesId, living.Presets[0].Model); Assert.Equal(SwarmUiModelDefinition.DreamShaperId, living.Presets[1].Model); Assert.Equal(SwarmUiModelDefinition.DreamShaperId, living.Resolve(8, PortraitKind.Avatar).Model); } [Fact] public void Clone_DoesNotInjectKreaModelsIntoAnExistingSchoolCopy() { var living = new SwarmUiConfigFile { ActivePresetId = "default", Models = [ new SwarmUiModelDefinition { Id = SwarmUiModelDefinition.BabesId, Steps = 7, CfgScale = 1.5, Sampler = "euler", Scheduler = "normal", }, new SwarmUiModelDefinition { Id = SwarmUiModelDefinition.DreamShaperId, Steps = 4, CfgScale = 2, Sampler = "dpmpp_sde", Scheduler = "karras", }, ], Presets = [ new SwarmUiPresetDefinition { Id = "default", Label = "Default", Model = SwarmUiModelDefinition.BabesId, Avatar = new SwarmUiKindPreset { Width = 1024, Height = 1024 }, Custom = new SwarmUiKindPreset { Width = 896, Height = 1152 }, FullBody = new SwarmUiKindPreset { Width = 896, Height = 1152 }, }, ], }; var copy = SwarmUiConfigFile.Clone(living); Assert.Equal(2, copy.Models.Count); Assert.DoesNotContain(copy.Models, model => model.Id == SwarmUiModelDefinition.MuseId); Assert.DoesNotContain(copy.Models, model => model.Id == SwarmUiModelDefinition.RealismV25Id); Assert.Equal(SwarmUiModelDefinition.BabesId, copy.Presets[0].Model); Assert.Equal("default", copy.ActivePresetId); } private static string RepoRoot() { var dir = new DirectoryInfo(AppContext.BaseDirectory); while (dir is not null && !File.Exists(Path.Combine(dir.FullName, "h-school.sln"))) { dir = dir.Parent; } if (dir is null) { throw new InvalidOperationException("Could not find h-school.sln from the test output directory."); } return dir.FullName; } private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, PropertyNameCaseInsensitive = true, }; }