Skip to content

Commit 9960c8b

Browse files
authored
Merge pull request #73 from Infarh/dev
Публикация новой версии пакета v1.0.0
2 parents ef2da35 + e977e5c commit 9960c8b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2271
-1125
lines changed

.github/copilot-instructions.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Правила для GitHub Copilot
2+
3+
- Всегда отвечай, используя русский язык
4+
- Всегда пиши комментарии в коде на русском языке
5+
6+
## Комментарии
7+
- Короткие пояснительные комментарии располагай в конце той же строки, что и код // кратко по делу
8+
- Старайся избегать тривиальных комментариев
9+
10+
## XML‑документация
11+
- Документируй классы, структуры, делегаты, перечисления и их члены только XML‑комментариями
12+
- Одинарное предложение пиши в одной строке внутри тега и без точки в конце
13+
- Каждый тег XML‑комментария располагай на отдельной строке
14+
- Порядок тегов: `<summary>``<param>``<returns>``<exception>``<remarks>``<example>`
15+
- Для сложных публичных метдов генерируй блок с простым примером использования кода внутри тега `<example>`
16+
17+
Примеры:
18+
- `<summary>Краткое описание сущности</summary>`
19+
- `<param name="Value">Описание параметра</param>`
20+
- `<returns>Описание возвращаемого значения</returns>`
21+
22+
## Синтаксис и минимализм
23+
- При генерации кода используй современные конструкции языка, совместимые с целевыми платформами проекта
24+
- Стремись минимизировать количество фигурных скобок за счёт expression‑bodied членов и switch‑выражений
25+
- Не убирай фигурные скобки в многострочных конструкциях ради читаемости
26+
- Всегда старайся минимизировать размер кода, если не запрошено иное
27+
28+
Разрешённые современные приёмы (когда поддерживается целевой платформой):
29+
- file‑scoped namespace
30+
- expression‑bodied члены
31+
- switch‑выражения и pattern matching
32+
- target‑typed `new`
33+
- collection expressions и инициализаторы коллекций
34+
- `using var` и `await using`
35+
- операторы `??`, `??=`, `is not`, `with`
36+
- упрощение nullable-присвоения `target?.Property = 15;` вместо `if(target is not null) target.Property = 15;`
37+
38+
## Именование
39+
- Локальные переменные: `snake_case`
40+
- Параметры методов: `PascalCase`
41+
- Поля экземпляров: `_PascalCase`
42+
- Статические поля: `__PascalCase`
43+
- Константы: `PascalCase`
44+
- Публичные типы и члены API: `PascalCase`
45+
- Предпочитай английский язык при именовании переменных, методов, классов и прочих сущностей
46+
47+
## Инициализация и объявления
48+
- При инициализации массивов, списков и словарей используй выражения инициализации массивов/коллекций
49+
- При объявлении переменных предпочитай использовать ключевое слово `var` (кроме случаев, когда явный тип заметно повышает понятность)
50+
51+
## Форматирование
52+
- Короткие системные комментарии пиши компактно в одну строку
53+
- Удаляй неиспользуемые `using`, сортируй и группируй директивы `using`
54+
- Разделяй логические блоки пустыми строками по мере необходимости, избегай лишних переносов
55+
56+
## Практики .NET
57+
- Включай `#nullable enable` там, где это поддерживается
58+
- Используй guard‑выражения, например `ArgumentNullException.ThrowIfNull(x)`
59+
- Предпочитай Try‑паттерны для контроля потока вместо исключений
60+
- При генерации метода добавляй в его начале блок проверки входных параметров. Отделяй этот блок пустой строкой от остального тела метода
61+
- При генерации публичных свойств у моделей-представления MVVM (классов, реализующих INotifyPropertyChanged) используй следующий формат (в одну строку):
62+
```csharp
63+
/// <summary>Описание свойства</summary>
64+
public string PropertyName { get; set => Set(ref field, value); }
65+
```
66+
- Для простых лаконичных методов используй expression‑bodied синтаксис, записанный в одну строку.
67+
68+
## Совместимость целей
69+
- В рабочем пространстве используются целевые платформы: `.NET Standard 2.0` и `.NET 10`
70+
- Применяй современные возможности языка и платформы только если они доступны для соответствующей целевой платформы проекта

.github/workflows/publish.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- name: Setup .NET
2424
uses: actions/setup-dotnet@v3
2525
with:
26-
dotnet-version: 7.0.x
26+
dotnet-version: 10.0.x
2727

2828
- name: Cache NuGet
2929
uses: actions/cache@v3
@@ -61,10 +61,10 @@ jobs:
6161
- name: Install .NET Core
6262
uses: actions/setup-dotnet@v3
6363
with:
64-
dotnet-version: 7.0.x
64+
dotnet-version: 10.0.x
6565

