1
0

Added HtmlHelper.IsDarkColor and enhanced UnitTests

This commit is contained in:
2021-12-17 00:14:38 +01:00
parent 6f6b79c88c
commit cea79c2359
4 changed files with 468 additions and 5 deletions

View File

@@ -0,0 +1,55 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace AMWD.Common.AspNetCore.Utilities
{
/// <summary>
/// Provides helpers for webpages.
/// </summary>
public static class HtmlHelper
{
/// <summary>
/// Checks whether a color is considered as dark.
/// </summary>
/// <param name="color">The color (hex or rgb - as defined in CSS)</param>
/// <returns><c>true</c> when the color is dark otherwise <c>false</c>.</returns>
public static bool IsDarkColor(string color)
{
if (string.IsNullOrWhiteSpace(color))
return false;
int r, g, b;
var rgbMatch = Regex.Match(color, @"^rgba?\(([0-9]+), ?([0-9]+), ?([0-9]+)");
var hexMatchFull = Regex.Match(color, @"^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$");
var hexMatchLite = Regex.Match(color, @"^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$");
if (rgbMatch.Success)
{
r = Convert.ToInt32(rgbMatch.Groups[1].Value);
g = Convert.ToInt32(rgbMatch.Groups[2].Value);
b = Convert.ToInt32(rgbMatch.Groups[3].Value);
}
else if (hexMatchFull.Success)
{
r = Convert.ToInt32(hexMatchFull.Groups[1].Value, 16);
g = Convert.ToInt32(hexMatchFull.Groups[2].Value, 16);
b = Convert.ToInt32(hexMatchFull.Groups[3].Value, 16);
}
else if (hexMatchLite.Success)
{
r = Convert.ToInt32(new string(hexMatchLite.Groups[1].Value.First(), 2), 16);
g = Convert.ToInt32(new string(hexMatchLite.Groups[2].Value.First(), 2), 16);
b = Convert.ToInt32(new string(hexMatchLite.Groups[3].Value.First(), 2), 16);
}
else
{
return false;
}
double luminance = (r * 0.299 + g * 0.587 + b * 0.114) / 255;
return luminance <= 0.5;
}
}
}

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using AMWD.Common.Utilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace AMWD.Common.Tests.Utilities
@@ -11,6 +11,278 @@ namespace AMWD.Common.Tests.Utilities
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class DelayedTaskTests
{
// TODO
[TestMethod]
public void ShouldCreateNewDelayedTaskNotStarting()
{
// arrange
int executionCount = 0;
var delay = TimeSpan.FromMilliseconds(100);
var action = () => { executionCount++; };
// act
var cts = new CancellationTokenSource(delay.Add(TimeSpan.FromSeconds(1)));
var delayedTask = DelayedTask.Create(action, delay);
SpinWait.SpinUntil(() => executionCount > 0 || cts.IsCancellationRequested);
// assert
Assert.IsNotNull(delayedTask);
Assert.AreEqual(delay, delayedTask.Delay);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNull(delayedTask.Exception);
Assert.AreEqual(0, executionCount);
}
[TestMethod]
public void ShouldCreateNewDelayedTaskStarting()
{
// arrange
int executionCount = 0;
var delay = TimeSpan.FromMilliseconds(100);
var action = () => { executionCount++; };
// act
var cts = new CancellationTokenSource(delay.Add(TimeSpan.FromSeconds(1)));
var delayedTask = DelayedTask.Run(action, delay);
SpinWait.SpinUntil(() => executionCount > 0 || cts.IsCancellationRequested);
// assert
Assert.IsNotNull(delayedTask);
Assert.AreEqual(delay, delayedTask.Delay);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNull(delayedTask.Exception);
Assert.AreEqual(1, executionCount);
}
[TestMethod]
public void ShouldRunOnceAfterReset()
{
// arrange
int executionCount = 0;
var delay = TimeSpan.FromMilliseconds(100);
var action = () => { executionCount++; };
// act
var cts = new CancellationTokenSource(delay.Add(TimeSpan.FromSeconds(1)));
var delayedTask = DelayedTask.Create(action, delay);
delayedTask.Reset();
SpinWait.SpinUntil(() => executionCount > 0 || cts.IsCancellationRequested);
// assert
Assert.IsNotNull(delayedTask);
Assert.AreEqual(delay, delayedTask.Delay);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNull(delayedTask.Exception);
Assert.AreEqual(1, executionCount);
}
[TestMethod]
public void ShouldCancelWaitingTask()
{
// arrange
int executionCount = 0;
var delay = TimeSpan.FromMilliseconds(100);
var action = () => { executionCount++; };
// act
var cts = new CancellationTokenSource(delay.Add(TimeSpan.FromSeconds(1)));
var delayedTask = DelayedTask.Run(action, delay);
delayedTask.Cancel();
SpinWait.SpinUntil(() => executionCount > 0 || cts.IsCancellationRequested);
// assert
Assert.IsNotNull(delayedTask);
Assert.AreEqual(delay, delayedTask.Delay);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNull(delayedTask.Exception);
Assert.AreEqual(0, executionCount);
}
[TestMethod]
public async Task ShouldResetRunningDelay()
{
// arrange
int executionCount = 0;
var sw = new Stopwatch();
var delay = TimeSpan.FromMilliseconds(200);
var action = () => { sw.Stop(); executionCount++; };
// act
var cts = new CancellationTokenSource(delay.Add(TimeSpan.FromSeconds(1)));
sw.Start();
var delayedTask = DelayedTask.Run(action, delay);
await Task.Delay(50);
delayedTask.Reset();
SpinWait.SpinUntil(() => executionCount > 0 || cts.IsCancellationRequested);
// assert
Assert.IsNotNull(delayedTask);
Assert.AreEqual(delay, delayedTask.Delay);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNull(delayedTask.Exception);
Assert.AreEqual(1, executionCount);
// delta of 50ms as the precision below 50ms is really bad for System.Timer
Assert.AreEqual(250, sw.ElapsedMilliseconds, 50);
}
[TestMethod]
public async Task ShouldNotExecutedImmediateOnCreated()
{
// arrange
int executionCount = 0;
var sw = new Stopwatch();
var delay = TimeSpan.FromMilliseconds(200);
var action = () => { sw.Stop(); executionCount++; };
// act
var cts = new CancellationTokenSource(delay.Add(TimeSpan.FromSeconds(1)));
sw.Start();
var delayedTask = DelayedTask.Create(action, delay);
await Task.Delay(50);
bool isSuccess = delayedTask.ExecutePending();
SpinWait.SpinUntil(() => executionCount > 0 || cts.IsCancellationRequested);
sw.Stop();
// assert
Assert.IsNotNull(delayedTask);
Assert.AreEqual(delay, delayedTask.Delay);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNull(delayedTask.Exception);
Assert.AreEqual(0, executionCount);
// delta of 50ms as the precision below 50ms is really bad for System.Timer
Assert.AreEqual(1250, sw.ElapsedMilliseconds, 50);
Assert.IsFalse(isSuccess);
}
[TestMethod]
public async Task ShouldExecuteImmediateOnExecutePendingWhenRunning()
{
// arrange
int executionCount = 0;
var sw = new Stopwatch();
var delay = TimeSpan.FromMilliseconds(200);
var action = () => { sw.Stop(); executionCount++; };
// act
var cts = new CancellationTokenSource(delay.Add(TimeSpan.FromSeconds(1)));
sw.Start();
var delayedTask = DelayedTask.Run(action, delay);
await Task.Delay(50);
bool isSuccess = delayedTask.ExecutePending();
SpinWait.SpinUntil(() => executionCount > 0 || cts.IsCancellationRequested);
// assert
Assert.IsNotNull(delayedTask);
Assert.AreEqual(delay, delayedTask.Delay);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNull(delayedTask.Exception);
Assert.AreEqual(1, executionCount);
// delta of 50ms as the precision below 50ms is really bad for System.Timer
Assert.AreEqual(50, sw.ElapsedMilliseconds, 50);
Assert.IsTrue(isSuccess);
}
[TestMethod]
public void ShouldReturnAnAwaiter()
{
// arrange
int executionCount = 0;
var delay = TimeSpan.FromMilliseconds(100);
var action = () => { executionCount++; };
var delayedTask = DelayedTask.Create(action, delay);
// act
delayedTask.Reset();
var awaiter = delayedTask.GetAwaiter();
SpinWait.SpinUntil(() => awaiter.IsCompleted);
// assert
Assert.IsNotNull(delayedTask);
Assert.IsNotNull(awaiter);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNull(delayedTask.Exception);
Assert.AreEqual(1, executionCount);
}
[TestMethod]
public void ShouldHaveAnExceptionSet()
{
// arrange
var delay = TimeSpan.FromMilliseconds(100);
var action = () => { throw new Exception("TEST :D"); };
// act
var delayedTask = DelayedTask.Run(action, delay);
var awaiter = delayedTask.GetAwaiter();
SpinWait.SpinUntil(() => awaiter.IsCompleted);
// assert
Assert.IsNotNull(delayedTask);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNotNull(delayedTask.Exception);
}
[TestMethod]
public void ShouldUseExceptionHandler()
{
// arrange
string exceptionText = null;
var delay = TimeSpan.FromMilliseconds(100);
var action = () => { throw new Exception("TEST :D"); };
var exceptionHandler = (Exception ex) =>
{
exceptionText = ex.Message;
};
// act
var delayedTask = DelayedTask.Run(action, delay)
.WithExceptionHandler(exceptionHandler);
var awaiter = delayedTask.GetAwaiter();
SpinWait.SpinUntil(() => awaiter.IsCompleted);
// assert
Assert.IsNotNull(delayedTask);
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.IsNotNull(delayedTask.Exception);
Assert.AreEqual("TEST :D", exceptionText);
}
[TestMethod]
public async Task ShouldReturnNormalTask()
{
// arrange
int executionCount = 0;
var delay = TimeSpan.FromMilliseconds(100);
var action = () => { executionCount++; };
var delayedTask = DelayedTask.Create(action, delay);
// act
delayedTask.Reset();
var task = delayedTask.Task;
await task;
// assert
Assert.IsNotNull(delayedTask);
Assert.IsNotNull(task);
Assert.IsInstanceOfType(task, typeof(Task));
Assert.IsFalse(delayedTask.IsRunning);
Assert.IsFalse(delayedTask.IsWaitingToRun);
Assert.AreEqual(1, executionCount);
Assert.AreEqual(TaskStatus.RanToCompletion, task.Status);
}
}
}

