Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions InkkSlinger.Tests/InkCanvasCoreTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
using System;
using Microsoft.Xna.Framework;
using Xunit;

namespace InkkSlinger.Tests;

public sealed class InkCanvasCoreTests
{
[Fact]
public void DefaultStrokeCollection_IsNotNull()
{
var canvas = new InkCanvas();
Assert.NotNull(canvas.Strokes);
Assert.Equal(0, canvas.Strokes!.Count);
}

[Fact]
public void SettingStrokes_UpdatesPresenter()
{
var canvas = new InkCanvas();
var strokes = new InkStrokeCollection();
canvas.Strokes = strokes;

Assert.Same(strokes, canvas.Presenter.Strokes);
}

[Fact]
public void AddingStroke_UpdatesCollection()
{
var canvas = new InkCanvas();
var stroke = new InkStroke(new[] { new Vector2(0, 0), new Vector2(10, 10) });
canvas.Strokes!.Add(stroke);

Assert.Equal(1, canvas.Strokes.Count);
Assert.Same(stroke, canvas.Strokes[0]);
}

[Fact]
public void RemovingStroke_UpdatesCollection()
{
var canvas = new InkCanvas();
var stroke = new InkStroke(new[] { new Vector2(0, 0), new Vector2(10, 10) });
canvas.Strokes!.Add(stroke);
canvas.Strokes.Remove(stroke);

Assert.Equal(0, canvas.Strokes.Count);
}

[Fact]
public void ClearingStrokes_EmptiesCollection()
{
var canvas = new InkCanvas();
canvas.Strokes!.Add(new InkStroke(new[] { new Vector2(0, 0), new Vector2(5, 5) }));
canvas.Strokes.Add(new InkStroke(new[] { new Vector2(10, 10), new Vector2(20, 20) }));
Assert.Equal(2, canvas.Strokes.Count);

canvas.Strokes.Clear();
Assert.Equal(0, canvas.Strokes.Count);
}

[Fact]
public void InkStroke_GetBounds_CalculatesCorrectly()
{
var points = new[] { new Vector2(10, 20), new Vector2(30, 40) };
var stroke = new InkStroke(points, new InkDrawingAttributes { Width = 4f, Height = 4f });

var bounds = stroke.GetBounds();
Assert.Equal(8f, bounds.X); // 10 - 2
Assert.Equal(18f, bounds.Y); // 20 - 2
Assert.Equal(24f, bounds.Width); // (30+2) - (10-2)
Assert.Equal(24f, bounds.Height); // (40+2) - (20-2)
}

[Fact]
public void InkStroke_GetBounds_CachesResult()
{
var points = new[] { new Vector2(10, 20), new Vector2(30, 40) };
var stroke = new InkStroke(points);

var bounds1 = stroke.GetBounds();
var bounds2 = stroke.GetBounds();
Assert.Equal(bounds1, bounds2);
}

[Fact]
public void InkStroke_AddPoint_InvalidatesBounds()
{
var stroke = new InkStroke(new[] { new Vector2(0, 0) });
var bounds1 = stroke.GetBounds();

stroke.AddPoint(new Vector2(100, 100));
var bounds2 = stroke.GetBounds();

Assert.True(bounds2.Width > bounds1.Width);
Assert.True(bounds2.Height > bounds1.Height);
}

[Fact]
public void InkDrawingAttributes_Clone_CreatesIndependentCopy()
{
var original = new InkDrawingAttributes
{
Color = Color.Red,
Width = 5f,
Height = 3f,
Opacity = 0.5f
};

var clone = original.Clone();
clone.Color = Color.Blue;
clone.Width = 10f;

Assert.Equal(Color.Red, original.Color);
Assert.Equal(5f, original.Width);
Assert.Equal(Color.Blue, clone.Color);
Assert.Equal(10f, clone.Width);
}

[Fact]
public void InkStrokeCollection_Changed_FiresOnAdd()
{
var collection = new InkStrokeCollection();
bool changed = false;
collection.Changed += (_, _) => changed = true;

collection.Add(new InkStroke(new[] { Vector2.Zero }));
Assert.True(changed);
}

[Fact]
public void InkStrokeCollection_Changed_FiresOnRemove()
{
var collection = new InkStrokeCollection();
var stroke = new InkStroke(new[] { Vector2.Zero });
collection.Add(stroke);

bool changed = false;
collection.Changed += (_, _) => changed = true;
collection.Remove(stroke);
Assert.True(changed);
}

[Fact]
public void InkStrokeCollection_Changed_FiresOnClear()
{
var collection = new InkStrokeCollection();
collection.Add(new InkStroke(new[] { Vector2.Zero }));

bool changed = false;
collection.Changed += (_, _) => changed = true;
collection.Clear();
Assert.True(changed);
}

[Fact]
public void InkStrokeCollection_Changed_DoesNotFireOnEmptyClear()
{
var collection = new InkStrokeCollection();
bool changed = false;
collection.Changed += (_, _) => changed = true;
collection.Clear();
Assert.False(changed);
}

[Fact]
public void InkStroke_EmptyPoints_ReturnsEmptyBounds()
{
var stroke = new InkStroke(Array.Empty<Vector2>());
var bounds = stroke.GetBounds();
Assert.Equal(0f, bounds.Width);
Assert.Equal(0f, bounds.Height);
}

[Fact]
public void InkCanvas_DefaultDrawingAttributes_CanBeSet()
{
var canvas = new InkCanvas();
var attrs = new InkDrawingAttributes { Color = Color.Blue, Width = 8f };
canvas.DefaultDrawingAttributes = attrs;

Assert.Same(attrs, canvas.DefaultDrawingAttributes);
}

[Fact]
public void InkPresenter_StrokesProperty_UpdatesRendering()
{
var presenter = new InkPresenter();
var strokes = new InkStrokeCollection();
presenter.Strokes = strokes;

Assert.Same(strokes, presenter.Strokes);
}
}
190 changes: 190 additions & 0 deletions InkkSlinger.Tests/InkCanvasInputTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Xunit;

