Initial commit: .NET MAUI Linux Platform
Complete Linux platform implementation for .NET MAUI with:
- 35+ Skia-rendered controls (Button, Label, Entry, CarouselView, etc.)
- Platform services (Clipboard, FilePicker, Notifications, DragDrop, etc.)
- Accessibility support (AT-SPI2, High Contrast)
- HiDPI and Input Method support
- 216 unit tests
- CI/CD workflows
- Project templates
- Documentation
🤖 Generated with Claude Code
This commit is contained in:
31
tests/Microsoft.Maui.Controls.Linux.Tests.csproj
Normal file
31
tests/Microsoft.Maui.Controls.Linux.Tests.csproj
Normal file
@@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.116.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.Maui.Controls.Linux.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
564
tests/Services/ServiceTests.cs
Normal file
564
tests/Services/ServiceTests.cs
Normal file
@@ -0,0 +1,564 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
using Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Tests;
|
||||
|
||||
public class HiDpiServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var service = new HiDpiService();
|
||||
|
||||
Assert.Equal(1.0f, service.ScaleFactor);
|
||||
Assert.Equal(96f, service.Dpi);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Initialize_CanBeCalled()
|
||||
{
|
||||
var service = new HiDpiService();
|
||||
|
||||
service.Initialize();
|
||||
|
||||
// Should not throw
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Initialize_OnlyRunsOnce()
|
||||
{
|
||||
var service = new HiDpiService();
|
||||
|
||||
service.Initialize();
|
||||
service.Initialize();
|
||||
|
||||
// Second call should be no-op
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DetectScaleFactor_CanBeCalled()
|
||||
{
|
||||
var service = new HiDpiService();
|
||||
|
||||
service.DetectScaleFactor();
|
||||
|
||||
// Should not throw, may or may not find scale
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToPhysicalPixels_WithDefaultScale_ReturnsInput()
|
||||
{
|
||||
var service = new HiDpiService();
|
||||
|
||||
float result = service.ToPhysicalPixels(100f);
|
||||
|
||||
Assert.Equal(100f, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToLogicalPixels_WithDefaultScale_ReturnsInput()
|
||||
{
|
||||
var service = new HiDpiService();
|
||||
|
||||
float result = service.ToLogicalPixels(100f);
|
||||
|
||||
Assert.Equal(100f, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScaleChangedEvent_CanBeSubscribed()
|
||||
{
|
||||
var service = new HiDpiService();
|
||||
bool eventRaised = false;
|
||||
|
||||
service.ScaleChanged += (s, e) => eventRaised = true;
|
||||
|
||||
Assert.False(eventRaised); // Not raised yet
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFontScaleFactor_ReturnsValidValue()
|
||||
{
|
||||
var service = new HiDpiService();
|
||||
|
||||
float scale = service.GetFontScaleFactor();
|
||||
|
||||
Assert.True(scale > 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class ScaleChangedEventArgsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsProperties()
|
||||
{
|
||||
var args = new ScaleChangedEventArgs(1.0f, 2.0f, 192f);
|
||||
|
||||
Assert.Equal(1.0f, args.OldScale);
|
||||
Assert.Equal(2.0f, args.NewScale);
|
||||
Assert.Equal(192f, args.NewDpi);
|
||||
}
|
||||
}
|
||||
|
||||
public class HighContrastServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var service = new HighContrastService();
|
||||
|
||||
Assert.False(service.IsHighContrastEnabled);
|
||||
Assert.Equal(HighContrastTheme.None, service.CurrentTheme);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Initialize_CanBeCalled()
|
||||
{
|
||||
var service = new HighContrastService();
|
||||
|
||||
service.Initialize();
|
||||
|
||||
// Should not throw
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DetectHighContrast_CanBeCalled()
|
||||
{
|
||||
var service = new HighContrastService();
|
||||
|
||||
service.DetectHighContrast();
|
||||
|
||||
// Should not throw
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ForceHighContrast_EnablesHighContrast()
|
||||
{
|
||||
var service = new HighContrastService();
|
||||
|
||||
service.ForceHighContrast(true, HighContrastTheme.WhiteOnBlack);
|
||||
|
||||
Assert.True(service.IsHighContrastEnabled);
|
||||
Assert.Equal(HighContrastTheme.WhiteOnBlack, service.CurrentTheme);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ForceHighContrast_DisablesHighContrast()
|
||||
{
|
||||
var service = new HighContrastService();
|
||||
service.ForceHighContrast(true);
|
||||
|
||||
service.ForceHighContrast(false);
|
||||
|
||||
Assert.False(service.IsHighContrastEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetColors_ReturnsWhiteOnBlackColors()
|
||||
{
|
||||
var service = new HighContrastService();
|
||||
service.ForceHighContrast(true, HighContrastTheme.WhiteOnBlack);
|
||||
|
||||
var colors = service.GetColors();
|
||||
|
||||
Assert.Equal(SKColors.Black, colors.Background);
|
||||
Assert.Equal(SKColors.White, colors.Foreground);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetColors_ReturnsBlackOnWhiteColors()
|
||||
{
|
||||
var service = new HighContrastService();
|
||||
service.ForceHighContrast(true, HighContrastTheme.BlackOnWhite);
|
||||
|
||||
var colors = service.GetColors();
|
||||
|
||||
Assert.Equal(SKColors.White, colors.Background);
|
||||
Assert.Equal(SKColors.Black, colors.Foreground);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetColors_ReturnsDefaultColorsWhenDisabled()
|
||||
{
|
||||
var service = new HighContrastService();
|
||||
|
||||
var colors = service.GetColors();
|
||||
|
||||
Assert.Equal(SKColors.White, colors.Background);
|
||||
Assert.NotEqual(SKColors.Black, colors.Foreground); // Default is gray
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HighContrastChangedEvent_CanBeSubscribed()
|
||||
{
|
||||
var service = new HighContrastService();
|
||||
bool eventRaised = false;
|
||||
|
||||
service.HighContrastChanged += (s, e) => eventRaised = true;
|
||||
service.ForceHighContrast(true);
|
||||
|
||||
Assert.True(eventRaised);
|
||||
}
|
||||
}
|
||||
|
||||
public class HighContrastColorsTests
|
||||
{
|
||||
[Fact]
|
||||
public void AllPropertiesCanBeSet()
|
||||
{
|
||||
var colors = new HighContrastColors
|
||||
{
|
||||
Background = SKColors.Black,
|
||||
Foreground = SKColors.White,
|
||||
Accent = SKColors.Cyan,
|
||||
Border = SKColors.White,
|
||||
Error = SKColors.Red,
|
||||
Success = SKColors.Green,
|
||||
Warning = SKColors.Yellow,
|
||||
Link = SKColors.Blue,
|
||||
LinkVisited = SKColors.Purple,
|
||||
Selection = SKColors.Blue,
|
||||
SelectionText = SKColors.White,
|
||||
DisabledText = SKColors.Gray,
|
||||
DisabledBackground = SKColors.DarkGray
|
||||
};
|
||||
|
||||
Assert.Equal(SKColors.Black, colors.Background);
|
||||
Assert.Equal(SKColors.White, colors.Foreground);
|
||||
Assert.Equal(SKColors.Cyan, colors.Accent);
|
||||
}
|
||||
}
|
||||
|
||||
public class HighContrastChangedEventArgsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsProperties()
|
||||
{
|
||||
var args = new HighContrastChangedEventArgs(true, HighContrastTheme.WhiteOnBlack);
|
||||
|
||||
Assert.True(args.IsEnabled);
|
||||
Assert.Equal(HighContrastTheme.WhiteOnBlack, args.Theme);
|
||||
}
|
||||
}
|
||||
|
||||
public class DragDropServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var service = new DragDropService();
|
||||
|
||||
Assert.False(service.IsDragging);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CancelDrag_WhenNotDragging_DoesNotThrow()
|
||||
{
|
||||
var service = new DragDropService();
|
||||
|
||||
service.CancelDrag();
|
||||
|
||||
Assert.False(service.IsDragging);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessClientMessage_CanBeCalled()
|
||||
{
|
||||
var service = new DragDropService();
|
||||
|
||||
// Simply verify the method can be called without exception
|
||||
service.ProcessClientMessage(0, new nint[5]);
|
||||
|
||||
Assert.NotNull(service);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DragEnterEvent_CanBeSubscribed()
|
||||
{
|
||||
var service = new DragDropService();
|
||||
bool eventRaised = false;
|
||||
|
||||
service.DragEnter += (s, e) => eventRaised = true;
|
||||
|
||||
Assert.False(eventRaised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DragOverEvent_CanBeSubscribed()
|
||||
{
|
||||
var service = new DragDropService();
|
||||
bool eventRaised = false;
|
||||
|
||||
service.DragOver += (s, e) => eventRaised = true;
|
||||
|
||||
Assert.False(eventRaised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DragLeaveEvent_CanBeSubscribed()
|
||||
{
|
||||
var service = new DragDropService();
|
||||
bool eventRaised = false;
|
||||
|
||||
service.DragLeave += (s, e) => eventRaised = true;
|
||||
|
||||
Assert.False(eventRaised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropEvent_CanBeSubscribed()
|
||||
{
|
||||
var service = new DragDropService();
|
||||
bool eventRaised = false;
|
||||
|
||||
service.Drop += (s, e) => eventRaised = true;
|
||||
|
||||
Assert.False(eventRaised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dispose_CanBeCalled()
|
||||
{
|
||||
var service = new DragDropService();
|
||||
|
||||
service.Dispose();
|
||||
|
||||
// Should not throw
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dispose_CanBeCalledMultipleTimes()
|
||||
{
|
||||
var service = new DragDropService();
|
||||
|
||||
service.Dispose();
|
||||
service.Dispose();
|
||||
|
||||
// Should not throw
|
||||
}
|
||||
}
|
||||
|
||||
public class DragDataTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var data = new DragData();
|
||||
|
||||
Assert.Equal(IntPtr.Zero, data.SourceWindow);
|
||||
Assert.Empty(data.SupportedTypes);
|
||||
Assert.Null(data.Text);
|
||||
Assert.Null(data.FilePaths);
|
||||
Assert.Null(data.Data);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Text_CanBeSet()
|
||||
{
|
||||
var data = new DragData { Text = "Hello World" };
|
||||
|
||||
Assert.Equal("Hello World", data.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilePaths_CanBeSet()
|
||||
{
|
||||
var data = new DragData
|
||||
{
|
||||
FilePaths = new[] { "/home/user/file1.txt", "/home/user/file2.txt" }
|
||||
};
|
||||
|
||||
Assert.Equal(2, data.FilePaths.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Data_CanBeSet()
|
||||
{
|
||||
var customData = new { Id = 1, Name = "Test" };
|
||||
var data = new DragData { Data = customData };
|
||||
|
||||
Assert.Equal(customData, data.Data);
|
||||
}
|
||||
}
|
||||
|
||||
public class LinuxDragEventArgsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsProperties()
|
||||
{
|
||||
var dragData = new DragData { Text = "Test" };
|
||||
var args = new Microsoft.Maui.Platform.Linux.Services.DragEventArgs(dragData, 100, 200);
|
||||
|
||||
Assert.Equal(dragData, args.Data);
|
||||
Assert.Equal(100, args.X);
|
||||
Assert.Equal(200, args.Y);
|
||||
Assert.False(args.Accepted);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Accepted_CanBeSet()
|
||||
{
|
||||
var args = new Microsoft.Maui.Platform.Linux.Services.DragEventArgs(new DragData(), 0, 0);
|
||||
|
||||
args.Accepted = true;
|
||||
|
||||
Assert.True(args.Accepted);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowedAction_CanBeSet()
|
||||
{
|
||||
var args = new Microsoft.Maui.Platform.Linux.Services.DragEventArgs(new DragData(), 0, 0);
|
||||
|
||||
args.AllowedAction = DragAction.Move;
|
||||
|
||||
Assert.Equal(DragAction.Move, args.AllowedAction);
|
||||
}
|
||||
}
|
||||
|
||||
public class LinuxDropEventArgsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsProperties()
|
||||
{
|
||||
var dragData = new DragData();
|
||||
var args = new Microsoft.Maui.Platform.Linux.Services.DropEventArgs(dragData, "dropped content");
|
||||
|
||||
Assert.Equal(dragData, args.Data);
|
||||
Assert.Equal("dropped content", args.DroppedData);
|
||||
Assert.False(args.Handled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Handled_CanBeSet()
|
||||
{
|
||||
var args = new Microsoft.Maui.Platform.Linux.Services.DropEventArgs(new DragData(), null);
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
Assert.True(args.Handled);
|
||||
}
|
||||
}
|
||||
|
||||
public class GlobalHotkeyServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_DoesNotThrow()
|
||||
{
|
||||
var service = new GlobalHotkeyService();
|
||||
|
||||
Assert.NotNull(service);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HotkeyPressedEvent_CanBeSubscribed()
|
||||
{
|
||||
var service = new GlobalHotkeyService();
|
||||
bool eventRaised = false;
|
||||
|
||||
service.HotkeyPressed += (s, e) => eventRaised = true;
|
||||
|
||||
Assert.False(eventRaised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnregisterAll_WhenNoRegistrations_DoesNotThrow()
|
||||
{
|
||||
var service = new GlobalHotkeyService();
|
||||
|
||||
service.UnregisterAll();
|
||||
|
||||
// Should not throw
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dispose_CanBeCalled()
|
||||
{
|
||||
var service = new GlobalHotkeyService();
|
||||
|
||||
service.Dispose();
|
||||
|
||||
// Should not throw
|
||||
}
|
||||
}
|
||||
|
||||
public class HotkeyEventArgsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsProperties()
|
||||
{
|
||||
var args = new HotkeyEventArgs(1, HotkeyKey.A, HotkeyModifiers.Control);
|
||||
|
||||
Assert.Equal(1, args.Id);
|
||||
Assert.Equal(HotkeyKey.A, args.Key);
|
||||
Assert.Equal(HotkeyModifiers.Control, args.Modifiers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModifiersCanBeCombined()
|
||||
{
|
||||
var modifiers = HotkeyModifiers.Control | HotkeyModifiers.Shift;
|
||||
var args = new HotkeyEventArgs(1, HotkeyKey.S, modifiers);
|
||||
|
||||
Assert.True(args.Modifiers.HasFlag(HotkeyModifiers.Control));
|
||||
Assert.True(args.Modifiers.HasFlag(HotkeyModifiers.Shift));
|
||||
}
|
||||
}
|
||||
|
||||
public class HotkeyModifiersTests
|
||||
{
|
||||
[Fact]
|
||||
public void None_IsZero()
|
||||
{
|
||||
Assert.Equal(0, (int)HotkeyModifiers.None);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllModifiers_AreFlagBased()
|
||||
{
|
||||
var all = HotkeyModifiers.Shift | HotkeyModifiers.Control | HotkeyModifiers.Alt | HotkeyModifiers.Super;
|
||||
|
||||
Assert.True(all.HasFlag(HotkeyModifiers.Shift));
|
||||
Assert.True(all.HasFlag(HotkeyModifiers.Control));
|
||||
Assert.True(all.HasFlag(HotkeyModifiers.Alt));
|
||||
Assert.True(all.HasFlag(HotkeyModifiers.Super));
|
||||
}
|
||||
}
|
||||
|
||||
public class HotkeyKeyTests
|
||||
{
|
||||
[Fact]
|
||||
public void Letters_HaveCorrectValues()
|
||||
{
|
||||
Assert.Equal((uint)0x61, (uint)HotkeyKey.A);
|
||||
Assert.Equal((uint)0x7A, (uint)HotkeyKey.Z);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FunctionKeys_HaveCorrectValues()
|
||||
{
|
||||
Assert.Equal((uint)0xFFBE, (uint)HotkeyKey.F1);
|
||||
Assert.Equal((uint)0xFFC9, (uint)HotkeyKey.F12);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpecialKeys_HaveCorrectValues()
|
||||
{
|
||||
Assert.Equal((uint)0xFF1B, (uint)HotkeyKey.Escape);
|
||||
Assert.Equal((uint)0x20, (uint)HotkeyKey.Space);
|
||||
Assert.Equal((uint)0xFF0D, (uint)HotkeyKey.Return);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrowKeys_HaveCorrectValues()
|
||||
{
|
||||
Assert.Equal((uint)0xFF51, (uint)HotkeyKey.Left);
|
||||
Assert.Equal((uint)0xFF52, (uint)HotkeyKey.Up);
|
||||
Assert.Equal((uint)0xFF53, (uint)HotkeyKey.Right);
|
||||
Assert.Equal((uint)0xFF54, (uint)HotkeyKey.Down);
|
||||
}
|
||||
}
|
||||
140
tests/Views/SkiaButtonTests.cs
Normal file
140
tests/Views/SkiaButtonTests.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using FluentAssertions;
|
||||
using Microsoft.Maui.Platform;
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Maui.Controls.Linux.Tests.Views;
|
||||
|
||||
public class SkiaButtonTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsDefaultValues()
|
||||
{
|
||||
// Arrange & Act
|
||||
var button = new SkiaButton();
|
||||
|
||||
// Assert
|
||||
button.Text.Should().BeEmpty();
|
||||
button.IsEnabled.Should().BeTrue();
|
||||
button.IsFocusable.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Text_WhenSet_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var button = new SkiaButton();
|
||||
|
||||
// Act
|
||||
button.Text = "Click Me";
|
||||
|
||||
// Assert
|
||||
button.Text.Should().Be("Click Me");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Measure_ReturnsMinimumSize()
|
||||
{
|
||||
// Arrange
|
||||
var button = new SkiaButton { Text = "Test" };
|
||||
|
||||
// Act
|
||||
var size = button.Measure(new SKSize(1000, 1000));
|
||||
|
||||
// Assert
|
||||
size.Width.Should().BeGreaterThan(0);
|
||||
size.Height.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Measure_ReturnsPositiveSize()
|
||||
{
|
||||
// Arrange
|
||||
var button = new SkiaButton
|
||||
{
|
||||
Text = "Test",
|
||||
RequestedWidth = 200,
|
||||
RequestedHeight = 50
|
||||
};
|
||||
|
||||
// Act
|
||||
var size = button.Measure(new SKSize(1000, 1000));
|
||||
|
||||
// Assert - Measure returns content-based size
|
||||
size.Width.Should().BeGreaterThan(0);
|
||||
size.Height.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_WhenFalse_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var button = new SkiaButton { Text = "Test" };
|
||||
|
||||
// Act
|
||||
button.IsEnabled = false;
|
||||
|
||||
// Assert
|
||||
button.IsEnabled.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clicked_EventCanBeSubscribed()
|
||||
{
|
||||
// Arrange
|
||||
var button = new SkiaButton { Text = "Test" };
|
||||
var eventSubscribed = false;
|
||||
|
||||
// Act
|
||||
button.Clicked += (s, e) => eventSubscribed = true;
|
||||
|
||||
// Assert - Just verify we can subscribe without error
|
||||
eventSubscribed.Should().BeFalse(); // Not raised yet, just subscribed
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Draw_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var button = new SkiaButton { Text = "Test" };
|
||||
button.Bounds = new SKRect(0, 0, 100, 40);
|
||||
|
||||
using var surface = SKSurface.Create(new SKImageInfo(200, 100));
|
||||
var canvas = surface.Canvas;
|
||||
|
||||
// Act & Assert
|
||||
var exception = Record.Exception(() => button.Draw(canvas));
|
||||
exception.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TextColor_WhenSet_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var button = new SkiaButton();
|
||||
var color = new SKColor(255, 0, 0);
|
||||
|
||||
// Act
|
||||
button.TextColor = color;
|
||||
|
||||
// Assert
|
||||
button.TextColor.Should().Be(color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BackgroundColor_WhenSet_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var button = new SkiaButton();
|
||||
var color = new SKColor(0, 255, 0);
|
||||
|
||||
// Act
|
||||
button.BackgroundColor = color;
|
||||
|
||||
// Assert
|
||||
button.BackgroundColor.Should().Be(color);
|
||||
}
|
||||
}
|
||||
266
tests/Views/SkiaCarouselViewTests.cs
Normal file
266
tests/Views/SkiaCarouselViewTests.cs
Normal file
@@ -0,0 +1,266 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Tests;
|
||||
|
||||
public class SkiaCarouselViewTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
Assert.Equal(0, carousel.Position);
|
||||
Assert.False(carousel.Loop);
|
||||
Assert.Equal(0f, carousel.PeekAreaInsets);
|
||||
Assert.Equal(0, carousel.ItemCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Position_CanBeSet()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item1" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item2" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item3" });
|
||||
|
||||
carousel.Position = 2;
|
||||
|
||||
Assert.Equal(2, carousel.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Position_RaisesPositionChangedEvent()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item1" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item2" });
|
||||
int eventRaised = 0;
|
||||
int previousPos = -1;
|
||||
int currentPos = -1;
|
||||
|
||||
carousel.PositionChanged += (s, e) =>
|
||||
{
|
||||
eventRaised++;
|
||||
previousPos = e.PreviousPosition;
|
||||
currentPos = e.CurrentPosition;
|
||||
};
|
||||
|
||||
carousel.Position = 1;
|
||||
|
||||
Assert.Equal(1, eventRaised);
|
||||
Assert.Equal(0, previousPos);
|
||||
Assert.Equal(1, currentPos);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Loop_CanBeEnabled()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
carousel.Loop = true;
|
||||
|
||||
Assert.True(carousel.Loop);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PeekAreaInsets_CanBeSet()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
carousel.PeekAreaInsets = 20f;
|
||||
|
||||
Assert.Equal(20f, carousel.PeekAreaInsets);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddItem_IncreasesItemCount()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item1" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item2" });
|
||||
|
||||
Assert.Equal(2, carousel.ItemCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveItem_DecreasesItemCount()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
var item = new SkiaLabel { Text = "Item1" };
|
||||
carousel.AddItem(item);
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item2" });
|
||||
|
||||
carousel.RemoveItem(item);
|
||||
|
||||
Assert.Equal(1, carousel.ItemCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClearItems_RemovesAllItems()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item1" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item2" });
|
||||
|
||||
carousel.ClearItems();
|
||||
|
||||
Assert.Equal(0, carousel.ItemCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScrollTo_UpdatesPosition()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
carousel.AddItem(new SkiaLabel { Text = "A" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "B" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "C" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "D" });
|
||||
|
||||
carousel.ScrollTo(2);
|
||||
|
||||
Assert.Equal(2, carousel.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScrollTo_WithAnimation_UpdatesPosition()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
carousel.AddItem(new SkiaLabel { Text = "A" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "B" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "C" });
|
||||
|
||||
carousel.ScrollTo(1, animate: true);
|
||||
|
||||
Assert.Equal(1, carousel.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsSwipeEnabled_DefaultsToTrue()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
Assert.True(carousel.IsSwipeEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsSwipeEnabled_CanBeDisabled()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
carousel.IsSwipeEnabled = false;
|
||||
|
||||
Assert.False(carousel.IsSwipeEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowIndicators_DefaultsToTrue()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
Assert.True(carousel.ShowIndicators);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowIndicators_CanBeDisabled()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
carousel.ShowIndicators = false;
|
||||
|
||||
Assert.False(carousel.ShowIndicators);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndicatorColor_CanBeSet()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
carousel.IndicatorColor = SKColors.Gray;
|
||||
|
||||
Assert.Equal(SKColors.Gray, carousel.IndicatorColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectedIndicatorColor_CanBeSet()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
carousel.SelectedIndicatorColor = SKColors.Blue;
|
||||
|
||||
Assert.Equal(SKColors.Blue, carousel.SelectedIndicatorColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScrolledEvent_CanBeSubscribed()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
carousel.AddItem(new SkiaLabel { Text = "1" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "2" });
|
||||
bool subscribed = false;
|
||||
|
||||
carousel.Scrolled += (s, e) => subscribed = true;
|
||||
|
||||
Assert.NotNull(carousel); // Event can be subscribed
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItemSpacing_DefaultsToZero()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
Assert.Equal(0f, carousel.ItemSpacing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItemSpacing_CanBeSet()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
|
||||
carousel.ItemSpacing = 16f;
|
||||
|
||||
Assert.Equal(16f, carousel.ItemSpacing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Position_NotChangedWhenOutOfRange()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item1" });
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item2" });
|
||||
carousel.Position = 1;
|
||||
|
||||
carousel.Position = 10; // Out of range
|
||||
|
||||
// Position stays at previous valid value or is clamped
|
||||
Assert.True(carousel.Position >= 0 && carousel.Position < carousel.ItemCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HitTest_ReturnsCorrectView()
|
||||
{
|
||||
var carousel = new SkiaCarouselView();
|
||||
carousel.AddItem(new SkiaLabel { Text = "Item" });
|
||||
carousel.Arrange(new SKRect(0, 0, 300, 200));
|
||||
|
||||
var hit = carousel.HitTest(150, 100);
|
||||
|
||||
Assert.NotNull(hit);
|
||||
}
|
||||
}
|
||||
|
||||
public class PositionChangedEventArgsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsProperties()
|
||||
{
|
||||
var args = new PositionChangedEventArgs(0, 2);
|
||||
|
||||
Assert.Equal(0, args.PreviousPosition);
|
||||
Assert.Equal(2, args.CurrentPosition);
|
||||
}
|
||||
}
|
||||
190
tests/Views/SkiaEntryTests.cs
Normal file
190
tests/Views/SkiaEntryTests.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using FluentAssertions;
|
||||
using Microsoft.Maui.Platform;
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Maui.Controls.Linux.Tests.Views;
|
||||
|
||||
public class SkiaEntryTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsDefaultValues()
|
||||
{
|
||||
// Arrange & Act
|
||||
var entry = new SkiaEntry();
|
||||
|
||||
// Assert
|
||||
entry.Text.Should().BeEmpty();
|
||||
entry.Placeholder.Should().BeEmpty();
|
||||
entry.IsEnabled.Should().BeTrue();
|
||||
entry.IsReadOnly.Should().BeFalse();
|
||||
entry.IsFocusable.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Text_WhenSet_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry();
|
||||
|
||||
// Act
|
||||
entry.Text = "Hello World";
|
||||
|
||||
// Assert
|
||||
entry.Text.Should().Be("Hello World");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Text_WhenSet_RaisesTextChangedEvent()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry();
|
||||
string? oldText = null;
|
||||
string? newText = null;
|
||||
entry.TextChanged += (s, e) =>
|
||||
{
|
||||
oldText = e.OldTextValue;
|
||||
newText = e.NewTextValue;
|
||||
};
|
||||
|
||||
// Act
|
||||
entry.Text = "Test";
|
||||
|
||||
// Assert
|
||||
oldText.Should().BeEmpty();
|
||||
newText.Should().Be("Test");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Placeholder_WhenSet_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry();
|
||||
|
||||
// Act
|
||||
entry.Placeholder = "Enter text...";
|
||||
|
||||
// Assert
|
||||
entry.Placeholder.Should().Be("Enter text...");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsPassword_WhenTrue_MasksText()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry
|
||||
{
|
||||
Text = "secret",
|
||||
IsPassword = true
|
||||
};
|
||||
|
||||
// Assert
|
||||
entry.IsPassword.Should().BeTrue();
|
||||
// The actual masking is done in Draw, but we verify the property is set
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MaxLength_CanBeSet()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry();
|
||||
|
||||
// Act
|
||||
entry.MaxLength = 5;
|
||||
|
||||
// Assert
|
||||
entry.MaxLength.Should().Be(5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnTextInput_ModifiesText()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry { Text = "Hello" };
|
||||
entry.Bounds = new SKRect(0, 0, 200, 40);
|
||||
entry.OnFocusGained();
|
||||
var originalLength = entry.Text.Length;
|
||||
|
||||
// Act
|
||||
entry.OnTextInput(new TextInputEventArgs(" World"));
|
||||
|
||||
// Assert - Text is modified (inserted at cursor position)
|
||||
entry.Text.Length.Should().BeGreaterThan(originalLength);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnKeyDown_ReturnsKeyEvent()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry { Text = "Hello" };
|
||||
entry.Bounds = new SKRect(0, 0, 200, 40);
|
||||
entry.OnFocusGained();
|
||||
|
||||
// Act - Verify OnKeyDown doesn't throw
|
||||
var exception = Record.Exception(() => entry.OnKeyDown(new KeyEventArgs(Key.Backspace)));
|
||||
|
||||
// Assert
|
||||
exception.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnKeyDown_WhenReadOnly_TextRemainsSame()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry { Text = "Hello", IsReadOnly = true };
|
||||
var originalText = entry.Text;
|
||||
entry.Bounds = new SKRect(0, 0, 200, 40);
|
||||
entry.OnFocusGained();
|
||||
|
||||
// Act
|
||||
entry.OnKeyDown(new KeyEventArgs(Key.Backspace));
|
||||
|
||||
// Assert - Text should remain unchanged
|
||||
entry.Text.Should().Be(originalText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CursorPosition_CanBeSet()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry { Text = "Hello World" };
|
||||
|
||||
// Act
|
||||
entry.CursorPosition = 5;
|
||||
|
||||
// Assert
|
||||
entry.CursorPosition.Should().Be(5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Draw_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry { Text = "Test", Placeholder = "Enter..." };
|
||||
entry.Bounds = new SKRect(0, 0, 200, 40);
|
||||
|
||||
using var surface = SKSurface.Create(new SKImageInfo(300, 100));
|
||||
var canvas = surface.Canvas;
|
||||
|
||||
// Act & Assert
|
||||
var exception = Record.Exception(() => entry.Draw(canvas));
|
||||
exception.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectAll_SelectsEntireText()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new SkiaEntry { Text = "Hello World" };
|
||||
entry.OnFocusGained();
|
||||
|
||||
// Act
|
||||
entry.SelectAll();
|
||||
|
||||
// Assert
|
||||
entry.SelectionLength.Should().Be(11);
|
||||
}
|
||||
}
|
||||
271
tests/Views/SkiaIndicatorViewTests.cs
Normal file
271
tests/Views/SkiaIndicatorViewTests.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Tests;
|
||||
|
||||
public class SkiaIndicatorViewTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
Assert.Equal(0, indicator.Count);
|
||||
Assert.Equal(0, indicator.Position);
|
||||
Assert.Equal(IndicatorShape.Circle, indicator.IndicatorShape);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Count_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.Count = 5;
|
||||
|
||||
Assert.Equal(5, indicator.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Position_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
indicator.Count = 5;
|
||||
|
||||
indicator.Position = 3;
|
||||
|
||||
Assert.Equal(3, indicator.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Position_ClampedToCount()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
indicator.Count = 3;
|
||||
|
||||
indicator.Position = 10;
|
||||
|
||||
Assert.Equal(2, indicator.Position); // Clamped to max (Count - 1)
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Position_ClampedToZero()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
indicator.Count = 3;
|
||||
|
||||
indicator.Position = -5;
|
||||
|
||||
Assert.Equal(0, indicator.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndicatorColor_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.IndicatorColor = SKColors.Gray;
|
||||
|
||||
Assert.Equal(SKColors.Gray, indicator.IndicatorColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectedIndicatorColor_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.SelectedIndicatorColor = SKColors.Blue;
|
||||
|
||||
Assert.Equal(SKColors.Blue, indicator.SelectedIndicatorColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndicatorSize_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.IndicatorSize = 12f;
|
||||
|
||||
Assert.Equal(12f, indicator.IndicatorSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectedIndicatorSize_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.SelectedIndicatorSize = 16f;
|
||||
|
||||
Assert.Equal(16f, indicator.SelectedIndicatorSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndicatorSpacing_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.IndicatorSpacing = 10f;
|
||||
|
||||
Assert.Equal(10f, indicator.IndicatorSpacing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndicatorShape_CanBeSetToSquare()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.IndicatorShape = IndicatorShape.Square;
|
||||
|
||||
Assert.Equal(IndicatorShape.Square, indicator.IndicatorShape);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndicatorShape_CanBeSetToRoundedSquare()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.IndicatorShape = IndicatorShape.RoundedSquare;
|
||||
|
||||
Assert.Equal(IndicatorShape.RoundedSquare, indicator.IndicatorShape);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndicatorShape_CanBeSetToDiamond()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.IndicatorShape = IndicatorShape.Diamond;
|
||||
|
||||
Assert.Equal(IndicatorShape.Diamond, indicator.IndicatorShape);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowBorder_DefaultsToFalse()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
Assert.False(indicator.ShowBorder);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowBorder_CanBeEnabled()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.ShowBorder = true;
|
||||
|
||||
Assert.True(indicator.ShowBorder);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BorderColor_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.BorderColor = SKColors.Black;
|
||||
|
||||
Assert.Equal(SKColors.Black, indicator.BorderColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BorderWidth_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.BorderWidth = 2f;
|
||||
|
||||
Assert.Equal(2f, indicator.BorderWidth);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MaximumVisible_DefaultValue()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
Assert.Equal(10, indicator.MaximumVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MaximumVisible_CanBeSet()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.MaximumVisible = 5;
|
||||
|
||||
Assert.Equal(5, indicator.MaximumVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HideSingle_DefaultsToTrue()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
Assert.True(indicator.HideSingle);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HideSingle_CanBeDisabled()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
indicator.HideSingle = false;
|
||||
|
||||
Assert.False(indicator.HideSingle);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Count_AdjustsPosition_WhenReduced()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
indicator.Count = 5;
|
||||
indicator.Position = 4;
|
||||
|
||||
indicator.Count = 3;
|
||||
|
||||
Assert.Equal(2, indicator.Position); // Adjusted to max valid
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HitTest_OnIndicator_ReturnsView()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
indicator.Count = 5;
|
||||
indicator.IndicatorSize = 10f;
|
||||
indicator.IndicatorSpacing = 8f;
|
||||
indicator.Arrange(new SKRect(0, 0, 200, 20));
|
||||
|
||||
var hit = indicator.HitTest(100, 10);
|
||||
|
||||
Assert.NotNull(hit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsVisible_DefaultsToTrue()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
Assert.True(indicator.IsVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_DefaultsToTrue()
|
||||
{
|
||||
var indicator = new SkiaIndicatorView();
|
||||
|
||||
Assert.True(indicator.IsEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
public class IndicatorShapeTests
|
||||
{
|
||||
[Fact]
|
||||
public void AllShapesAreDefined()
|
||||
{
|
||||
Assert.Equal(IndicatorShape.Circle, (IndicatorShape)0);
|
||||
Assert.Equal(IndicatorShape.Square, (IndicatorShape)1);
|
||||
Assert.Equal(IndicatorShape.RoundedSquare, (IndicatorShape)2);
|
||||
Assert.Equal(IndicatorShape.Diamond, (IndicatorShape)3);
|
||||
}
|
||||
}
|
||||
366
tests/Views/SkiaMenuBarTests.cs
Normal file
366
tests/Views/SkiaMenuBarTests.cs
Normal file
@@ -0,0 +1,366 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Tests;
|
||||
|
||||
public class SkiaMenuBarTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
|
||||
Assert.Empty(menuBar.Items);
|
||||
Assert.Equal(28f, menuBar.BarHeight);
|
||||
Assert.Equal(13f, menuBar.FontSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Items_CanAddMenuBarItem()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
var item = new MenuBarItem { Text = "File" };
|
||||
|
||||
menuBar.Items.Add(item);
|
||||
|
||||
Assert.Single(menuBar.Items);
|
||||
Assert.Equal("File", menuBar.Items[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MenuBarItem_CanAddMenuItems()
|
||||
{
|
||||
var menuBarItem = new MenuBarItem { Text = "Edit" };
|
||||
menuBarItem.Items.Add(new MenuItem { Text = "Cut" });
|
||||
menuBarItem.Items.Add(new MenuItem { Text = "Copy" });
|
||||
menuBarItem.Items.Add(new MenuItem { Text = "Paste" });
|
||||
|
||||
Assert.Equal(3, menuBarItem.Items.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MenuItem_CanHaveShortcut()
|
||||
{
|
||||
var item = new MenuItem { Text = "Save", Shortcut = "Ctrl+S" };
|
||||
|
||||
Assert.Equal("Ctrl+S", item.Shortcut);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MenuItem_CanBeSeparator()
|
||||
{
|
||||
var item = new MenuItem { IsSeparator = true };
|
||||
|
||||
Assert.True(item.IsSeparator);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MenuItem_IsEnabled_DefaultsToTrue()
|
||||
{
|
||||
var item = new MenuItem { Text = "Test" };
|
||||
|
||||
Assert.True(item.IsEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MenuItem_CanBeDisabled()
|
||||
{
|
||||
var item = new MenuItem { Text = "Test", IsEnabled = false };
|
||||
|
||||
Assert.False(item.IsEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MenuItem_CanBeChecked()
|
||||
{
|
||||
var item = new MenuItem { Text = "Option", IsChecked = true };
|
||||
|
||||
Assert.True(item.IsChecked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MenuItem_CanHaveIcon()
|
||||
{
|
||||
var item = new MenuItem { Text = "Open", IconSource = "open.png" };
|
||||
|
||||
Assert.Equal("open.png", item.IconSource);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MenuItem_CanHaveSubItems()
|
||||
{
|
||||
var item = new MenuItem { Text = "Recent" };
|
||||
item.SubItems.Add(new MenuItem { Text = "File1.txt" });
|
||||
item.SubItems.Add(new MenuItem { Text = "File2.txt" });
|
||||
|
||||
Assert.Equal(2, item.SubItems.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MenuItem_ClickedEvent_CanBeSubscribed()
|
||||
{
|
||||
var item = new MenuItem { Text = "Test" };
|
||||
bool clicked = false;
|
||||
|
||||
item.Clicked += (s, e) => clicked = true;
|
||||
|
||||
Assert.False(clicked); // Event not raised yet
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BarHeight_CanBeSet()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
|
||||
menuBar.BarHeight = 32f;
|
||||
|
||||
Assert.Equal(32f, menuBar.BarHeight);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FontSize_CanBeSet()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
|
||||
menuBar.FontSize = 14f;
|
||||
|
||||
Assert.Equal(14f, menuBar.FontSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItemPadding_CanBeSet()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
|
||||
menuBar.ItemPadding = 16f;
|
||||
|
||||
Assert.Equal(16f, menuBar.ItemPadding);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BackgroundColor_CanBeSet()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
|
||||
menuBar.BackgroundColor = SKColors.White;
|
||||
|
||||
Assert.Equal(SKColors.White, menuBar.BackgroundColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TextColor_CanBeSet()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
|
||||
menuBar.TextColor = SKColors.Black;
|
||||
|
||||
Assert.Equal(SKColors.Black, menuBar.TextColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HoverBackgroundColor_CanBeSet()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
|
||||
menuBar.HoverBackgroundColor = SKColors.LightGray;
|
||||
|
||||
Assert.Equal(SKColors.LightGray, menuBar.HoverBackgroundColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ActiveBackgroundColor_CanBeSet()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
|
||||
menuBar.ActiveBackgroundColor = SKColors.DarkGray;
|
||||
|
||||
Assert.Equal(SKColors.DarkGray, menuBar.ActiveBackgroundColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Measure_ReturnsBarHeight()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
menuBar.BarHeight = 30f;
|
||||
|
||||
var size = menuBar.Measure(new SKSize(800, 600));
|
||||
|
||||
Assert.Equal(30f, size.Height);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Measure_ReturnsAvailableWidth()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
|
||||
var size = menuBar.Measure(new SKSize(800, 600));
|
||||
|
||||
Assert.Equal(800f, size.Width);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HitTest_WithinBounds_ReturnsMenuBar()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
menuBar.Arrange(new SKRect(0, 0, 800, 28));
|
||||
|
||||
var hit = menuBar.HitTest(400, 14);
|
||||
|
||||
Assert.Equal(menuBar, hit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HitTest_OutsideBounds_ReturnsNull()
|
||||
{
|
||||
var menuBar = new SkiaMenuBar();
|
||||
menuBar.Arrange(new SKRect(0, 0, 800, 28));
|
||||
|
||||
var hit = menuBar.HitTest(400, 50);
|
||||
|
||||
Assert.Null(hit);
|
||||
}
|
||||
}
|
||||
|
||||
public class SkiaMenuFlyoutTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
Assert.Empty(flyout.Items);
|
||||
Assert.Equal(13f, flyout.FontSize);
|
||||
Assert.Equal(28f, flyout.ItemHeight);
|
||||
Assert.Equal(180f, flyout.MinWidth);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Items_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
flyout.Items = new List<MenuItem>
|
||||
{
|
||||
new() { Text = "Item1" },
|
||||
new() { Text = "Item2" }
|
||||
};
|
||||
|
||||
Assert.Equal(2, flyout.Items.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Position_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
flyout.Position = new SKPoint(100, 200);
|
||||
|
||||
Assert.Equal(100, flyout.Position.X);
|
||||
Assert.Equal(200, flyout.Position.Y);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BackgroundColor_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
flyout.BackgroundColor = SKColors.White;
|
||||
|
||||
Assert.Equal(SKColors.White, flyout.BackgroundColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TextColor_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
flyout.TextColor = SKColors.Black;
|
||||
|
||||
Assert.Equal(SKColors.Black, flyout.TextColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisabledTextColor_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
flyout.DisabledTextColor = new SKColor(160, 160, 160);
|
||||
|
||||
Assert.Equal(new SKColor(160, 160, 160), flyout.DisabledTextColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HoverBackgroundColor_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
flyout.HoverBackgroundColor = SKColors.LightBlue;
|
||||
|
||||
Assert.Equal(SKColors.LightBlue, flyout.HoverBackgroundColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SeparatorColor_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
flyout.SeparatorColor = SKColors.Gray;
|
||||
|
||||
Assert.Equal(SKColors.Gray, flyout.SeparatorColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItemHeight_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
flyout.ItemHeight = 32f;
|
||||
|
||||
Assert.Equal(32f, flyout.ItemHeight);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SeparatorHeight_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
flyout.SeparatorHeight = 12f;
|
||||
|
||||
Assert.Equal(12f, flyout.SeparatorHeight);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MinWidth_CanBeSet()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
|
||||
flyout.MinWidth = 200f;
|
||||
|
||||
Assert.Equal(200f, flyout.MinWidth);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItemClickedEvent_CanBeSubscribed()
|
||||
{
|
||||
var flyout = new SkiaMenuFlyout();
|
||||
MenuItem? clickedItem = null;
|
||||
|
||||
flyout.ItemClicked += (s, e) => clickedItem = e.Item;
|
||||
|
||||
Assert.Null(clickedItem);
|
||||
}
|
||||
}
|
||||
|
||||
public class MenuItemClickedEventArgsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsItem()
|
||||
{
|
||||
var item = new MenuItem { Text = "Test" };
|
||||
var args = new MenuItemClickedEventArgs(item);
|
||||
|
||||
Assert.Equal(item, args.Item);
|
||||
}
|
||||
}
|
||||
160
tests/Views/SkiaRefreshViewTests.cs
Normal file
160
tests/Views/SkiaRefreshViewTests.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Tests;
|
||||
|
||||
public class SkiaRefreshViewTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
Assert.False(refreshView.IsRefreshing);
|
||||
Assert.Null(refreshView.Content);
|
||||
Assert.True(refreshView.IsEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsRefreshing_CanBeSet()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
refreshView.IsRefreshing = true;
|
||||
|
||||
Assert.True(refreshView.IsRefreshing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_CanBeSet()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
var content = new SkiaLabel { Text = "Test" };
|
||||
|
||||
refreshView.Content = content;
|
||||
|
||||
Assert.Equal(content, refreshView.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_AddsChildToTree()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
var content = new SkiaLabel { Text = "Test" };
|
||||
|
||||
refreshView.Content = content;
|
||||
|
||||
Assert.Equal(refreshView, content.Parent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_RemovesPreviousChild()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
var content1 = new SkiaLabel { Text = "First" };
|
||||
var content2 = new SkiaLabel { Text = "Second" };
|
||||
|
||||
refreshView.Content = content1;
|
||||
refreshView.Content = content2;
|
||||
|
||||
Assert.Null(content1.Parent);
|
||||
Assert.Equal(refreshView, content2.Parent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefreshThreshold_DefaultValue()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
Assert.Equal(80f, refreshView.RefreshThreshold);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefreshThreshold_CanBeSet()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
refreshView.RefreshThreshold = 100f;
|
||||
|
||||
Assert.Equal(100f, refreshView.RefreshThreshold);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefreshColor_DefaultsToBlue()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
Assert.Equal(new SKColor(33, 150, 243), refreshView.RefreshColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefreshColor_CanBeSet()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
refreshView.RefreshColor = SKColors.Red;
|
||||
|
||||
Assert.Equal(SKColors.Red, refreshView.RefreshColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefreshBackgroundColor_DefaultsToWhite()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
Assert.Equal(SKColors.White, refreshView.RefreshBackgroundColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefreshBackgroundColor_CanBeSet()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
refreshView.RefreshBackgroundColor = SKColors.LightGray;
|
||||
|
||||
Assert.Equal(SKColors.LightGray, refreshView.RefreshBackgroundColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefreshingEvent_CanBeSubscribed()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
bool eventRaised = false;
|
||||
|
||||
refreshView.Refreshing += (s, e) => eventRaised = true;
|
||||
|
||||
Assert.False(eventRaised); // Not raised yet
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HitTest_ReturnsCorrectView()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
var content = new SkiaLabel { Text = "Test" };
|
||||
refreshView.Content = content;
|
||||
refreshView.Arrange(new SKRect(0, 0, 200, 400));
|
||||
|
||||
var hit = refreshView.HitTest(100, 200);
|
||||
|
||||
Assert.NotNull(hit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsVisible_DefaultsToTrue()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
Assert.True(refreshView.IsVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_DefaultsToTrue()
|
||||
{
|
||||
var refreshView = new SkiaRefreshView();
|
||||
|
||||
Assert.True(refreshView.IsEnabled);
|
||||
}
|
||||
}
|
||||
162
tests/Views/SkiaScrollViewTests.cs
Normal file
162
tests/Views/SkiaScrollViewTests.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using FluentAssertions;
|
||||
using Microsoft.Maui.Platform;
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Maui.Controls.Linux.Tests.Views;
|
||||
|
||||
public class SkiaScrollViewTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsDefaultValues()
|
||||
{
|
||||
// Arrange & Act
|
||||
var scrollView = new SkiaScrollView();
|
||||
|
||||
// Assert
|
||||
scrollView.ScrollX.Should().Be(0);
|
||||
scrollView.ScrollY.Should().Be(0);
|
||||
scrollView.Content.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_WhenSet_UpdatesParent()
|
||||
{
|
||||
// Arrange
|
||||
var scrollView = new SkiaScrollView();
|
||||
var content = new SkiaStackLayout();
|
||||
|
||||
// Act
|
||||
scrollView.Content = content;
|
||||
|
||||
// Assert
|
||||
scrollView.Content.Should().Be(content);
|
||||
content.Parent.Should().Be(scrollView);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScrollY_WhenSet_ClampsToValidRange()
|
||||
{
|
||||
// Arrange
|
||||
var scrollView = new SkiaScrollView();
|
||||
var content = new SkiaStackLayout();
|
||||
content.AddChild(new SkiaButton { Text = "1", RequestedHeight = 100 });
|
||||
content.AddChild(new SkiaButton { Text = "2", RequestedHeight = 100 });
|
||||
scrollView.Content = content;
|
||||
scrollView.Measure(new SKSize(200, 100)); // Viewport smaller than content
|
||||
scrollView.Arrange(new SKRect(0, 0, 200, 100));
|
||||
|
||||
// Act - Try to scroll below 0
|
||||
scrollView.ScrollY = -50;
|
||||
|
||||
// Assert
|
||||
scrollView.ScrollY.Should().BeGreaterOrEqualTo(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnScroll_UpdatesScrollOffset()
|
||||
{
|
||||
// Arrange
|
||||
var scrollView = new SkiaScrollView();
|
||||
var content = new SkiaStackLayout();
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
content.AddChild(new SkiaButton { Text = $"Button {i}", RequestedHeight = 50 });
|
||||
}
|
||||
scrollView.Content = content;
|
||||
scrollView.Measure(new SKSize(200, 300));
|
||||
scrollView.Arrange(new SKRect(0, 0, 200, 300));
|
||||
|
||||
var initialScrollY = scrollView.ScrollY;
|
||||
|
||||
// Act
|
||||
scrollView.OnScroll(new ScrollEventArgs(100, 100, 0, 3)); // Scroll down
|
||||
|
||||
// Assert
|
||||
scrollView.ScrollY.Should().BeGreaterThan(initialScrollY);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HitTest_ReturnsView()
|
||||
{
|
||||
// Arrange
|
||||
var scrollView = new SkiaScrollView();
|
||||
var content = new SkiaStackLayout();
|
||||
var button = new SkiaButton { Text = "Test" };
|
||||
content.AddChild(button);
|
||||
scrollView.Content = content;
|
||||
|
||||
scrollView.Measure(new SKSize(200, 200));
|
||||
scrollView.Arrange(new SKRect(0, 0, 200, 200));
|
||||
|
||||
// Act
|
||||
var hit = scrollView.HitTest(100, 25);
|
||||
|
||||
// Assert - HitTest should return a view within bounds
|
||||
hit.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScrollY_CanBeSet()
|
||||
{
|
||||
// Arrange
|
||||
var scrollView = new SkiaScrollView();
|
||||
var content = new SkiaStackLayout();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
content.AddChild(new SkiaButton { Text = $"Button {i}" });
|
||||
}
|
||||
scrollView.Content = content;
|
||||
|
||||
scrollView.Measure(new SKSize(200, 100));
|
||||
scrollView.Arrange(new SKRect(0, 0, 200, 100));
|
||||
|
||||
// Act
|
||||
scrollView.ScrollY = 50;
|
||||
|
||||
// Assert - ScrollY should be settable
|
||||
scrollView.ScrollY.Should().BeGreaterOrEqualTo(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Draw_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var scrollView = new SkiaScrollView();
|
||||
var content = new SkiaStackLayout();
|
||||
content.AddChild(new SkiaButton { Text = "Test" });
|
||||
scrollView.Content = content;
|
||||
scrollView.Bounds = new SKRect(0, 0, 200, 200);
|
||||
|
||||
using var surface = SKSurface.Create(new SKImageInfo(300, 300));
|
||||
var canvas = surface.Canvas;
|
||||
|
||||
// Act & Assert
|
||||
var exception = Record.Exception(() => scrollView.Draw(canvas));
|
||||
exception.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MaxScrollOffset_CalculatesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var scrollView = new SkiaScrollView();
|
||||
var content = new SkiaStackLayout();
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
content.AddChild(new SkiaButton { Text = $"Button {i}", RequestedHeight = 50 });
|
||||
}
|
||||
scrollView.Content = content;
|
||||
scrollView.Measure(new SKSize(200, 200));
|
||||
scrollView.Arrange(new SKRect(0, 0, 200, 200));
|
||||
|
||||
// Act - Scroll to maximum
|
||||
scrollView.ScrollY = 10000; // Very large value
|
||||
|
||||
// Assert - Should be clamped to content height minus viewport
|
||||
scrollView.ScrollY.Should().BeLessOrEqualTo(1000 - 200); // 20*50 - 200
|
||||
}
|
||||
}
|
||||
160
tests/Views/SkiaSliderTests.cs
Normal file
160
tests/Views/SkiaSliderTests.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using FluentAssertions;
|
||||
using Microsoft.Maui.Platform;
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Maui.Controls.Linux.Tests.Views;
|
||||
|
||||
public class SkiaSliderTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsDefaultValues()
|
||||
{
|
||||
// Arrange & Act
|
||||
var slider = new SkiaSlider();
|
||||
|
||||
// Assert
|
||||
slider.Value.Should().Be(0);
|
||||
slider.Minimum.Should().Be(0);
|
||||
slider.Maximum.Should().Be(100); // Default maximum is 100
|
||||
slider.IsEnabled.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Value_WhenSet_ClampsToRange()
|
||||
{
|
||||
// Arrange
|
||||
var slider = new SkiaSlider { Minimum = 0, Maximum = 100 };
|
||||
|
||||
// Act & Assert - Below minimum
|
||||
slider.Value = -10;
|
||||
slider.Value.Should().Be(0);
|
||||
|
||||
// Act & Assert - Above maximum
|
||||
slider.Value = 150;
|
||||
slider.Value.Should().Be(100);
|
||||
|
||||
// Act & Assert - Within range
|
||||
slider.Value = 50;
|
||||
slider.Value.Should().Be(50);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Value_WhenChanged_RaisesValueChangedEvent()
|
||||
{
|
||||
// Arrange
|
||||
var slider = new SkiaSlider { Minimum = 0, Maximum = 100 };
|
||||
var eventRaised = false;
|
||||
double newValue = 0;
|
||||
slider.ValueChanged += (s, e) =>
|
||||
{
|
||||
eventRaised = true;
|
||||
newValue = slider.Value;
|
||||
};
|
||||
|
||||
// Act
|
||||
slider.Value = 50;
|
||||
|
||||
// Assert
|
||||
eventRaised.Should().BeTrue();
|
||||
newValue.Should().Be(50);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Minimum_WhenSet_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var slider = new SkiaSlider { Minimum = 0, Maximum = 100 };
|
||||
|
||||
// Act
|
||||
slider.Minimum = 20;
|
||||
|
||||
// Assert
|
||||
slider.Minimum.Should().Be(20);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Maximum_WhenSet_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var slider = new SkiaSlider { Minimum = 0, Maximum = 100 };
|
||||
|
||||
// Act
|
||||
slider.Maximum = 50;
|
||||
|
||||
// Assert
|
||||
slider.Maximum.Should().Be(50);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsEnabled_DefaultsToTrue()
|
||||
{
|
||||
// Arrange & Act
|
||||
var slider = new SkiaSlider();
|
||||
|
||||
// Assert
|
||||
slider.IsEnabled.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValueChanged_EventCanBeSubscribed()
|
||||
{
|
||||
// Arrange
|
||||
var slider = new SkiaSlider { Minimum = 0, Maximum = 100 };
|
||||
var eventCount = 0;
|
||||
|
||||
// Act
|
||||
slider.ValueChanged += (s, e) => eventCount++;
|
||||
slider.Value = 50;
|
||||
slider.Value = 75;
|
||||
|
||||
// Assert
|
||||
eventCount.Should().Be(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Draw_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var slider = new SkiaSlider { Value = 50, Minimum = 0, Maximum = 100 };
|
||||
slider.Bounds = new SKRect(0, 0, 200, 40);
|
||||
|
||||
using var surface = SKSurface.Create(new SKImageInfo(300, 100));
|
||||
var canvas = surface.Canvas;
|
||||
|
||||
// Act & Assert
|
||||
var exception = Record.Exception(() => slider.Draw(canvas));
|
||||
exception.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThumbColor_WhenSet_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var slider = new SkiaSlider();
|
||||
var color = new SKColor(255, 0, 0);
|
||||
|
||||
// Act
|
||||
slider.ThumbColor = color;
|
||||
|
||||
// Assert
|
||||
slider.ThumbColor.Should().Be(color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TrackColor_WhenSet_UpdatesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var slider = new SkiaSlider();
|
||||
var color = new SKColor(0, 255, 0);
|
||||
|
||||
// Act
|
||||
slider.TrackColor = color;
|
||||
|
||||
// Assert
|
||||
slider.TrackColor.Should().Be(color);
|
||||
}
|
||||
}
|
||||
200
tests/Views/SkiaStackLayoutTests.cs
Normal file
200
tests/Views/SkiaStackLayoutTests.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using FluentAssertions;
|
||||
using Microsoft.Maui.Platform;
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
using PlatformStackOrientation = Microsoft.Maui.Platform.StackOrientation;
|
||||
|
||||
namespace Microsoft.Maui.Controls.Linux.Tests.Views;
|
||||
|
||||
public class SkiaStackLayoutTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsDefaultValues()
|
||||
{
|
||||
// Arrange & Act
|
||||
var layout = new SkiaStackLayout();
|
||||
|
||||
// Assert
|
||||
layout.Orientation.Should().Be(PlatformStackOrientation.Vertical);
|
||||
layout.Spacing.Should().Be(0);
|
||||
layout.Children.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddChild_AddsToChildren()
|
||||
{
|
||||
// Arrange
|
||||
var layout = new SkiaStackLayout();
|
||||
var button = new SkiaButton { Text = "Test" };
|
||||
|
||||
// Act
|
||||
layout.AddChild(button);
|
||||
|
||||
// Assert
|
||||
layout.Children.Should().Contain(button);
|
||||
button.Parent.Should().Be(layout);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveChild_RemovesFromChildren()
|
||||
{
|
||||
// Arrange
|
||||
var layout = new SkiaStackLayout();
|
||||
var button = new SkiaButton { Text = "Test" };
|
||||
layout.AddChild(button);
|
||||
|
||||
// Act
|
||||
layout.RemoveChild(button);
|
||||
|
||||
// Assert
|
||||
layout.Children.Should().NotContain(button);
|
||||
button.Parent.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Measure_Vertical_ReturnsPositiveSize()
|
||||
{
|
||||
// Arrange
|
||||
var layout = new SkiaStackLayout
|
||||
{
|
||||
Orientation = PlatformStackOrientation.Vertical,
|
||||
Spacing = 10
|
||||
};
|
||||
layout.AddChild(new SkiaButton { Text = "1" });
|
||||
layout.AddChild(new SkiaButton { Text = "2" });
|
||||
layout.AddChild(new SkiaButton { Text = "3" });
|
||||
|
||||
// Act
|
||||
var size = layout.Measure(new SKSize(200, 1000));
|
||||
|
||||
// Assert - Size should account for 3 children with spacing
|
||||
size.Height.Should().BeGreaterThan(0);
|
||||
size.Width.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Measure_Horizontal_ReturnsPositiveSize()
|
||||
{
|
||||
// Arrange
|
||||
var layout = new SkiaStackLayout
|
||||
{
|
||||
Orientation = PlatformStackOrientation.Horizontal,
|
||||
Spacing = 10
|
||||
};
|
||||
layout.AddChild(new SkiaButton { Text = "1" });
|
||||
layout.AddChild(new SkiaButton { Text = "2" });
|
||||
layout.AddChild(new SkiaButton { Text = "3" });
|
||||
|
||||
// Act
|
||||
var size = layout.Measure(new SKSize(1000, 200));
|
||||
|
||||
// Assert - Size should account for 3 children with spacing
|
||||
size.Width.Should().BeGreaterThan(0);
|
||||
size.Height.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Arrange_Vertical_PositionsChildren()
|
||||
{
|
||||
// Arrange
|
||||
var layout = new SkiaStackLayout
|
||||
{
|
||||
Orientation = PlatformStackOrientation.Vertical,
|
||||
Spacing = 10
|
||||
};
|
||||
var button1 = new SkiaButton { Text = "1" };
|
||||
var button2 = new SkiaButton { Text = "2" };
|
||||
layout.AddChild(button1);
|
||||
layout.AddChild(button2);
|
||||
|
||||
// Act
|
||||
layout.Measure(new SKSize(200, 500));
|
||||
layout.Arrange(new SKRect(0, 0, 200, 500));
|
||||
|
||||
// Assert - Button2 should be below Button1
|
||||
button2.Bounds.Top.Should().BeGreaterThan(button1.Bounds.Top);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Arrange_Horizontal_PositionsChildren()
|
||||
{
|
||||
// Arrange
|
||||
var layout = new SkiaStackLayout
|
||||
{
|
||||
Orientation = PlatformStackOrientation.Horizontal,
|
||||
Spacing = 10
|
||||
};
|
||||
var button1 = new SkiaButton { Text = "1" };
|
||||
var button2 = new SkiaButton { Text = "2" };
|
||||
layout.AddChild(button1);
|
||||
layout.AddChild(button2);
|
||||
|
||||
// Act
|
||||
layout.Measure(new SKSize(500, 200));
|
||||
layout.Arrange(new SKRect(0, 0, 500, 200));
|
||||
|
||||
// Assert - Button2 should be to the right of Button1
|
||||
button2.Bounds.Left.Should().BeGreaterThan(button1.Bounds.Left);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Padding_CanBeSet()
|
||||
{
|
||||
// Arrange
|
||||
var layout = new SkiaStackLayout
|
||||
{
|
||||
Orientation = PlatformStackOrientation.Vertical,
|
||||
Padding = new SKRect(20, 20, 20, 20)
|
||||
};
|
||||
var button = new SkiaButton { Text = "Test" };
|
||||
layout.AddChild(button);
|
||||
|
||||
// Act
|
||||
layout.Measure(new SKSize(300, 300));
|
||||
layout.Arrange(new SKRect(0, 0, 300, 300));
|
||||
|
||||
// Assert - Padding property is set
|
||||
layout.Padding.Left.Should().Be(20);
|
||||
layout.Padding.Top.Should().Be(20);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Draw_DrawsAllChildren()
|
||||
{
|
||||
// Arrange
|
||||
var layout = new SkiaStackLayout();
|
||||
layout.AddChild(new SkiaButton { Text = "1" });
|
||||
layout.AddChild(new SkiaButton { Text = "2" });
|
||||
layout.Bounds = new SKRect(0, 0, 200, 200);
|
||||
|
||||
using var surface = SKSurface.Create(new SKImageInfo(300, 300));
|
||||
var canvas = surface.Canvas;
|
||||
|
||||
// Act & Assert
|
||||
var exception = Record.Exception(() => layout.Draw(canvas));
|
||||
exception.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HitTest_ReturnsView()
|
||||
{
|
||||
// Arrange
|
||||
var layout = new SkiaStackLayout { Orientation = PlatformStackOrientation.Vertical };
|
||||
var button1 = new SkiaButton { Text = "1" };
|
||||
var button2 = new SkiaButton { Text = "2" };
|
||||
layout.AddChild(button1);
|
||||
layout.AddChild(button2);
|
||||
|
||||
layout.Measure(new SKSize(200, 200));
|
||||
layout.Arrange(new SKRect(0, 0, 200, 200));
|
||||
|
||||
// Act - Hit test within layout bounds
|
||||
var hit = layout.HitTest(100, 10);
|
||||
|
||||
// Assert - Should return a view (either button1 or layout)
|
||||
hit.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
211
tests/Views/SkiaSwipeViewTests.cs
Normal file
211
tests/Views/SkiaSwipeViewTests.cs
Normal file
@@ -0,0 +1,211 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Tests;
|
||||
|
||||
public class SkiaSwipeViewTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesWithDefaultValues()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
|
||||
Assert.Null(swipeView.Content);
|
||||
Assert.Empty(swipeView.LeftItems);
|
||||
Assert.Empty(swipeView.RightItems);
|
||||
Assert.Empty(swipeView.TopItems);
|
||||
Assert.Empty(swipeView.BottomItems);
|
||||
Assert.Equal(SwipeMode.Reveal, swipeView.Mode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_CanBeSet()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
var content = new SkiaLabel { Text = "Swipeable" };
|
||||
|
||||
swipeView.Content = content;
|
||||
|
||||
Assert.Equal(content, swipeView.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LeftItems_CanAddItems()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
var item = new SwipeItem { Text = "Delete", BackgroundColor = SKColors.Red };
|
||||
|
||||
swipeView.LeftItems.Add(item);
|
||||
|
||||
Assert.Single(swipeView.LeftItems);
|
||||
Assert.Equal("Delete", swipeView.LeftItems[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RightItems_CanAddItems()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
var item = new SwipeItem { Text = "Archive", BackgroundColor = SKColors.Blue };
|
||||
|
||||
swipeView.RightItems.Add(item);
|
||||
|
||||
Assert.Single(swipeView.RightItems);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SwipeItem_InvokedEvent_CanBeSubscribed()
|
||||
{
|
||||
var item = new SwipeItem { Text = "Test" };
|
||||
bool invoked = false;
|
||||
|
||||
item.Invoked += (s, e) => invoked = true;
|
||||
|
||||
Assert.False(invoked); // Event not raised yet
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Open_OpensSwipeInDirection()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
swipeView.RightItems.Add(new SwipeItem { Text = "Delete" });
|
||||
|
||||
swipeView.Open(SwipeDirection.Left);
|
||||
|
||||
// Open state is internal, but we verify no exception
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Close_ClosesOpenSwipe()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
swipeView.LeftItems.Add(new SwipeItem { Text = "Test" });
|
||||
swipeView.Open(SwipeDirection.Right);
|
||||
|
||||
swipeView.Close();
|
||||
|
||||
// Verifies no exception
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Mode_CanBeSetToExecute()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
|
||||
swipeView.Mode = SwipeMode.Execute;
|
||||
|
||||
Assert.Equal(SwipeMode.Execute, swipeView.Mode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LeftSwipeThreshold_CanBeSet()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
|
||||
swipeView.LeftSwipeThreshold = 150f;
|
||||
|
||||
Assert.Equal(150f, swipeView.LeftSwipeThreshold);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RightSwipeThreshold_CanBeSet()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
|
||||
swipeView.RightSwipeThreshold = 150f;
|
||||
|
||||
Assert.Equal(150f, swipeView.RightSwipeThreshold);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SwipeStartedEvent_CanBeSubscribed()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
SwipeDirection? direction = null;
|
||||
|
||||
swipeView.SwipeStarted += (s, e) => direction = e.Direction;
|
||||
// Simulate internal swipe start
|
||||
swipeView.LeftItems.Add(new SwipeItem { Text = "Test" });
|
||||
|
||||
Assert.NotNull(swipeView);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SwipeEndedEvent_CanBeSubscribed()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
bool ended = false;
|
||||
|
||||
swipeView.SwipeEnded += (s, e) => ended = true;
|
||||
|
||||
Assert.NotNull(swipeView);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SwipeItem_TextColor_CanBeSet()
|
||||
{
|
||||
var item = new SwipeItem { TextColor = SKColors.Yellow };
|
||||
|
||||
Assert.Equal(SKColors.Yellow, item.TextColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SwipeItem_BackgroundColor_CanBeSet()
|
||||
{
|
||||
var item = new SwipeItem { BackgroundColor = SKColors.Green };
|
||||
|
||||
Assert.Equal(SKColors.Green, item.BackgroundColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SwipeItem_IconSource_CanBeSet()
|
||||
{
|
||||
var item = new SwipeItem { IconSource = "delete.png" };
|
||||
|
||||
Assert.Equal("delete.png", item.IconSource);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TopItems_CanAddItems()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
swipeView.TopItems.Add(new SwipeItem { Text = "Top" });
|
||||
|
||||
Assert.Single(swipeView.TopItems);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BottomItems_CanAddItems()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
swipeView.BottomItems.Add(new SwipeItem { Text = "Bottom" });
|
||||
|
||||
Assert.Single(swipeView.BottomItems);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HitTest_ReturnsCorrectView()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
swipeView.Content = new SkiaLabel { Text = "Content" };
|
||||
swipeView.Arrange(new SKRect(0, 0, 300, 50));
|
||||
|
||||
var hit = swipeView.HitTest(150, 25);
|
||||
|
||||
Assert.NotNull(hit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Measure_ReturnsCorrectSize()
|
||||
{
|
||||
var swipeView = new SkiaSwipeView();
|
||||
swipeView.Content = new SkiaLabel { Text = "Test" };
|
||||
|
||||
var size = swipeView.Measure(new SKSize(300, 100));
|
||||
|
||||
Assert.True(size.Width <= 300);
|
||||
Assert.True(size.Height <= 100);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user