diff --git a/.github/workflows/project-build.yml b/.github/workflows/project-build.yml
index a70d8cb..959aa4c 100644
--- a/.github/workflows/project-build.yml
+++ b/.github/workflows/project-build.yml
@@ -17,9 +17,12 @@ jobs:
- name: Build
run: dotnet build -c Release --no-restore
- - name: Test
+ - name: Unit tests
run: dotnet test -c Release --no-restore --no-build -v=normal --collect:"XPlat Code Coverage"
+ - name: Performance tests
+ run: dotnet test -c Release --no-restore --no-build -v=normal --filter TestCategory="PerfTests"
+
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4.0.1
with:
@@ -39,3 +42,10 @@ jobs:
path: bin/NoStringEvaluating.Extensions.Microsoft.DependencyInjection/Release/*.nupkg
retention-days: 1
+ - name: Upload performance tests artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: performance-tests
+ path: bin/NoStringEvaluating.Tests/Release/PerformanceTestsResults/PerformanceTests.txt
+ retention-days: 90
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 87f9ebb..5cae333 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,6 +3,7 @@
+
diff --git a/benchResults/Benchmark.xlsx b/benchResults/Benchmark.xlsx
index 02732d6..9187ce0 100644
Binary files a/benchResults/Benchmark.xlsx and b/benchResults/Benchmark.xlsx differ
diff --git a/src/ConsoleApp/Benchmark/Base/BenchBase.cs b/src/ConsoleApp/Benchmark/Base/BenchBase.cs
index bc3d260..ebfc6b5 100644
--- a/src/ConsoleApp/Benchmark/Base/BenchBase.cs
+++ b/src/ConsoleApp/Benchmark/Base/BenchBase.cs
@@ -139,7 +139,7 @@ private Expression CreateMxParser(string formula)
public const string Formula4 = "(2 + 6 - (13 * 24 + 5 / (123 - 364 + 23))) - (2 + 6 - (13 * 24 + 5 / (123 - 364 + 23))) + (2 + 6 - (13 * 24 + 5 / (123 - 364 + 23))) * 345 * ((897 - 323)/ 23)";
public const string Formula5 = $"{Arg1} * {Arg2} + {Arg3} - {Arg4}";
- public const string Formula6 = $"{Arg1} * ({Arg2} + {Arg3}) - {Arg4} / ({Arg5} - {Arg6}) + 45 * {Arg7} + (({Arg8} * 56 + (12 + {Arg9}))) - {Arg10}";
+ public const string Formula6 = $"{Arg1} * ({Arg2} + {Arg3}) - {Arg4} / ({Arg5} - {Arg6} + 1) + 45 * {Arg7} + (({Arg8} * 56 + (12 + {Arg9}))) - {Arg10}";
public const string Formula7 = $"add(1; 2; 3)";
public const string Formula8 = $"add(add(5; 1) - add(5; 2; 3))";
diff --git a/src/NoStringEvaluating.Tests/Helpers/FormulaModelFactory.cs b/src/NoStringEvaluating.Tests/Helpers/FormulaModelFactory.cs
deleted file mode 100644
index dcd5d0e..0000000
--- a/src/NoStringEvaluating.Tests/Helpers/FormulaModelFactory.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using NoStringEvaluating.Models.Values;
-using NoStringEvaluating.Tests.Models;
-
-namespace NoStringEvaluating.Tests.Helpers;
-
-internal static class FormulaModelFactory
-{
- public static FormulaModel CreateTestModelToCheck(string formula, bool expectedOkresult)
- {
- var model = new FormulaModel(formula, "NULL", double.NaN, expectedOkresult);
- return model;
- }
-
- public static FormulaModel CreateTestModel(string formula, EvaluatorValue result, params (string, EvaluatorValue)[] arguments)
- {
- return CreateTestModel(formula, "NULL", result, arguments);
- }
-
- public static FormulaModel CreateTestModel(string formula, string parsedFormula, EvaluatorValue result, params (string, EvaluatorValue)[] arguments)
- {
- var model = new FormulaModel(formula, parsedFormula, result);
- foreach (var argument in arguments)
- {
- model.Arguments[argument.Item1] = argument.Item2;
- }
-
- return model;
- }
-}
diff --git a/src/NoStringEvaluating.Tests/NoStringEvaluating.Tests.csproj b/src/NoStringEvaluating.Tests/NoStringEvaluating.Tests.csproj
index e3b85f1..f0a633b 100644
--- a/src/NoStringEvaluating.Tests/NoStringEvaluating.Tests.csproj
+++ b/src/NoStringEvaluating.Tests/NoStringEvaluating.Tests.csproj
@@ -9,4 +9,8 @@
+
+
+
+
diff --git a/src/NoStringEvaluating.Tests/PerfTests/PerformanceTests.cs b/src/NoStringEvaluating.Tests/PerfTests/PerformanceTests.cs
new file mode 100644
index 0000000..3e5d0f8
--- /dev/null
+++ b/src/NoStringEvaluating.Tests/PerfTests/PerformanceTests.cs
@@ -0,0 +1,115 @@
+using System.Diagnostics;
+using NoStringEvaluating.Factories;
+using NoStringEvaluating.Functions.Base;
+using NoStringEvaluating.Functions.Logic;
+using NoStringEvaluating.Functions.Math;
+using NoStringEvaluating.Models.Values;
+using NoStringEvaluating.Tests.PerfTests.Report;
+using NUnit.Framework;
+
+namespace NoStringEvaluating.Tests.PerfTests;
+
+[NonParallelizable]
+[Category("PerfTests")]
+[Explicit("These tests are only run when explicitly specified")]
+internal class PerformanceTests
+{
+ private NoStringEvaluator.Facade _serviceFacade;
+ private ReportContainer _report;
+
+ [OneTimeSetUp]
+ public void GlobalSetup()
+ {
+ _report = new();
+ }
+
+ [OneTimeTearDown]
+ public void GlobalTeardown()
+ {
+ ReportWriter.Write(_report);
+ }
+
+ [SetUp]
+ public void Setup()
+ {
+ var functions = new IFunction[]
+ {
+ new AddFunction(),
+ new IfFunction(),
+ new OrFunction(),
+ new Func_kov(),
+ new Func_kovt(),
+ };
+
+ _serviceFacade = NoStringEvaluator.CreateFacade(cfg => cfg.WithoutDefaultFunctions().WithFunctions(functions));
+ }
+
+ [TestCaseSource(nameof(RunSource))]
+ public void RunFormula(string formulaName, string formula, IDictionary args, long targetElapsedMilliseconds)
+ {
+ // arrange
+ var n = 1_000_000;
+
+ var nodes = _serviceFacade.FormulaCache.GetFormulaNodes(formula);
+
+ // act, assert
+ var res = _serviceFacade.Evaluator.CalcNumber(nodes, args);
+
+ var ela = Stopwatch.StartNew();
+ for (var i = 0; i < n; i++)
+ {
+ _ = _serviceFacade.Evaluator.Calc(nodes, args);
+ }
+
+ ela.Stop();
+
+ _report.Append(formulaName, res, ela.ElapsedMilliseconds, targetElapsedMilliseconds);
+ }
+
+ private static IEnumerable