namespace LivingVillage.Desktop.Tests open System open System.IO open Microsoft.VisualStudio.TestTools.UnitTesting open LivingVillage.Kernel open LivingVillage.Kernel.Sim open LivingVillage.Desktop.VillageArt /// P33 vertical slice: the provenanced CC0 asset pack (Kenney Tiny Farm ground + /// Puny Characters) must load at the documented 32x32 / 32x48 shapes, be an exact /// integer 2x of the 16px / 16x24 source sprites, and stay behind the /// `LV_ASSET_PACK=cc0` switch so the procedural Jiangnan atlas is the fallback. [] type AssetPackTests () = let assetPath (relative: string) = Path.Combine(AppContext.BaseDirectory, relative) let pngDimensions (path: string) : int * int = let bytes = File.ReadAllBytes path let signature = [| 0x89uy; 0x50uy; 0x4Euy; 0x47uy |] for i in 0 .. 3 do Assert.IsTrue(signature.[i] = bytes.[i], sprintf "%s is not a PNG" path) let be32 (offset: int) = (int bytes.[offset] <<< 24) ||| (int bytes.[offset + 1] <<< 16) ||| (int bytes.[offset + 2] <<< 8) ||| int bytes.[offset + 3] be32 16, be32 20 [] member _.Cc0GroundAtlasIsIntegerMultipleOfTheTileGrid () = let width, height = pngDimensions (assetPath cc0TileAtlasRelativePath) Assert.AreEqual(cc0TileAtlasWidth, width) Assert.AreEqual(cc0TileAtlasHeight, height) Assert.AreEqual(0, width % Sim.tilePixels) Assert.AreEqual(0, height % Sim.tilePixels) Assert.AreEqual(cc0TileCount, width / Sim.tilePixels) Assert.AreEqual(cc0TileAtlasWidth, width) Assert.AreEqual(2, Sim.tilePixels / cc0TileSourcePixels) Assert.AreEqual(0, Sim.tilePixels % cc0TileSourcePixels) [] member _.Cc0StructureTileIndicesFitTheAtlasAndWaterHasTwoPhases () = // Every P34/P39 self-drawn cell must sit inside the 19-tile atlas band. let indices = [ cc0TileIndexWaterA cc0TileIndexWaterB cc0TileIndexRoofRidge cc0TileIndexRoofEave cc0TileIndexWallWood cc0TileIndexWallWindow cc0TileIndexRailing cc0TileIndexDoor cc0TileIndexBridgeCenter cc0TileIndexBridgeEnd cc0TileIndexBoatLeft cc0TileIndexBoatRight cc0TileIndexStoneLantern cc0TileIndexStall cc0TileIndexReeds ] for index in indices do Assert.IsTrue(index >= 0 && index < cc0TileCount, sprintf "cc0 tile index %d out of atlas" index) let width, _ = pngDimensions (assetPath cc0TileAtlasRelativePath) Assert.IsTrue(width >= (List.max indices + 1) * Sim.tilePixels, "atlas must cover every structure index") // Two-phase water: phase depends only on tick/tile, always in {A, B}, and both // phases appear across a row of tiles in one frame. Assert.AreEqual(2, cc0WaterFrameCount) let phases = [ for tileX in 0 .. 15 -> cc0WaterTileIndexAt 0L tileX 0 ] |> Set.ofList Assert.IsTrue((phases = Set.ofList [ cc0TileIndexWaterA; cc0TileIndexWaterB ]), "one frame must show both water phases across the river") for tileX in 0 .. 15 do for tileY in 0 .. 15 do let index = cc0WaterTileIndexAt 12345L tileX tileY Assert.IsTrue(index = cc0TileIndexWaterA || index = cc0TileIndexWaterB) [] member _.Cc0CharacterAtlasIsIntegerMultipleOfTheCellGrid () = let width, height = pngDimensions (assetPath cc0CharacterAtlasRelativePath) Assert.AreEqual(cc0CharacterAtlasWidth, width) Assert.AreEqual(cc0CharacterCellHeight, height) Assert.AreEqual(0, width % cc0CharacterCellWidth) Assert.AreEqual(0, height % cc0CharacterCellHeight) Assert.AreEqual( cc0CharacterVariantCount * cc0CharacterDirectionCount * cc0CharacterFrameCount, width / cc0CharacterCellWidth) Assert.AreEqual(2, cc0CharacterCellWidth / cc0CharacterSourceWidth) Assert.AreEqual(2, cc0CharacterCellHeight / cc0CharacterSourceHeight) [] member _.AssetPackSwitchSelectsRealPackAndFallsBackToProcedural () = let previous = Environment.GetEnvironmentVariable "LV_ASSET_PACK" try Environment.SetEnvironmentVariable("LV_ASSET_PACK", null) Assert.IsFalse(useCc0Pack (), "unset switch must keep the procedural fallback") Assert.IsTrue((selectedGroundAtlasRelativePath ()).IsNone, "fallback ground is procedural") Assert.AreEqual(characterAtlasRelativePath, selectedCharacterAtlasRelativePath ()) Environment.SetEnvironmentVariable("LV_ASSET_PACK", "cc0") Assert.IsTrue(useCc0Pack (), "cc0 switch enables the real pack") Assert.IsTrue(selectedGroundAtlasRelativePath () = Some cc0TileAtlasRelativePath) Assert.AreEqual(cc0CharacterAtlasRelativePath, selectedCharacterAtlasRelativePath ()) Environment.SetEnvironmentVariable("LV_ASSET_PACK", "kenney") Assert.IsFalse(useCc0Pack (), "unknown pack value falls back to procedural") finally Environment.SetEnvironmentVariable("LV_ASSET_PACK", previous)