View File

@@ -0,0 +1,134 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using AMWD.Common.Utilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace AMWD.Common.Tests.Utilities
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class DelayedTaskWithResultTests
{
[TestMethod]
public void ShouldCreateNewDelayedTaskNotStarting()
{
// arrange
int executionCount = 0;
var delay = TimeSpan.FromMilliseconds(100);
var function = () => { executionCount++; return new[] { 42, 21 }; };
// act
var cts = new CancellationTokenSource(delay.Add(TimeSpan.FromSeconds(1)));
var delayedTaskWithResult = DelayedTask.Create(function, delay);
SpinWait.SpinUntil(() => executionCount > 0 || cts.IsCancellationRequested);
// assert
Assert.IsNotNull(delayedTaskWithResult);
Assert.AreEqual(delay, delayedTaskWithResult.Delay);
Assert.IsFalse(delayedTaskWithResult.IsRunning);
Assert.IsFalse(delayedTaskWithResult.IsWaitingToRun);
Assert.IsNull(delayedTaskWithResult.Exception);
Assert.AreEqual(0, executionCount);
}
[TestMethod]
public async Task ShouldCreateNewDelayedTaskStarting()
{
// arrange
int executionCount = 0;
var delay = TimeSpan.FromMilliseconds(100);
var function = () => { executionCount++; return new[] { 42, 21 }; };
// act
var delayedTaskWithResult = DelayedTask.Run(function, delay);
int[] result = await delayedTaskWithResult;
// assert
Assert.IsNotNull(delayedTaskWithResult);
Assert.AreEqual(delay, delayedTaskWithResult.Delay);
Assert.IsFalse(delayedTaskWithResult.IsRunning);
Assert.IsFalse(delayedTaskWithResult.IsWaitingToRun);
Assert.IsNull(delayedTaskWithResult.Exception);
Assert.AreEqual(1, executionCount);
CollectionAssert.AreEqual(new[] { 42, 21 }, result);
}
[TestMethod]
public void ShouldHaveAnExceptionSet()
{
// arrange
var delay = TimeSpan.FromMilliseconds(100);
#pragma warning disable CS0162 // Unreachable Code detected.
var function = () => { throw new Exception("TEST :D"); return new[] { 42, 21 }; };
#pragma warning restore CS0162 // Unreachable Code detected
// act
var delayedTaskWithResult = DelayedTask.Run(function, delay);
var awaiter = delayedTaskWithResult.GetAwaiter();
SpinWait.SpinUntil(() => awaiter.IsCompleted);
// assert
Assert.IsNotNull(delayedTaskWithResult);
Assert.IsFalse(delayedTaskWithResult.IsRunning);
Assert.IsFalse(delayedTaskWithResult.IsWaitingToRun);
Assert.IsNotNull(delayedTaskWithResult.Exception);
}
[TestMethod]
public void ShouldUseExceptionHandler()
{
// arrange
string exceptionText = null;
var delay = TimeSpan.FromMilliseconds(100);
#pragma warning disable CS0162 // Unreachable Code detected.
var function = () => { throw new Exception("TEST :D"); return new[] { 42, 21 }; };
#pragma warning restore CS0162 // Unreachable Code detected
var exceptionHandler = (Exception ex) =>
{
exceptionText = ex.Message;
};
// act
var delayedTaskWithResult = DelayedTask.Run(function, delay)
.WithExceptionHandler(exceptionHandler);
var awaiter = delayedTaskWithResult.GetAwaiter();
SpinWait.SpinUntil(() => awaiter.IsCompleted);
// assert
Assert.IsNotNull(delayedTaskWithResult);
Assert.IsFalse(delayedTaskWithResult.IsRunning);
Assert.IsFalse(delayedTaskWithResult.IsWaitingToRun);
Assert.IsNotNull(delayedTaskWithResult.Exception);
Assert.AreEqual("TEST :D", exceptionText);
}
[TestMethod]
public async Task ShouldReturnNormalTask()
{
// arrange
int executionCount = 0;
var delay = TimeSpan.FromMilliseconds(100);
var function = () => { executionCount++; return new[] { 42, 21 }; };
var delayedTaskWithResult = DelayedTask.Create(function, delay);
// act
delayedTaskWithResult.Reset();
var task = delayedTaskWithResult.Task;
int[] result = await task;
// assert
Assert.IsNotNull(delayedTaskWithResult);
Assert.IsNotNull(task);
Assert.IsInstanceOfType(task, typeof(Task));
Assert.IsFalse(delayedTaskWithResult.IsRunning);
Assert.IsFalse(delayedTaskWithResult.IsWaitingToRun);
Assert.AreEqual(1, executionCount);
Assert.AreEqual(TaskStatus.RanToCompletion, task.Status);
CollectionAssert.AreEqual(new int[] { 42, 21 }, result);
}
}
}

View File

@@ -7,10 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased](https://git.am-wd.de/AM.WD/common/compare/v1.1.0...master)
### Added
- CHANGELOG
- `HtmlHelper.IsDarkColor` to classify a color as dark or light one (by luminance)
### Changed
- Unit-Tests enhanced
- Updated `NetRevisionTask`
- Unit-Tests excluded from code coverage calcualtion
- Updated NuGet package `NetRevisionTask`
## [v1.1.0](https://git.am-wd.de/AM.WD/common/compare/v1.0.2...v1.1.0) - 2021-11-22