using System.Windows; using Azaion.Common; using Azaion.Common.DTO; using Azaion.Common.Services; using Xunit; namespace Azaion.Annotator.Test; public class TileProcessorTest { private const int IMAGE_SIZE = 5000; [Fact] public void Split_DetectionsNearImageCorners_ShouldCreateFourTiles() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var detections = new List { new(10, 60, 10, 60), // Top-left corner new(IMAGE_SIZE - 60, IMAGE_SIZE - 10, 10, 60), // Top-right corner new(10, 60, IMAGE_SIZE - 60, IMAGE_SIZE - 10), // Bottom-left corner new(IMAGE_SIZE - 60, IMAGE_SIZE - 10, IMAGE_SIZE - 60, IMAGE_SIZE - 10) // Bottom-right corner }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Equal(4, results.Count); } [Fact] public void Split_DetectionsFarApartButFitInOneTile_ShouldCreateOneTile() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var detections = new List { new(100, 150, 100, 150), new(1200, 1250, 1200, 1250) }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Single(results); Assert.Equal(2, results[0].Detections.Count); } [Fact] public void Split_DetectionsTooFarApart_ShouldCreateMultipleTiles() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var detections = new List { new(100, 150, 100, 150), new(2000, 2050, 2000, 2050) // More than Constants.AI_TILE_SIZE away }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Equal(2, results.Count); Assert.Contains(results, r => r.Detections.Count == 1 && r.Detections.Contains(detections[0])); Assert.Contains(results, r => r.Detections.Count == 1 && r.Detections.Contains(detections[1])); } [Fact] public void Split_ComplexScenario_ShouldCreateCorrectNumberOfTiles() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var detections = new List { // Group 1 (should be tiled together) new(100, 150, 100, 150), new(200, 250, 200, 250), new(500, 550, 500, 550), // Group 2 (far from group 1, should be in a separate tile) new(3000, 3050, 3000, 3050), new(3100, 3150, 3100, 3150), }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Equal(2, results.Count); var group1Tile = results.FirstOrDefault(r => r.Detections.Count == 3); var group2Tile = results.FirstOrDefault(r => r.Detections.Count == 2); Assert.NotNull(group1Tile); Assert.NotNull(group2Tile); Assert.Contains(detections[0], group1Tile.Detections); Assert.Contains(detections[1], group1Tile.Detections); Assert.Contains(detections[2], group1Tile.Detections); Assert.Contains(detections[3], group2Tile.Detections); Assert.Contains(detections[4], group2Tile.Detections); } [Fact] public void Split_NoDetections_ShouldReturnEmptyList() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var detections = new List(); // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Empty(results); } [Fact] public void Split_OneDetection_ShouldCreateOneTile() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var detections = new List { new(100, 150, 100, 150) }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Single(results); Assert.Single(results[0].Detections); Assert.Equal(detections[0], results[0].Detections[0]); } [Fact] public void Split_DetectionsOnTileBoundary_ShouldFitInOneTile() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); // Combined width is 1270. 1270 + BORDER (10) is not > Constants.AI_TILE_SIZE (1280), so they fit. var detections = new List { new(0, 50, 0, 50), new(Constants.AI_TILE_SIZE - TileProcessor.BORDER - 50, Constants.AI_TILE_SIZE - TileProcessor.BORDER, 0, 50) }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Single(results); Assert.Equal(2, results[0].Detections.Count); } [Fact] public void Split_DetectionsJustOverTileBoundary_ShouldCreateTwoTiles() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); // Combined width is 1271. 1271 + BORDER (10) is > Constants.AI_TILE_SIZE (1280), so they don't fit. var detections = new List { new(0, 50, 1000, 1050), // Top-most new(Constants.AI_TILE_SIZE - TileProcessor.BORDER - 49, Constants.AI_TILE_SIZE - TileProcessor.BORDER + 1, 0, 50) }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Equal(2, results.Count); } [Fact] public void Split_ResultingTiles_ShouldBeWithinImageBoundaries() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var detections = new List { new(10, 60, 10, 60), // Top-left corner new(IMAGE_SIZE - 60, IMAGE_SIZE - 10, IMAGE_SIZE - 60, IMAGE_SIZE - 10) // Bottom-right corner }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Equal(2, results.Count); foreach (var result in results) { var tile = result.Tile; Assert.True(tile.Left >= 0, $"Tile Left boundary {tile.Left} is out of bounds."); Assert.True(tile.Top >= 0, $"Tile Top boundary {tile.Top} is out of bounds."); Assert.True(tile.Right <= originalSize.Width, $"Tile Right boundary {tile.Right} is out of bounds."); Assert.True(tile.Bottom <= originalSize.Height, $"Tile Bottom boundary {tile.Bottom} is out of bounds."); } } [Fact] public void Split_ChainedDetections_ShouldCreateOneTile() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var detections = new List { new(100, 200, 100, 200), // Detection A new(600, 700, 600, 700), // Detection B (close to A) new(1100, 1200, 1100, 1200) // Detection C (close to B, but far from A) }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Single(results); Assert.Equal(3, results[0].Detections.Count); } [Fact] public void Split_SingleDetectionLargerThanTileSize_ShouldCreateOneTile() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var largeDetection = new CanvasLabel(100, 100 + Constants.AI_TILE_SIZE + 100, 100, 200); var detections = new List { largeDetection }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Single(results); var resultTile = results[0]; Assert.Single(resultTile.Detections); Assert.Equal(largeDetection, resultTile.Detections[0]); // The tile should be at least as large as the detection it contains. Assert.True(resultTile.Tile.Width >= largeDetection.Width); Assert.True(resultTile.Tile.Height >= largeDetection.Height); } [Fact] public void Split_LargeDetectionWithNearbySmallDetection_ShouldCreateOneTile() { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); var largeTallDetection = new CanvasLabel(100, 150, 100, 100 + Constants.AI_TILE_SIZE + 200); var smallDetectionNearby = new CanvasLabel(largeTallDetection.Right + 15, largeTallDetection.Right + 35, 700, 720); var detections = new List { largeTallDetection, smallDetectionNearby }; // Act var results = TileProcessor.Split(originalSize, detections, CancellationToken.None); // Assert Assert.Single(results); Assert.Equal(2, results[0].Detections.Count); Assert.Contains(largeTallDetection, results[0].Detections); Assert.Contains(smallDetectionNearby, results[0].Detections); } }