namespace InkkSlinger.Tests;

public sealed class InkCanvasInputTests
{
[Fact]
public void PointerDown_StartsStroke()
{
var canvas = CreateInkCanvas();
var uiRoot = CreateUiRoot(canvas);

var pointer = new Vector2(100f, 100f);
uiRoot.RunInputDeltaForTests(CreatePointerDelta(pointer, leftPressed: true));

Assert.True(canvas.IsDrawing);
Assert.Equal(1, canvas.Strokes!.Count);
}

[Fact]
public void PointerMove_AppendsPoints()
{
var canvas = CreateInkCanvas();
var uiRoot = CreateUiRoot(canvas);

var startPoint = new Vector2(50f, 50f);
uiRoot.RunInputDeltaForTests(CreatePointerDelta(startPoint, leftPressed: true));

var movePoint = new Vector2(100f, 100f);
uiRoot.RunInputDeltaForTests(CreatePointerDelta(movePoint, pointerMoved: true));

var stroke = canvas.Strokes![0];
Assert.Equal(2, stroke.PointCount);
}

[Fact]
public void PointerUp_FinalizesStroke()
{
var canvas = CreateInkCanvas();
var uiRoot = CreateUiRoot(canvas);

var startPoint = new Vector2(50f, 50f);
uiRoot.RunInputDeltaForTests(CreatePointerDelta(startPoint, leftPressed: true));

var movePoint = new Vector2(100f, 100f);
uiRoot.RunInputDeltaForTests(CreatePointerDelta(movePoint, pointerMoved: true));

uiRoot.RunInputDeltaForTests(CreatePointerDelta(movePoint, leftReleased: true));

Assert.False(canvas.IsDrawing);
Assert.Equal(1, canvas.Strokes!.Count);

var stroke = canvas.Strokes[0];
Assert.Equal(2, stroke.PointCount);
}

[Fact]
public void MultipleStrokes_AreAccumulated()
{
var canvas = CreateInkCanvas();
var uiRoot = CreateUiRoot(canvas);

// First stroke
uiRoot.RunInputDeltaForTests(CreatePointerDelta(new Vector2(50f, 50f), leftPressed: true));
uiRoot.RunInputDeltaForTests(CreatePointerDelta(new Vector2(100f, 100f), pointerMoved: true));
uiRoot.RunInputDeltaForTests(CreatePointerDelta(new Vector2(100f, 100f), leftReleased: true));

// Second stroke
uiRoot.RunInputDeltaForTests(CreatePointerDelta(new Vector2(200f, 200f), leftPressed: true));
uiRoot.RunInputDeltaForTests(CreatePointerDelta(new Vector2(250f, 250f), pointerMoved: true));
uiRoot.RunInputDeltaForTests(CreatePointerDelta(new Vector2(250f, 250f), leftReleased: true));

Assert.Equal(2, canvas.Strokes!.Count);
}

[Fact]
public void DisabledCanvas_DoesNotDraw()
{
var canvas = CreateInkCanvas();
canvas.IsEnabled = false;
var uiRoot = CreateUiRoot(canvas);

var pointer = new Vector2(100f, 100f);
uiRoot.RunInputDeltaForTests(CreatePointerDelta(pointer, leftPressed: true));

Assert.False(canvas.IsDrawing);
Assert.Equal(0, canvas.Strokes!.Count);
}

[Fact]
public void DrawingAttributes_AreAppliedToStrokes()
{
var canvas = CreateInkCanvas();
canvas.DefaultDrawingAttributes = new InkDrawingAttributes
{
Color = Color.Red,
Width = 10f
};

var uiRoot = CreateUiRoot(canvas);
uiRoot.RunInputDeltaForTests(CreatePointerDelta(new Vector2(50f, 50f), leftPressed: true));
uiRoot.RunInputDeltaForTests(CreatePointerDelta(new Vector2(50f, 50f), leftReleased: true));

var stroke = canvas.Strokes![0];
Assert.Equal(Color.Red, stroke.DrawingAttributes.Color);
Assert.Equal(10f, stroke.DrawingAttributes.Width);
}

[Fact]
public void StrokePoints_AreInCorrectSequence()
{
var canvas = CreateInkCanvas();
var uiRoot = CreateUiRoot(canvas);

var p1 = new Vector2(10f, 10f);
var p2 = new Vector2(20f, 20f);
var p3 = new Vector2(30f, 30f);

uiRoot.RunInputDeltaForTests(CreatePointerDelta(p1, leftPressed: true));
uiRoot.RunInputDeltaForTests(CreatePointerDelta(p2, pointerMoved: true));
uiRoot.RunInputDeltaForTests(CreatePointerDelta(p3, pointerMoved: true));
uiRoot.RunInputDeltaForTests(CreatePointerDelta(p3, leftReleased: true));

var stroke = canvas.Strokes![0];
Assert.Equal(3, stroke.PointCount);
Assert.Equal(p1, stroke.Points[0]);
Assert.Equal(p2, stroke.Points[1]);
Assert.Equal(p3, stroke.Points[2]);
}

private static InkCanvas CreateInkCanvas()
{
return new InkCanvas
{
Width = 400f,
Height = 300f
};
}

private static UiRoot CreateUiRoot(InkCanvas canvas)
{
var host = new Canvas
{
Width = 460f,
Height = 340f
};
host.AddChild(canvas);
Canvas.SetLeft(canvas, 20f);
Canvas.SetTop(canvas, 20f);

var uiRoot = new UiRoot(host);
RunLayout(uiRoot);
return uiRoot;
}

private static InputDelta CreatePointerDelta(
Vector2 pointer,
bool pointerMoved = false,
bool leftPressed = false,
bool leftReleased = false)
{
return new InputDelta
{
Previous = new InputSnapshot(default, default, pointer),
Current = new InputSnapshot(default, default, pointer),
PressedKeys = new List<Keys>(),
ReleasedKeys = new List<Keys>(),
TextInput = new List<char>(),
PointerMoved = pointerMoved || leftPressed || leftReleased,
WheelDelta = 0,
LeftPressed = leftPressed,
LeftReleased = leftReleased,
RightPressed = false,
RightReleased = false,
MiddlePressed = false,
MiddleReleased = false
};
}

private static void RunLayout(UiRoot uiRoot)
{
uiRoot.Update(
new GameTime(System.TimeSpan.FromMilliseconds(16), System.TimeSpan.FromMilliseconds(16)),
new Viewport(0, 0, 460, 340));
}
}
Loading