6666
- name: Get artifact
67-
uses: actions/download-artifact@v3.0.1
67+
uses: actions/download-artifact@v4.1.7
6868
id: download
6969
with:
7070
name: Release
@@ -82,10 +82,10 @@ jobs:
8282
- name: Install .NET Core
8383
uses: actions/setup-dotnet@v3
8484
with:
85-
dotnet-version: 7.0.x
85+
dotnet-version: 10.0.x
8686

8787
- name: Get artifact
88-
uses: actions/download-artifact@v3.0.1
88+
uses: actions/download-artifact@v4.1.7
8989
id: download
9090
with:
9191
name: Release

.github/workflows/testing.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Setup .NET
2020
uses: actions/setup-dotnet@v3
2121
with:
22-
dotnet-version: 7.0.x
22+
dotnet-version: 10.0.x
2323

2424
- name: Building
2525
run: dotnet build -c Debug

MathCore.TestsExtensions.sln

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 17
4-
VisualStudioVersion = 17.4.33103.184
3+
# Visual Studio Version 18
4+
VisualStudioVersion = 18.0.11205.157 d18.0
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MathCore.TestsExtensions", "MathCore.TestsExtensions\MathCore.TestsExtensions.csproj", "{0F039156-E6CB-4EFB-A863-13A1AC2DD4AE}"
77
EndProject
88
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MathCore.TestsExtensions.Tests", "Tests\MathCore.TestsExtensions.Tests\MathCore.TestsExtensions.Tests.csproj", "{10093BD2-D872-4383-B075-92850E009647}"
99
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Service", ".Service", "{29B29638-89EC-4383-B587-AE8C981DED4F}"
11+
ProjectSection(SolutionItems) = preProject
12+
.github\copilot-instructions.md = .github\copilot-instructions.md
13+
EndProjectSection
14+
EndProject
15+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{D6A23A02-D860-4101-AB7B-0C7FB57331CB}"
16+
ProjectSection(SolutionItems) = preProject
17+
.github\copilot-instructions.md = .github\copilot-instructions.md
18+
EndProjectSection
19+
EndProject
20+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{83B95A2F-1D99-43CB-BA0C-769D88078D6F}"
21+
ProjectSection(SolutionItems) = preProject
22+
.github\workflows\publish.yml = .github\workflows\publish.yml
23+
.github\workflows\testing.yml = .github\workflows\testing.yml
24+
EndProjectSection
25+
EndProject
1026
Global
1127
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1228
Debug|Any CPU = Debug|Any CPU
@@ -25,6 +41,10 @@ Global
2541
GlobalSection(SolutionProperties) = preSolution
2642
HideSolutionNode = FALSE
2743
EndGlobalSection
44+
GlobalSection(NestedProjects) = preSolution
45+
{D6A23A02-D860-4101-AB7B-0C7FB57331CB} = {29B29638-89EC-4383-B587-AE8C981DED4F}
46+
{83B95A2F-1D99-43CB-BA0C-769D88078D6F} = {D6A23A02-D860-4101-AB7B-0C7FB57331CB}
47+
EndGlobalSection
2848
GlobalSection(ExtensibilityGlobals) = postSolution
2949
SolutionGuid = {5C7C0D00-B422-4B19-B6D4-19B55F78389C}
3050
EndGlobalSection

MathCore.TestsExtensions/Accuracy.cs

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,73 @@
11
namespace Microsoft.VisualStudio.TestTools.UnitTesting;
22

