-
Notifications
You must be signed in to change notification settings - Fork 70
/
TestUtils.cs
149 lines (134 loc) · 4.49 KB
/
TestUtils.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//
// Copyright (c) 2019-2022 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
// Website: https://am.angouri.org.
//
using AngouriMath;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HonkSharp.Fluency;
using HonkSharp.Functional;
using Xunit;
using AngouriMath.Core.Exceptions;
namespace AngouriMath.Tests
{
public static class TestExtensions
{
public static (T, T) Into2<T>(this IEnumerable<T> seq)
{
using var enumerator = seq.GetEnumerator();
(T, T) res;
if (!enumerator.MoveNext()) throw new Exception("Sequence should contain two elements");
res.Item1 = enumerator.Current;
if (!enumerator.MoveNext()) throw new Exception("Sequence should contain two elements");
res.Item2 = enumerator.Current;
if (enumerator.MoveNext()) throw new Exception("Sequence should contain two elements");
return res;
}
public static void ShouldBe(this Entity @this, Entity other)
{
using var _ = MathS.Diagnostic.OutputExplicit.Set(true);
Assert.True(@this == other, $"\nExpected: {PrettyOutput(other)}\n\nActual: {PrettyOutput(@this)}\n");
static string PrettyOutput(Entity entity)
=> entity is Entity.Matrix m ? m.ToString(multilineFormat: true) : entity.ToString();
}
public static T AsNotNull<T>(T? value)
{
Assert.NotNull(value);
return value!;
}
public static T ShouldBeNotNull<T>(this T? value)
=> AsNotNull(value);
public static void ShouldBeNull<T>(this T? value)
=> Assert.Null(value);
// okay; this one makes an unnecessary allocation
public static IEnumerable<T> ShouldCountTo<T>(this IEnumerable<T> value, int target)
{
Assert.Equal(target, value.Count());
return value;
}
public static Unit ShouldApproximatelyEqual(this Entity actual, Entity target)
=> (actual.EvalNumerical() - target.EvalNumerical())
.Abs()
.Pipe(error => Assert.True(error < 0.01, $"Error is {error}"))
.Discard();
}
/// <summary>
/// When waits, ignores all the operation canceled exceptions
/// </summary>
public sealed class WaiterAndSwallower
{
private readonly int precision;
public WaiterAndSwallower(int precisionMs)
{
this.precision = precisionMs;
}
public async Task Wait(int timeMs)
{
var precLocal = precision;
while (timeMs > 0)
{
try
{
await Task.Delay(precLocal);
timeMs -= precLocal;
}
catch (OperationCanceledException) { }
}
}
public async Task WaitWhile(Func<bool> predicate)
{
while (predicate())
try
{
await Task.Delay(10);
}
catch (OperationCanceledException) { }
}
}
public sealed class TimeOutChecker
{
public bool BeingCompletedForLessThan(Action action, long timeoutMs)
{
var stopped = false;
var th = new Thread(() =>
{
action();
stopped = true;
});
th.Start();
var stopwatch = new Stopwatch();
stopwatch.Start();
while (!stopped && stopwatch.ElapsedMilliseconds < timeoutMs)
Thread.Sleep(5);
return stopped;
}
}
public sealed class ThreadingChecker
{
private readonly Action<int> action;
public ThreadingChecker(Action<int> action)
{
this.action = action;
}
public void Run(int iterCount = 1, int threadCount = 4)
{
var tasks = new Task[threadCount];
for (var i = 0; i < threadCount; i++)
tasks[i] = Task.Run(
() =>
{
var iterCountLocal = iterCount;
for (var j = 0; j < iterCountLocal; j++)
action(i);
}
);
Task.WaitAll(tasks);
}
}
}