using AIStudio.Tools.PowerPoint; namespace AIStudio.Tests.Tools.PowerPoint; /// /// Checks which pictures of a library folder the LLM may choose from. /// [TestFixture] public sealed class PictureLibraryTests { private string folder = string.Empty; [SetUp] public void CreateFolder() { this.folder = Path.Combine(Path.GetTempPath(), $"ai-studio-picture-library-{Guid.NewGuid():N}"); Directory.CreateDirectory(this.folder); } [TearDown] public void DeleteFolder() => Directory.Delete(this.folder, true); [Test] public void OnlyPngAndJpegPicturesCountAndIconsGoByTheirNames() { this.CreateFiles("rocket.png", "Moon.JPG", "mars.jpeg", "star.svg", "notes.txt", ".hidden.png", "icon-star.png", "icons/flag.png", "IconSet/small/planet.png", "photos/crater.png"); var library = PictureLibrary.Read(this.folder, new Random(1), PictureLibrary.MAX_LIBRARY_PICTURES, null, CancellationToken.None); Assert.Multiple(() => { Assert.That(library.Pictures.Select(picture => picture.Name), Is.EquivalentTo(new[] { "rocket.png", "Moon.JPG", "mars.jpeg", "icon-star.png", "icons/flag.png", "IconSet/small/planet.png", "photos/crater.png" }), "Hidden files stay out, as everywhere in AI Studio."); Assert.That(library.Pictures.Select(picture => picture.Name), Is.Ordered.Using(StringComparer.OrdinalIgnoreCase)); Assert.That(library.Pictures.Where(picture => picture.IsIcon).Select(picture => picture.Name), Is.EquivalentTo(new[] { "icon-star.png", "icons/flag.png", "IconSet/small/planet.png" }), "A file or any of its folders may say that it is an icon."); Assert.That(library.PictureCount, Is.EqualTo(7)); Assert.That(library.IconCount, Is.EqualTo(3)); Assert.That(library.SkippedFileCount, Is.EqualTo(2), "The SVG icon and the notes are neither PNG nor JPEG."); Assert.That(library.IsSampled, Is.False); }); } [Test] public void AFolderOfIconsMakesAllOfItsPicturesIcons() { // // The library folder counts like the folders below it, so a folder "Icons" holds icons only. // The folders above it say where the library lies, so a library inside "iconography" gains nothing: // var iconFolder = Path.Combine(this.folder, "Icons"); var iconSetFolder = Path.Combine(this.folder, "IconSet"); var photoFolder = Path.Combine(this.folder, "iconography", "Photos"); this.CreateFiles("Icons/rocket.png", "Icons/planets/mars.png", "IconSet/moon.jpg", "iconography/Photos/crater.png"); Assert.Multiple(() => { Assert.That(PictureLibrary.Read(iconFolder, new Random(1), PictureLibrary.MAX_LIBRARY_PICTURES, null, CancellationToken.None).Pictures.Select(picture => picture.IsIcon), Is.EqualTo(new[] { true, true })); Assert.That(PictureLibrary.Read(iconSetFolder + Path.DirectorySeparatorChar, new Random(1), PictureLibrary.MAX_LIBRARY_PICTURES, null, CancellationToken.None).IconCount, Is.EqualTo(1), "A trailing separator changes nothing."); Assert.That(PictureLibrary.Read(photoFolder, new Random(1), PictureLibrary.MAX_LIBRARY_PICTURES, null, CancellationToken.None).IconCount, Is.Zero); }); } [Test] public void ALargeLibraryIsSampledAtRandom() { this.CreateFiles([..Enumerable.Range(1, 30).Select(number => $"picture-{number:00}.png")]); var sample = PictureLibrary.Read(this.folder, new Random(7), 10, null, CancellationToken.None); var again = PictureLibrary.Read(this.folder, new Random(7), 10, null, CancellationToken.None); Assert.Multiple(() => { Assert.That(sample.Pictures, Has.Count.EqualTo(10)); Assert.That(sample.Pictures.Select(picture => picture.Name), Is.Unique); Assert.That(sample.Pictures.Select(picture => picture.Name), Is.Ordered.Using(StringComparer.OrdinalIgnoreCase), "The sample is sorted after it is drawn."); Assert.That(sample.PictureCount, Is.EqualTo(30), "The count tells about the whole library."); Assert.That(sample.IsSampled, Is.True); Assert.That(again.Pictures.Select(picture => picture.Name), Is.EqualTo(sample.Pictures.Select(picture => picture.Name)), "The same random numbers draw the same sample."); }); } [Test] public void EveryPictureHasTheSameChanceToBeInTheSample() { // // The first pictures fill the sample, so a sampling which only kept them would let the // last pictures never in. Drawn a thousand times, every picture shows up about as often: // this.CreateFiles([..Enumerable.Range(1, 20).Select(number => $"picture-{number:00}.png")]); var random = new Random(3); var counts = new Dictionary(); for (var draw = 0; draw < 1_000; draw++) { foreach (var picture in PictureLibrary.Read(this.folder, random, 5, null, CancellationToken.None).Pictures) counts[picture.Name] = counts.GetValueOrDefault(picture.Name) + 1; } // Each picture is in a sample with a chance of 5 in 20, i.e., about 250 times: Assert.That(counts.Values, Has.All.InRange(180, 320)); Assert.That(counts, Has.Count.EqualTo(20)); } private void CreateFiles(params string[] names) { foreach (var name in names) { var path = Path.Combine(this.folder, name.Replace('/', Path.DirectorySeparatorChar)); Directory.CreateDirectory(Path.GetDirectoryName(path)!); File.WriteAllBytes(path, [1, 2, 3]); } } }