3+
/// <summary>Утилиты для создания сравнителей точности и пользовательских сравнителей/проверок равенства</summary>
34
public static class Accuracy
45
{
6+
/// <summary>Создаёт сравнитель чисел типа <see cref="double"/> с заданной абсолютной точностью</summary>
7+
/// <param name="eps">Допустимое отклонение (ε). Должно быть неотрицательным и не NaN</param>
8+
/// <returns>Экземпляр <see cref="IEqualityComparer{Double}"/> и <see cref="IComparer{Double}"/></returns>
9+
/// <exception cref="ArgumentOutOfRangeException">Если <paramref name="eps"/> &lt; 0</exception>
10+
/// <exception cref="ArgumentException">Если <paramref name="eps"/> равен <see cref="double.NaN"/></exception>
511
public static IEqualityComparer<double> Eps(double eps) => new AccuracyComparer(eps);
12+
13+
/// <summary>Создаёт сравнитель целых чисел типа <see cref="int"/> с заданной абсолютной точностью</summary>
14+
/// <param name="eps">Допустимое отклонение (ε). Должно быть неотрицательным</param>
15+
/// <returns>Экземпляр <see cref="IEqualityComparer{Int32}"/> и <see cref="IComparer{Int32}"/></returns>
16+
/// <exception cref="ArgumentOutOfRangeException">Если <paramref name="eps"/> &lt; 0</exception>
617
public static IEqualityComparer<int> Eps(int eps) => new AccuracyComparer(eps);
718

8-
public static IEqualityComparer<T> Equals<T>(Func<T, T, bool> Comparer, Func<T, int> Hasher) => new AccuracyEqualityComparer<T>(Comparer, Hasher);
9-
public static IComparer<T> Compare<T>(Comparison<T> Comparer) => new AccuracyComparer<T>(Comparer);
19+
/// <summary>Создаёт универсальный сравнитель равенства на основе делегатов</summary>
20+
/// <typeparam name="T">Тип сравниваемых объектов</typeparam>
21+
/// <param name="Comparer">Делегат, выполняющий проверку равенства</param>
22+
/// <param name="Hasher">Делегат, вычисляющий хеш-код</param>
23+
/// <returns><see cref="IEqualityComparer{T}"/> использующий предоставленные делегаты</returns>
24+
/// <exception cref="ArgumentNullException">Если один из делегатов равен null</exception>
25+
public static IEqualityComparer<T> Equals<T>(Func<T, T, bool> Comparer, Func<T, int> Hasher) =>
26+
new AccuracyEqualityComparer<T>(Comparer ?? throw new ArgumentNullException(nameof(Comparer)),
27+
Hasher ?? throw new ArgumentNullException(nameof(Hasher)));
28+
29+
/// <summary>Создаёт универсальный сравнитель порядка на основе делегата <see cref="Comparison{T}"/></summary>
30+
/// <typeparam name="T">Тип сравниваемых объектов</typeparam>
31+
/// <param name="Comparer">Делегат сравнения</param>
32+
/// <returns><see cref="IComparer{T}"/> использующий предоставленный делегат</returns>
33+
/// <exception cref="ArgumentNullException">Если <paramref name="Comparer"/> равен null</exception>
34+
public static IComparer<T> Compare<T>(Comparison<T> Comparer) =>
35+
new AccuracyComparer<T>(Comparer ?? throw new ArgumentNullException(nameof(Comparer)));
1036
}
1137

38+
/// <summary>Сравнитель значений типов <see cref="double"/> и <see cref="int"/> с учётом допустимой абсолютной погрешности</summary>
39+
/// <remarks>
40+
/// Для чисел с плавающей точкой равенство определяется условием |x - y| ≤ ε.
41+
/// Для операций хеширования используется нормализация по шагу ε (округление к сетке).
42+
/// </remarks>
43+
/// <param name="Eps">Допустимое отклонение (ε). Должно быть неотрицательным</param>
1244
public readonly struct AccuracyComparer(double Eps) :
1345
IEqualityComparer<double>, IComparer<double>,
1446
IEqualityComparer<int>, IComparer<int>
1547
{
48+
/// <summary>Допустимое абсолютное отклонение</summary>
1649
private double Eps { get; init; } = Eps switch
1750
{
1851
< 0 => throw new ArgumentOutOfRangeException(nameof(Eps), Eps, "Значение точности не должно быть меньше нуля"),
1952
double.NaN => throw new ArgumentException("Значение точности не должно быть NaN", nameof(Eps)),
2053
_ => Eps
2154
};
2255

56+
/// <summary>Проверяет равенство двух значений <see cref="double"/> с учётом точности</summary>
2357
public bool Equals(double x, double y) => Math.Abs(x - y) <= Eps;
2458

25-
public int GetHashCode(double x) => x is double.NaN
26-
? x.GetHashCode()
59+
/// <summary>Вычисляет хеш-код для значения <see cref="double"/>, нормализуя его относительно точности</summary>
60+
/// <param name="x">Значение</param>
61+
/// <returns>Хеш-код</returns>
62+
public int GetHashCode(double x) => x is double.NaN
63+
? x.GetHashCode()
2764
: (Math.Round(x * Eps) / Eps).GetHashCode();
2865

66+
/// <summary>Сравнивает два значения <see cref="double"/> с учётом допустимой погрешности</summary>
67+
/// <param name="x">Первое значение</param>
68+
/// <param name="y">Второе значение</param>
69+
/// <returns>0 если считаются равными; -1 или 1 в зависимости от знака разности</returns>
70+
/// <exception cref="InvalidOperationException">Если одно из значений равно <see cref="double.NaN"/></exception>
2971
public int Compare(double x, double y)
3072
{
3173
var delta = x - y;
@@ -38,15 +80,19 @@ public int Compare(double x, double y)
3880
{ nameof(y), y },
3981
}
4082
};
41-
return Math.Abs(delta) <= Eps
42-
? 0
83+
return Math.Abs(delta) <= Eps
84+
? 0
4385
: Math.Sign(delta);
4486
}
4587

