mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
forcing codecov
This commit is contained in:
522
Tests/UnitTestsParallelizable/Views/SpinnerStyleTests.cs
Normal file
522
Tests/UnitTestsParallelizable/Views/SpinnerStyleTests.cs
Normal file
@@ -0,0 +1,522 @@
|
|||||||
|
#nullable enable
|
||||||
|
namespace UnitTests_Parallelizable.ViewsTests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parallelizable tests for <see cref="SpinnerStyle"/> and its concrete implementations.
|
||||||
|
/// Tests the abstract properties and behavior of all spinner style variants.
|
||||||
|
/// </summary>
|
||||||
|
public class SpinnerStyleTests
|
||||||
|
{
|
||||||
|
#region Abstract Properties Tests
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Custom_HasExpectedDefaults ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Custom ();
|
||||||
|
|
||||||
|
Assert.False (style.HasSpecialCharacters);
|
||||||
|
Assert.Empty (style.Sequence);
|
||||||
|
Assert.False (style.SpinBounce);
|
||||||
|
Assert.Equal (80, style.SpinDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Dots_HasExpectedProperties ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Dots ();
|
||||||
|
|
||||||
|
Assert.False (style.HasSpecialCharacters);
|
||||||
|
Assert.Equal (10, style.Sequence.Length);
|
||||||
|
Assert.False (style.SpinBounce);
|
||||||
|
Assert.Equal (80, style.SpinDelay);
|
||||||
|
Assert.Equal ("⠋", style.Sequence [0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Line_HasExpectedProperties ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Line ();
|
||||||
|
|
||||||
|
Assert.False (style.HasSpecialCharacters);
|
||||||
|
Assert.Equal (4, style.Sequence.Length);
|
||||||
|
Assert.False (style.SpinBounce);
|
||||||
|
Assert.Equal (130, style.SpinDelay);
|
||||||
|
Assert.Equal (["-", @"\", "|", "/"], style.Sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region SpinBounce Tests
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots4), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots6), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots7), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.GrowVertical), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.GrowHorizontal), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Balloon2), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Bounce), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.BouncingBar), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.BouncingBall), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Pong), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.SoccerHeader), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Speaker), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots), false)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Line), false)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.SimpleDots), false)]
|
||||||
|
public void SpinBounce_ReturnsExpectedValue (Type styleType, bool expectedBounce)
|
||||||
|
{
|
||||||
|
SpinnerStyle? style = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
|
||||||
|
Assert.NotNull (style);
|
||||||
|
Assert.Equal (expectedBounce, style.SpinBounce);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region HasSpecialCharacters Tests
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Arrow2), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Smiley), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Monkey), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Hearts), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Clock), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Earth), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Moon), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Runner), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Weather), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Christmas), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Grenade), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.FingerDance), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.FistBump), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.SoccerHeader), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.MindBlown), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Speaker), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.OrangePulse), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.BluePulse), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.OrangeBluePulse), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.TimeTravelClock), true)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots), false)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Line), false)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.SimpleDots), false)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Star), false)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Arc), false)]
|
||||||
|
public void HasSpecialCharacters_ReturnsExpectedValue (Type styleType, bool expectedHasSpecial)
|
||||||
|
{
|
||||||
|
SpinnerStyle? style = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
|
||||||
|
Assert.NotNull (style);
|
||||||
|
Assert.Equal (expectedHasSpecial, style.HasSpecialCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Sequence Tests
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sequence_AllStyles_ReturnsNonEmptyArray ()
|
||||||
|
{
|
||||||
|
Type [] allStyles = typeof (SpinnerStyle)
|
||||||
|
.GetNestedTypes ()
|
||||||
|
.Where (t => !t.IsAbstract && t.IsSubclassOf (typeof (SpinnerStyle)))
|
||||||
|
.ToArray ();
|
||||||
|
|
||||||
|
foreach (Type styleType in allStyles)
|
||||||
|
{
|
||||||
|
if (styleType == typeof (SpinnerStyle.Custom))
|
||||||
|
{
|
||||||
|
continue; // Custom has empty sequence by design
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinnerStyle? style = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
Assert.NotNull (style);
|
||||||
|
Assert.NotEmpty (style.Sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sequence_AllStyles_ContainsOnlyNonNullStrings ()
|
||||||
|
{
|
||||||
|
Type [] allStyles = typeof (SpinnerStyle)
|
||||||
|
.GetNestedTypes ()
|
||||||
|
.Where (t => !t.IsAbstract && t.IsSubclassOf (typeof (SpinnerStyle)))
|
||||||
|
.ToArray ();
|
||||||
|
|
||||||
|
foreach (Type styleType in allStyles)
|
||||||
|
{
|
||||||
|
SpinnerStyle? style = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
Assert.NotNull (style);
|
||||||
|
Assert.All (style.Sequence, frame => Assert.NotNull (frame));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots), 10)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots2), 8)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Line), 4)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.SimpleDots), 4)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Star), 6)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Arrow), 8)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Smiley), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Hearts), 5)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Clock), 12)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Earth), 3)]
|
||||||
|
public void Sequence_SpecificStyles_HasExpectedLength (Type styleType, int expectedLength)
|
||||||
|
{
|
||||||
|
SpinnerStyle? style = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
|
||||||
|
Assert.NotNull (style);
|
||||||
|
Assert.Equal (expectedLength, style.Sequence.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sequence_Dots8Bit_Has256Frames ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Dots8Bit ();
|
||||||
|
|
||||||
|
Assert.Equal (256, style.Sequence.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sequence_Material_HasProgressBarFrames ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Material ();
|
||||||
|
|
||||||
|
Assert.NotEmpty (style.Sequence);
|
||||||
|
|
||||||
|
// Material style uses both filled (█) and empty (▁) block characters
|
||||||
|
// to create a progress bar animation
|
||||||
|
Assert.All (style.Sequence, frame =>
|
||||||
|
Assert.True (
|
||||||
|
frame.Contains ("█") || frame.Contains ("▁"),
|
||||||
|
$"Frame should contain either filled (█) or empty (▁) blocks, but was: {frame}"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that at least some frames contain the filled block
|
||||||
|
Assert.Contains (style.Sequence, frame => frame.Contains ("█"));
|
||||||
|
|
||||||
|
// Verify that the sequence shows progression (some frames are all empty at the end)
|
||||||
|
Assert.Contains (style.Sequence, frame => frame == "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region SpinDelay Tests
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Custom), 80)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots), 80)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Line), 130)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.SimpleDots), 400)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Star), 70)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.GrowVertical), 120)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Balloon), 140)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Triangle), 50)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Arc), 100)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Material), 17)]
|
||||||
|
public void SpinDelay_SpecificStyles_HasExpectedValue (Type styleType, int expectedDelay)
|
||||||
|
{
|
||||||
|
SpinnerStyle? style = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
|
||||||
|
Assert.NotNull (style);
|
||||||
|
Assert.Equal (expectedDelay, style.SpinDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SpinDelay_AllStyles_IsPositive ()
|
||||||
|
{
|
||||||
|
Type [] allStyles = typeof (SpinnerStyle)
|
||||||
|
.GetNestedTypes ()
|
||||||
|
.Where (t => !t.IsAbstract && t.IsSubclassOf (typeof (SpinnerStyle)))
|
||||||
|
.ToArray ();
|
||||||
|
|
||||||
|
foreach (Type styleType in allStyles)
|
||||||
|
{
|
||||||
|
SpinnerStyle? style = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
Assert.NotNull (style);
|
||||||
|
Assert.True (style.SpinDelay > 0, $"{styleType.Name} should have positive SpinDelay");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Specific Style Behavior Tests
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SimpleDots_SequenceStartsWithDot ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.SimpleDots ();
|
||||||
|
|
||||||
|
Assert.StartsWith (".", style.Sequence [0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SimpleDotsScrolling_SequenceShowsProgression ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.SimpleDotsScrolling ();
|
||||||
|
|
||||||
|
Assert.Equal ([". ", ".. ", "...", " ..", " .", " "], style.Sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Arrow_SequenceContainsAllDirections ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Arrow ();
|
||||||
|
|
||||||
|
Assert.Contains ("←", style.Sequence);
|
||||||
|
Assert.Contains ("↑", style.Sequence);
|
||||||
|
Assert.Contains ("→", style.Sequence);
|
||||||
|
Assert.Contains ("↓", style.Sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BouncingBar_SequenceContainsBrackets ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.BouncingBar ();
|
||||||
|
|
||||||
|
Assert.All (style.Sequence, frame => Assert.Contains ("[", frame));
|
||||||
|
Assert.All (style.Sequence, frame => Assert.Contains ("]", frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BouncingBall_SequenceContainsParentheses ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.BouncingBall ();
|
||||||
|
|
||||||
|
Assert.All (style.Sequence, frame => Assert.Contains ("(", frame));
|
||||||
|
Assert.All (style.Sequence, frame => Assert.Contains (")", frame));
|
||||||
|
Assert.All (style.Sequence, frame => Assert.Contains ("●", frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Pong_SequenceContainsVerticalBars ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Pong ();
|
||||||
|
|
||||||
|
Assert.All (style.Sequence, frame => Assert.StartsWith ("▐", frame));
|
||||||
|
Assert.All (style.Sequence, frame => Assert.EndsWith ("▌", frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Clock_SequenceContains12Frames ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Clock ();
|
||||||
|
|
||||||
|
Assert.Equal (12, style.Sequence.Length);
|
||||||
|
|
||||||
|
// Verify it contains the 12 hour positions (on-the-hour clock faces)
|
||||||
|
Assert.Contains ("🕛 ", style.Sequence); // 12 o'clock
|
||||||
|
Assert.Contains ("🕐 ", style.Sequence); // 1 o'clock
|
||||||
|
Assert.Contains ("🕑 ", style.Sequence); // 2 o'clock
|
||||||
|
Assert.Contains ("🕒 ", style.Sequence); // 3 o'clock
|
||||||
|
Assert.Contains ("🕓 ", style.Sequence); // 4 o'clock
|
||||||
|
Assert.Contains ("🕔 ", style.Sequence); // 5 o'clock
|
||||||
|
Assert.Contains ("🕕 ", style.Sequence); // 6 o'clock
|
||||||
|
Assert.Contains ("🕖 ", style.Sequence); // 7 o'clock
|
||||||
|
Assert.Contains ("🕗 ", style.Sequence); // 8 o'clock
|
||||||
|
Assert.Contains ("🕘 ", style.Sequence); // 9 o'clock
|
||||||
|
Assert.Contains ("🕙 ", style.Sequence); // 10 o'clock
|
||||||
|
Assert.Contains ("🕚 ", style.Sequence); // 11 o'clock
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Earth_SequenceContainsGlobeEmojis ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Earth ();
|
||||||
|
|
||||||
|
Assert.Contains ("🌍 ", style.Sequence);
|
||||||
|
Assert.Contains ("🌎 ", style.Sequence);
|
||||||
|
Assert.Contains ("🌏 ", style.Sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Weather_SequenceShowsWeatherProgression ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Weather ();
|
||||||
|
|
||||||
|
Assert.Contains ("☀️ ", style.Sequence);
|
||||||
|
Assert.Contains ("⛅️ ", style.Sequence);
|
||||||
|
Assert.Contains ("🌧 ", style.Sequence);
|
||||||
|
Assert.Contains ("⛈ ", style.Sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Shark_SequenceShowsSharkAnimation ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Shark ();
|
||||||
|
|
||||||
|
// Check that frames show movement
|
||||||
|
Assert.All (style.Sequence, frame => Assert.Contains ("|", frame));
|
||||||
|
Assert.All (style.Sequence, frame => Assert.Contains ("_", frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Christmas_SequenceContainsTreeEmojis ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Christmas ();
|
||||||
|
|
||||||
|
Assert.Contains ("🌲", style.Sequence);
|
||||||
|
Assert.Contains ("🎄", style.Sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MindBlown_SequenceShowsProgressiveExpression ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.MindBlown ();
|
||||||
|
|
||||||
|
Assert.Contains ("😐 ", style.Sequence);
|
||||||
|
Assert.Contains ("😮 ", style.Sequence);
|
||||||
|
Assert.Contains ("🤯 ", style.Sequence);
|
||||||
|
Assert.Contains ("💥 ", style.Sequence);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Toggle Style Tests
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle2), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle3), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle4), 4)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle5), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle6), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle7), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle8), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle9), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle10), 3)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle11), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle12), 2)]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Toggle13), 3)]
|
||||||
|
public void ToggleStyles_HaveExpectedFrameCount (Type styleType, int expectedFrames)
|
||||||
|
{
|
||||||
|
SpinnerStyle? style = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
|
||||||
|
Assert.NotNull (style);
|
||||||
|
Assert.Equal (expectedFrames, style.Sequence.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Dots Style Variant Tests
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots2))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots3))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots4))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots5))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots6))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots7))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots8))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots9))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots10))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots11))]
|
||||||
|
[InlineData (typeof (SpinnerStyle.Dots12))]
|
||||||
|
public void DotsStyles_DoNotHaveSpecialCharacters (Type styleType)
|
||||||
|
{
|
||||||
|
SpinnerStyle? style = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
|
||||||
|
Assert.NotNull (style);
|
||||||
|
Assert.False (style.HasSpecialCharacters);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Dots8Bit_SequenceCoversAllBrailleCharacters ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.Dots8Bit ();
|
||||||
|
|
||||||
|
// Braille patterns from U+2800 to U+28FF (256 characters)
|
||||||
|
Assert.Equal (256, style.Sequence.Length);
|
||||||
|
|
||||||
|
// Should start with blank braille
|
||||||
|
Assert.Equal ("⠀", style.Sequence [0]);
|
||||||
|
|
||||||
|
// Should end with full braille
|
||||||
|
Assert.Equal ("⣿", style.Sequence [^1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Pulse Style Tests
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OrangePulse_SequenceShowsPulseEffect ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.OrangePulse ();
|
||||||
|
|
||||||
|
Assert.Contains ("🔸 ", style.Sequence);
|
||||||
|
Assert.Contains ("🔶 ", style.Sequence);
|
||||||
|
Assert.Contains ("🟠 ", style.Sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BluePulse_SequenceShowsPulseEffect ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.BluePulse ();
|
||||||
|
|
||||||
|
Assert.Contains ("🔹 ", style.Sequence);
|
||||||
|
Assert.Contains ("🔷 ", style.Sequence);
|
||||||
|
Assert.Contains ("🔵 ", style.Sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OrangeBluePulse_CombinesBothPulses ()
|
||||||
|
{
|
||||||
|
SpinnerStyle style = new SpinnerStyle.OrangeBluePulse ();
|
||||||
|
|
||||||
|
// Should contain frames from both orange and blue pulses
|
||||||
|
Assert.Contains ("🔸 ", style.Sequence);
|
||||||
|
Assert.Contains ("🟠 ", style.Sequence);
|
||||||
|
Assert.Contains ("🔹 ", style.Sequence);
|
||||||
|
Assert.Contains ("🔵 ", style.Sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Edge Cases
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AllStyles_CanBeInstantiated ()
|
||||||
|
{
|
||||||
|
Type [] allStyles = typeof (SpinnerStyle)
|
||||||
|
.GetNestedTypes ()
|
||||||
|
.Where (t => !t.IsAbstract && t.IsSubclassOf (typeof (SpinnerStyle)))
|
||||||
|
.ToArray ();
|
||||||
|
|
||||||
|
foreach (Type styleType in allStyles)
|
||||||
|
{
|
||||||
|
Exception? exception = Record.Exception (() => Activator.CreateInstance (styleType));
|
||||||
|
|
||||||
|
Assert.Null (exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AllStyles_PropertiesAreImmutable ()
|
||||||
|
{
|
||||||
|
Type [] allStyles = typeof (SpinnerStyle)
|
||||||
|
.GetNestedTypes ()
|
||||||
|
.Where (t => !t.IsAbstract && t.IsSubclassOf (typeof (SpinnerStyle)))
|
||||||
|
.ToArray ();
|
||||||
|
|
||||||
|
foreach (Type styleType in allStyles)
|
||||||
|
{
|
||||||
|
SpinnerStyle? style1 = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
SpinnerStyle? style2 = Activator.CreateInstance (styleType) as SpinnerStyle;
|
||||||
|
|
||||||
|
Assert.NotNull (style1);
|
||||||
|
Assert.NotNull (style2);
|
||||||
|
|
||||||
|
// Same type should have same property values
|
||||||
|
Assert.Equal (style1.HasSpecialCharacters, style2.HasSpecialCharacters);
|
||||||
|
Assert.Equal (style1.SpinBounce, style2.SpinBounce);
|
||||||
|
Assert.Equal (style1.SpinDelay, style2.SpinDelay);
|
||||||
|
Assert.Equal (style1.Sequence, style2.Sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
43
codecov.yml
43
codecov.yml
@@ -15,6 +15,9 @@ coverage:
|
|||||||
threshold: 1% # Allow 1% decrease without failing
|
threshold: 1% # Allow 1% decrease without failing
|
||||||
base: auto # Compare against base branch (v2_develop)
|
base: auto # Compare against base branch (v2_develop)
|
||||||
if_ci_failed: error # Fail if CI fails
|
if_ci_failed: error # Fail if CI fails
|
||||||
|
# Only measure Terminal.Gui library
|
||||||
|
paths:
|
||||||
|
- "Terminal.Gui/"
|
||||||
|
|
||||||
# Per-patch (PR) coverage
|
# Per-patch (PR) coverage
|
||||||
patch:
|
patch:
|
||||||
@@ -23,50 +26,44 @@ coverage:
|
|||||||
threshold: 5% # Allow 5% variance
|
threshold: 5% # Allow 5% variance
|
||||||
base: auto
|
base: auto
|
||||||
if_ci_failed: error
|
if_ci_failed: error
|
||||||
|
# Only measure Terminal.Gui library
|
||||||
|
paths:
|
||||||
|
- "Terminal.Gui/"
|
||||||
|
|
||||||
# Comment configuration for PRs
|
# Comment configuration for PRs
|
||||||
comment:
|
comment:
|
||||||
layout: "diff, files, footer"
|
layout: "diff, files, footer"
|
||||||
behavior: default # Update existing comment
|
behavior: default # Update existing comment
|
||||||
require_changes: false # Always comment
|
require_changes: false # Always comment
|
||||||
require_base: true # Require base coverage to compare
|
require_base: true # Require base coverage to compare
|
||||||
require_head: true # Require head coverage
|
require_head: true # Require head coverage
|
||||||
branches:
|
|
||||||
- v2_develop
|
|
||||||
- v2_release
|
|
||||||
|
|
||||||
# Flag-based coverage grouping (matches your workflow flags)
|
# Flag-based coverage grouping (matches your workflow flags)
|
||||||
flags:
|
flags:
|
||||||
unittests-nonparallel:
|
unittests-nonparallel:
|
||||||
carryforward: false # Don't carry forward if missing
|
carryforward: false # Don't carry forward if missing
|
||||||
paths:
|
paths:
|
||||||
- Terminal.Gui/
|
- "Terminal.Gui/" # Only Terminal.Gui library
|
||||||
|
|
||||||
unittests-parallel:
|
unittests-parallel:
|
||||||
carryforward: false
|
carryforward: false
|
||||||
paths:
|
paths:
|
||||||
- Terminal.Gui/
|
- "Terminal.Gui/" # Only Terminal.Gui library
|
||||||
|
|
||||||
integrationtests:
|
integrationtests:
|
||||||
carryforward: false
|
carryforward: false
|
||||||
paths:
|
paths:
|
||||||
- Terminal.Gui/
|
- "Terminal.Gui/" # Only Terminal.Gui library
|
||||||
|
|
||||||
# Files and paths to ignore
|
# Files and paths to ignore (belt-and-suspenders approach)
|
||||||
ignore:
|
ignore:
|
||||||
- "Examples/**/*" # Example projects
|
- "Examples/**" # Example projects (no trailing /*)
|
||||||
- "Tests/**/*" # Test projects themselves
|
- "Tests/**" # Test projects themselves
|
||||||
- "UnitTests/**/*" # Legacy test location
|
- "UnitTests/**" # Legacy test location
|
||||||
- "docfx/**/*" # Documentation
|
- "docfx/**" # Documentation
|
||||||
- "Scripts/**/*" # PowerShell scripts
|
- "Scripts/**" # PowerShell scripts
|
||||||
- "**/*.Designer.cs" # Auto-generated files
|
- "**/*.Designer.cs" # Auto-generated files
|
||||||
- "**/obj/**/*" # Build artifacts
|
- "**/obj/**" # Build artifacts
|
||||||
- "**/bin/**/*" # Build artifacts
|
- "**/bin/**" # Build artifacts
|
||||||
|
- "**/*.AssemblyInfo.cs" # Assembly info files
|
||||||
# # Path fixes (normalize Windows paths to Unix)
|
|
||||||
# fixes:
|
|
||||||
# - "C:/Users/runner/work/Terminal.Gui/Terminal.Gui/::" # Windows CI paths
|
|
||||||
# - "D:/a/Terminal.Gui/Terminal.Gui/::" # Alternative Windows paths
|
|
||||||
|
|
||||||
# Only process coverage from these branches
|
# Only process coverage from these branches
|
||||||
branches:
|
branches:
|
||||||
|
|||||||
Reference in New Issue
Block a user