From 52595b56bebe31e0404f3a69ca5c6f77790e6e3f Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 3 May 2026 17:12:52 +0200 Subject: [PATCH] Add TestFixtures.Resources project for manual resource-view tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single .NET classlib that embeds one resource of every type the Avalonia port recognises — .xml / .xsd / .xslt / .xaml / .png / .bmp / .jpg / .gif / .ico / .cur / .resources / .bin (unknown-extension fall-through). The image fixtures render a 64×64 cream square with a blue circle and red diagonal stripe so the inline preview is obviously decoded rather than blank; the .ico is multi-frame (16/32/48) so future per-frame work has something to chew on. Assisted-by: Claude:claude-opus-4-7:Claude Code --- TestFixtures.Resources/Generate.cs | 130 ++++++++++++++++++ TestFixtures.Resources/Generate.csproj | 18 +++ .../TestFixtures.Resources.csproj | 34 +++++ .../fixtures/Strings.resources | Bin 0 -> 331 bytes TestFixtures.Resources/fixtures/Window.xaml | 20 +++ TestFixtures.Resources/fixtures/blob.bin | 1 + TestFixtures.Resources/fixtures/favicon.ico | Bin 0 -> 2403 bytes TestFixtures.Resources/fixtures/logo.bmp | Bin 0 -> 12342 bytes TestFixtures.Resources/fixtures/logo.gif | Bin 0 -> 1493 bytes TestFixtures.Resources/fixtures/logo.jpg | Bin 0 -> 2700 bytes TestFixtures.Resources/fixtures/logo.png | Bin 0 -> 1442 bytes TestFixtures.Resources/fixtures/pointer.cur | Bin 0 -> 796 bytes TestFixtures.Resources/fixtures/sample.xml | 15 ++ TestFixtures.Resources/fixtures/schema.xsd | 26 ++++ .../fixtures/transform.xslt | 25 ++++ 15 files changed, 269 insertions(+) create mode 100644 TestFixtures.Resources/Generate.cs create mode 100644 TestFixtures.Resources/Generate.csproj create mode 100644 TestFixtures.Resources/TestFixtures.Resources.csproj create mode 100644 TestFixtures.Resources/fixtures/Strings.resources create mode 100644 TestFixtures.Resources/fixtures/Window.xaml create mode 100644 TestFixtures.Resources/fixtures/blob.bin create mode 100644 TestFixtures.Resources/fixtures/favicon.ico create mode 100644 TestFixtures.Resources/fixtures/logo.bmp create mode 100644 TestFixtures.Resources/fixtures/logo.gif create mode 100644 TestFixtures.Resources/fixtures/logo.jpg create mode 100644 TestFixtures.Resources/fixtures/logo.png create mode 100644 TestFixtures.Resources/fixtures/pointer.cur create mode 100644 TestFixtures.Resources/fixtures/sample.xml create mode 100644 TestFixtures.Resources/fixtures/schema.xsd create mode 100644 TestFixtures.Resources/fixtures/transform.xslt diff --git a/TestFixtures.Resources/Generate.cs b/TestFixtures.Resources/Generate.cs new file mode 100644 index 000000000..d39c253c8 --- /dev/null +++ b/TestFixtures.Resources/Generate.cs @@ -0,0 +1,130 @@ +// Tiny helper that produces all the binary fixture files (PNG / BMP / JPG / GIF / ICO / CUR / +// .resources / .bin) into the fixtures/ directory. Text fixtures (XML / XSD / XSLT / XAML) are +// checked in as-is. Run with `dotnet run --project Generate.csproj` from this directory. +// +// Each image format renders an obvious recognizable shape (coloured square with a circle and a +// diagonal stripe) at 64×64 so manual ILSpy testing can eyeball that the rendering pipeline +// is decoding the bytes — not just rendering a blank tile. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Resources; + +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +var dir = Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "fixtures"); +dir = Path.GetFullPath(dir); +Directory.CreateDirectory(dir); + +WriteImage(Path.Combine(dir, "logo.png"), new PngEncoder()); +WriteImage(Path.Combine(dir, "logo.bmp"), new BmpEncoder()); +WriteImage(Path.Combine(dir, "logo.jpg"), new JpegEncoder { Quality = 92 }); +WriteImage(Path.Combine(dir, "logo.gif"), new GifEncoder()); + +// Multi-frame .ico: 16x16, 32x32, 48x48, each PNG-encoded inside the ICO container so Avalonia +// can decode the largest frame for preview while a savvy viewer can pick any. +File.WriteAllBytes(Path.Combine(dir, "favicon.ico"), BuildIcoOrCur(isCursor: false, sizes: new[] { 16, 32, 48 })); +File.WriteAllBytes(Path.Combine(dir, "pointer.cur"), BuildIcoOrCur(isCursor: true, sizes: new[] { 32 })); + +// .resources file with a mix of strings and other-typed entries — the .resources DataGrid view +// splits these into two tables. +var ms = new MemoryStream(); +using (var rw = new ResourceWriter(ms)) +{ + rw.AddResource("greeting", "Hello, world"); + rw.AddResource("city", "Linz"); + rw.AddResource("year", 2026); + rw.AddResource("ratio", 1.61803); + rw.AddResource("flag", true); +} +File.WriteAllBytes(Path.Combine(dir, "Strings.resources"), ms.ToArray()); + +// Unknown extension — should fall through to the generic ResourceTreeNode. +File.WriteAllBytes(Path.Combine(dir, "blob.bin"), new byte[] { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE }); + +Console.WriteLine($"Wrote fixtures into {dir}"); + +// --- helpers --- + +static void WriteImage(string path, IImageEncoder encoder, int size = 64) +{ + using var img = RenderShape(size); + using var fs = File.Create(path); + img.Save(fs, encoder); +} + +static Image RenderShape(int size) +{ + var img = new Image(size, size, new Rgba32(0xFF, 0xF6, 0xE5)); + img.Mutate(ctx => { + // Filled blue circle in the centre. + ctx.Fill(new Rgba32(0x33, 0x99, 0xCC), + new SixLabors.ImageSharp.Drawing.EllipsePolygon(size / 2f, size / 2f, size * 0.35f)); + // Red diagonal stripe. + ctx.DrawLine(new Rgba32(0xCC, 0x33, 0x33), + Math.Max(2, size / 16f), + new PointF(0, size), + new PointF(size, 0)); + // 1px dark border so the bounds are obvious against any background. + ctx.Draw(new Rgba32(0x33, 0x33, 0x33), 1, + new RectangleF(0, 0, size - 1, size - 1)); + }); + return img; +} + +// Builds an ICO/CUR file containing one PNG-encoded entry per requested size. The on-disk +// layout: ICONDIR + ICONDIRENTRY[*] + concatenated frame bytes; only byte 2 (image type) +// distinguishes ICO (1) from CUR (2). Hotspot for cursors is centred at (size/2, size/2). +static byte[] BuildIcoOrCur(bool isCursor, int[] sizes) +{ + var frames = new List(sizes.Length); + var pngEncoder = new PngEncoder(); + foreach (var sz in sizes) + { + using var img = RenderShape(sz); + using var ms = new MemoryStream(); + img.Save(ms, pngEncoder); + frames.Add(ms.ToArray()); + } + var fileMs = new MemoryStream(); + var w = new BinaryWriter(fileMs); + w.Write((ushort)0); // reserved + w.Write((ushort)(isCursor ? 2 : 1)); // type: 1=ICO, 2=CUR + w.Write((ushort)sizes.Length); // image count + int dirSize = 6 + 16 * sizes.Length; + int offset = dirSize; + for (int i = 0; i < sizes.Length; i++) + { + var sz = sizes[i]; + var dim = (byte)(sz >= 256 ? 0 : sz); + w.Write(dim); // width + w.Write(dim); // height + w.Write((byte)0); // palette count + w.Write((byte)0); // reserved + if (isCursor) + { + w.Write((ushort)(sz / 2)); // hotspot X + w.Write((ushort)(sz / 2)); // hotspot Y + } + else + { + w.Write((ushort)1); // colour planes + w.Write((ushort)32); // bits per pixel + } + w.Write((uint)frames[i].Length); // bytes in frame + w.Write((uint)offset); // offset to frame + offset += frames[i].Length; + } + foreach (var frame in frames) + w.Write(frame); + return fileMs.ToArray(); +} diff --git a/TestFixtures.Resources/Generate.csproj b/TestFixtures.Resources/Generate.csproj new file mode 100644 index 000000000..3e03171f1 --- /dev/null +++ b/TestFixtures.Resources/Generate.csproj @@ -0,0 +1,18 @@ + + + Exe + net10.0 + TestFixtures.Generate + enable + + false + + + + + + + diff --git a/TestFixtures.Resources/TestFixtures.Resources.csproj b/TestFixtures.Resources/TestFixtures.Resources.csproj new file mode 100644 index 000000000..e5a87e5b7 --- /dev/null +++ b/TestFixtures.Resources/TestFixtures.Resources.csproj @@ -0,0 +1,34 @@ + + + net10.0 + TestFixtures.Resources + TestFixtures.Resources + enable + + $(MSBuildThisFileDirectory)bin\ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TestFixtures.Resources/fixtures/Strings.resources b/TestFixtures.Resources/fixtures/Strings.resources new file mode 100644 index 0000000000000000000000000000000000000000..0ea60fead4b552a1f52cb8c6dc178bba24902fba GIT binary patch literal 331 zcmX?i>is@O1_p+SK%5g?SzMBus~417oL^d$oLUTL1*ImYq!#HYR*8GxXUf^%t3Noi54ZC+|=Nl{{sjzU0bQch;FcWPxwes*e}ZIZcpqG__J znW3ezNveT`r81^vrFkWpxv4PQgHubGfR17XVh{*$bOE6jHLHdrg0r|Yo$_juo)px0 z&9ADF0!r%xF)v6R5ZD2+I?z)b$qbncB@C5dL5?(r9EL=ObOtscS0J6Ch#?gSOMoi! zfPx%AL9Qa8JV+p)K@7;{s07L<0@cX_IgBhmnR!)AjEp=UsX00MItt~$a7f|JQM;d0 N{P?Fm$18RQ1^_T+Su_9u literal 0 HcmV?d00001 diff --git a/TestFixtures.Resources/fixtures/Window.xaml b/TestFixtures.Resources/fixtures/Window.xaml new file mode 100644 index 000000000..0f9a76e86 --- /dev/null +++ b/TestFixtures.Resources/fixtures/Window.xaml @@ -0,0 +1,20 @@ + + + + + +