88+
/// <summary>Проверяет равенство двух значений <see cref="int"/> с учётом допустимого отклонения</summary>
4689
public bool Equals(int x, int y) => Math.Abs(x - y) <= Eps;
4790

91+
/// <summary>Вычисляет хеш-код для целого значения с учётом нормализации к сетке точности</summary>
4892
public int GetHashCode(int x) => (Math.Round(x * Eps) / Eps).GetHashCode();
4993

94+
/// <summary>Сравнивает два значения <see cref="int"/> с учётом допустимого отклонения</summary>
95+
/// <returns>0 если считаются равными; -1 или 1 в зависимости от знака разности</returns>
5096
public int Compare(int x, int y)
5197
{
5298
var delta = x - y;
@@ -56,14 +102,24 @@ public int Compare(int x, int y)
56102
}
57103
}
58104

105+
/// <summary>Универсальный сравнитель равенства на основе переданных делегатов</summary>
106+
/// <typeparam name="T">Тип сравниваемых объектов</typeparam>
107+
/// <param name="Comparer">Делегат проверки равенства</param>
108+
/// <param name="Hasher">Делегат вычисления хеш-кода</param>
59109
public class AccuracyEqualityComparer<T>(Func<T, T, bool> Comparer, Func<T, int> Hasher) : IEqualityComparer<T>
60110
{
111+
/// <summary>Проверяет равенство двух объектов</summary>
61112
public bool Equals(T x, T y) => Comparer(x, y);
62113

114+
/// <summary>Вычисляет хеш-код объекта</summary>
63115
public int GetHashCode(T obj) => Hasher(obj);
64116
}
65117

118+
/// <summary>Универсальный сравнитель порядка на основе делегата <see cref="Comparison{T}"/></summary>
119+
/// <typeparam name="T">Тип сравниваемых объектов</typeparam>
120+
/// <param name="Comparer">Делегат сравнения</param>
66121
public class AccuracyComparer<T>(Comparison<T> Comparer) : IComparer<T>
67122
{
123+
/// <summary>Сравнивает два значения</summary>
68124
public int Compare(T x, T y) => Comparer(x, y);
69125
}

MathCore.TestsExtensions/Attributes/DataTestMethodIterativeAttribute.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
// ReSharper disable MemberCanBePrivate.Global
33
// ReSharper disable UnusedAutoPropertyAccessor.Global
44

5+
using System.Runtime.CompilerServices;
6+
57
namespace Microsoft.VisualStudio.TestTools.UnitTesting;
68

79
/// <summary>Итерационное выполнение теста на основе данных с заданием числа итераций для набора статистики</summary>
810
/// <remarks>Инициализация итерационного теста на основе данных</remarks>
911
/// <param name="IterationsCount">Число итераций</param>
1012
[AttributeUsage(AttributeTargets.Method)]
11-
public class DataTestMethodIterativeAttribute(int IterationsCount) : TestMethodAttribute
13+
public class DataTestMethodIterativeAttribute(int IterationsCount, [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = -1)
14+
: TestMethodAttribute(callerFilePath, callerLineNumber)
1215
{
1316
/// <summary>Число итераций повторения теста</summary>
1417
private readonly int _IterationsCount = IterationsCount;
@@ -17,13 +20,13 @@ public class DataTestMethodIterativeAttribute(int IterationsCount) : TestMethodA
1720
public bool StopAtFirstFail { get; set; }
1821

1922
/// <inheritdoc />
20-
public override TestResult[] Execute(ITestMethod TestMethod)
23+
public override async Task<TestResult[]> ExecuteAsync(ITestMethod TestMethod)
2124
{
2225
var results = new List<TestResult>();
2326
var stop_at_first_fail = this.StopAtFirstFail;
2427
for (var count = 0; count < _IterationsCount; count++)
2528
{
26-
var test_results = base.Execute(TestMethod);
29+
var test_results = await base.ExecuteAsync(TestMethod);
2730
results.AddRange(test_results);
2831
if (stop_at_first_fail && test_results.Any(r => r.TestFailureException != null)) break;
2932
}

MathCore.TestsExtensions/Attributes/TestClassHandlerAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ public override TestMethodAttribute GetTestMethodAttribute(TestMethodAttribute A
2727
HandlePassed = HandlePassed,
2828
};
2929

30-
return base.GetTestMethodAttribute(Attribute);
30+
return base.GetTestMethodAttribute(Attribute!)!;
3131
}
3232
}

0 commit comments

Comments
 (0)