tests(stdlib): reorganize and expand StandardLibrary tests
- Switch tests to use Initializer.InitializeAll for setup - Split stdlib tests by category: Angle, Rounding, Trig (incl. hyperbolic), NumberTheory, Random - Add comprehensive tests invoking functions via InputInterpreter.Interpret() - Register Bernoulli in Initializer so random tests cover
This commit is contained in:
parent
1d86b2bc19
commit
106efbc86e
7 changed files with 410 additions and 3 deletions
|
@ -118,6 +118,7 @@ namespace CSMic.StandardLibrary
|
|||
}
|
||||
|
||||
inputInterpreter.RegisterFunction(new FairFlip());
|
||||
inputInterpreter.RegisterFunction(new Bernoulli());
|
||||
inputInterpreter.RegisterFunction(new RandomUniform());
|
||||
inputInterpreter.RegisterFunction(new RandomUniformSpread());
|
||||
inputInterpreter.RegisterFunction(new RandomNormal());
|
||||
|
|
57
src/Tests/AngleFunctionsTests.cs
Normal file
57
src/Tests/AngleFunctionsTests.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
using System.Globalization;
|
||||
using CSMic;
|
||||
using CSMic.StandardLibrary;
|
||||
|
||||
namespace CSMic.Tests;
|
||||
|
||||
public class AngleFunctionsTests
|
||||
{
|
||||
private InputInterpreter _interp = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
_interp = new InputInterpreter();
|
||||
Initializer.InitializeAll(_interp);
|
||||
}
|
||||
|
||||
private static void AssertSuccess(decimal result, decimal expected, InputInterpreter interp)
|
||||
{
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
Assert.That(interp.NumericValue, Is.EqualTo(expected));
|
||||
Assert.That(interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
private static void AssertApprox(decimal result, decimal expected, decimal tol, InputInterpreter interp)
|
||||
{
|
||||
Assert.That(Math.Abs(result - expected) <= tol, $"Expected ~{expected} ± {tol}, got {result}");
|
||||
Assert.That(interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Degrees_Works_OnCommonValues()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("degrees(0)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("degrees(pi)"), 180m, _interp);
|
||||
AssertSuccess(_interp.Interpret("degrees(tau)"), 360m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Radians_Works_OnCommonValues()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("radians(0)"), 0m, _interp);
|
||||
var res = _interp.Interpret("radians(180)");
|
||||
// Approximately pi
|
||||
AssertApprox(res, 3.1415926535897931m, 0.0000000000001m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WrapAngle_WrapsIntoRange()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("wrapangle(-10, 0, 360)"), 350m, _interp);
|
||||
AssertSuccess(_interp.Interpret("wrapangle(370, 0, 360)"), 10m, _interp);
|
||||
AssertSuccess(_interp.Interpret("wrapangle(361, -180, 180)"), -179m, _interp);
|
||||
}
|
||||
}
|
||||
|
84
src/Tests/NumberTheoryFunctionsTests.cs
Normal file
84
src/Tests/NumberTheoryFunctionsTests.cs
Normal file
|
@ -0,0 +1,84 @@
|
|||
using System.Globalization;
|
||||
using CSMic;
|
||||
using CSMic.StandardLibrary;
|
||||
|
||||
namespace CSMic.Tests;
|
||||
|
||||
public class NumberTheoryFunctionsTests
|
||||
{
|
||||
private InputInterpreter _interp = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
_interp = new InputInterpreter();
|
||||
Initializer.InitializeAll(_interp);
|
||||
}
|
||||
|
||||
private static void AssertSuccess(decimal result, decimal expected, InputInterpreter interp)
|
||||
{
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
Assert.That(interp.NumericValue, Is.EqualTo(expected));
|
||||
Assert.That(interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
private static void AssertApprox(decimal result, decimal expected, decimal tol, InputInterpreter interp)
|
||||
{
|
||||
Assert.That(Math.Abs(result - expected) <= tol, $"Expected ~{expected} ± {tol}, got {result}");
|
||||
Assert.That(interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Gcd_Works_And_Validates()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("gcd(54, 24)"), 6m, _interp);
|
||||
AssertSuccess(_interp.Interpret("gcd(7, 3)"), 1m, _interp);
|
||||
AssertSuccess(_interp.Interpret("gcd(0, 5)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("gcd(5.5, 2)"), 0m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Lcm_Works_And_Validates()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("lcm(4, 6)"), 12m, _interp);
|
||||
AssertSuccess(_interp.Interpret("lcm(21, 6)"), 42m, _interp);
|
||||
AssertSuccess(_interp.Interpret("lcm(-2, 6)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("lcm(2.5, 6)"), 0m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BinomialCoefficient_Works_And_Validates()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("ncr(5, 2)"), 10m, _interp);
|
||||
AssertSuccess(_interp.Interpret("ncr(20, 0)"), 1m, _interp);
|
||||
AssertSuccess(_interp.Interpret("ncr(5, -1)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("ncr(5, 6)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("ncr(5.2, 2)"), 0m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Permutations_Works_And_Validates()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("npr(5, 2)"), 20m, _interp);
|
||||
AssertSuccess(_interp.Interpret("npr(6, 6)"), 720m, _interp);
|
||||
AssertSuccess(_interp.Interpret("npr(5, 6)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("npr(5.2, 2)"), 0m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Factorial_Works_And_Validates()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("fac(0)"), 1m, _interp);
|
||||
AssertSuccess(_interp.Interpret("fac(1)"), 1m, _interp);
|
||||
AssertSuccess(_interp.Interpret("fac(5)"), 120m, _interp);
|
||||
AssertSuccess(_interp.Interpret("fac(20)"), 2432902008176640000m, _interp);
|
||||
AssertSuccess(_interp.Interpret("fac(-1)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("fac(21)"), 0m, _interp);
|
||||
|
||||
var res = _interp.Interpret("fac(0.5)");
|
||||
// Gamma(1.5) ~= sqrt(pi)/2 ~= 0.8862269254527579
|
||||
AssertApprox(res, 0.8862269254527579m, 0.0000000000001m, _interp);
|
||||
}
|
||||
}
|
||||
|
99
src/Tests/RandomFunctionsTests.cs
Normal file
99
src/Tests/RandomFunctionsTests.cs
Normal file
|
@ -0,0 +1,99 @@
|
|||
using System.Globalization;
|
||||
using CSMic;
|
||||
using CSMic.StandardLibrary;
|
||||
|
||||
namespace CSMic.Tests;
|
||||
|
||||
public class RandomFunctionsTests
|
||||
{
|
||||
private InputInterpreter _interp = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
_interp = new InputInterpreter();
|
||||
Initializer.InitializeAll(_interp);
|
||||
}
|
||||
|
||||
private static void AssertSuccess(decimal result, decimal expected, InputInterpreter interp)
|
||||
{
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
Assert.That(interp.NumericValue, Is.EqualTo(expected));
|
||||
Assert.That(interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Flip_ReturnsBooleanAsNumeric()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var res = _interp.Interpret("flip()");
|
||||
Assert.That(res == 0m || res == 1m, "flip() must return 0 or 1");
|
||||
Assert.That(_interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Rand_IsWithinUnitInterval()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var res = _interp.Interpret("rand()");
|
||||
Assert.That(res, Is.GreaterThanOrEqualTo(0m));
|
||||
Assert.That(res, Is.LessThan(1m));
|
||||
Assert.That(_interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RandSpread_IsWithinBounds_And_Validates()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var res = _interp.Interpret("rands(5, 10)");
|
||||
Assert.That(res, Is.GreaterThanOrEqualTo(5m));
|
||||
Assert.That(res, Is.LessThan(10m));
|
||||
Assert.That(_interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
AssertSuccess(_interp.Interpret("rands(10, 5)"), 0m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RandNormal_ProducesNumeric()
|
||||
{
|
||||
bool sawNonZero = false;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var res = _interp.Interpret("randn()");
|
||||
if (res != 0m) sawNonZero = true;
|
||||
Assert.That(_interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
Assert.That(sawNonZero, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RandNormalSpread_ValidatesBounds()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("randns(10, 5)"), 0m, _interp);
|
||||
// With valid bounds, it should succeed and produce a numeric (any value)
|
||||
var res = _interp.Interpret("randns(5, 10)");
|
||||
Assert.That(_interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Bernoulli_ValidatesP_And_ReturnsBoolean()
|
||||
{
|
||||
// Invalid p produces soft error (message populated)
|
||||
_interp.Interpret("bern(-0.1)");
|
||||
Assert.That(string.IsNullOrEmpty(_interp.StringValue), Is.False);
|
||||
_interp.Interpret("bern(1.1)");
|
||||
Assert.That(string.IsNullOrEmpty(_interp.StringValue), Is.False);
|
||||
|
||||
// Valid p returns 0 or 1 without error
|
||||
var res = _interp.Interpret("bern(0.7)");
|
||||
Assert.That(res == 0m || res == 1m);
|
||||
Assert.That(_interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
}
|
69
src/Tests/RoundingFunctionsTests.cs
Normal file
69
src/Tests/RoundingFunctionsTests.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using System.Globalization;
|
||||
using CSMic;
|
||||
using CSMic.StandardLibrary;
|
||||
|
||||
namespace CSMic.Tests;
|
||||
|
||||
public class RoundingFunctionsTests
|
||||
{
|
||||
private InputInterpreter _interp = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
_interp = new InputInterpreter();
|
||||
Initializer.InitializeAll(_interp);
|
||||
}
|
||||
|
||||
private static void AssertSuccess(decimal result, decimal expected, InputInterpreter interp)
|
||||
{
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
Assert.That(interp.NumericValue, Is.EqualTo(expected));
|
||||
Assert.That(interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Floor_Works()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("floor(2.3)"), 2m, _interp);
|
||||
AssertSuccess(_interp.Interpret("floor(-2.3)"), -3m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ceiling_Works()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("ceiling(2.3)"), 3m, _interp);
|
||||
AssertSuccess(_interp.Interpret("ceiling(-2.3)"), -2m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Truncate_Works()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("truncate(2.9)"), 2m, _interp);
|
||||
AssertSuccess(_interp.Interpret("truncate(-2.9)"), -2m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Fractional_Works()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("frac(2.75)"), 0.75m, _interp);
|
||||
AssertSuccess(_interp.Interpret("frac(-2.75)"), -0.75m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Round_WithPrecision_Works()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("round(2.346, 2)"), 2.35m, _interp);
|
||||
AssertSuccess(_interp.Interpret("round(2.344, 2)"), 2.34m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Clamp_Works()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("clamp(5, 1, 10)"), 5m, _interp);
|
||||
AssertSuccess(_interp.Interpret("clamp(0, 1, 10)"), 1m, _interp);
|
||||
AssertSuccess(_interp.Interpret("clamp(11, 1, 10)"), 10m, _interp);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ using CSMic.StandardLibrary;
|
|||
using NUnit.Framework;
|
||||
using CSMic.StandardLibrary.Functions;
|
||||
using System.Globalization;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace CSMic.Tests;
|
||||
|
||||
|
@ -16,8 +15,8 @@ public class StdlibFunctionsTests
|
|||
{
|
||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
_interp = new InputInterpreter();
|
||||
Constants.Initialize(_interp);
|
||||
Functions.Initialize(_interp); ;
|
||||
// Initialize full standard library (functions + constants)
|
||||
Initializer.InitializeAll(_interp);
|
||||
}
|
||||
|
||||
private static void AssertSuccess(decimal result, decimal expected, InputInterpreter interp)
|
||||
|
|
98
src/Tests/TrigonometryFunctionsTests.cs
Normal file
98
src/Tests/TrigonometryFunctionsTests.cs
Normal file
|
@ -0,0 +1,98 @@
|
|||
using System.Globalization;
|
||||
using CSMic;
|
||||
using CSMic.StandardLibrary;
|
||||
|
||||
namespace CSMic.Tests;
|
||||
|
||||
public class TrigonometryFunctionsTests
|
||||
{
|
||||
private InputInterpreter _interp = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
_interp = new InputInterpreter();
|
||||
Initializer.InitializeAll(_interp);
|
||||
}
|
||||
|
||||
private static void AssertSuccess(decimal result, decimal expected, InputInterpreter interp)
|
||||
{
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
Assert.That(interp.NumericValue, Is.EqualTo(expected));
|
||||
Assert.That(interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
private static void AssertApprox(decimal result, decimal expected, decimal tol, InputInterpreter interp)
|
||||
{
|
||||
Assert.That(Math.Abs(result - expected) <= tol, $"Expected ~{expected} ± {tol}, got {result}");
|
||||
Assert.That(interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BasicTrig_ZeroPoints()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("sin(0)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("cos(0)"), 1m, _interp);
|
||||
AssertSuccess(_interp.Interpret("tan(0)"), 0m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BasicTrig_CommonAngles()
|
||||
{
|
||||
AssertApprox(_interp.Interpret("sin(pi/2)"), 1m, 0.0000000000001m, _interp);
|
||||
AssertApprox(_interp.Interpret("cos(pi/2)"), 0m, 0.0000000000001m, _interp);
|
||||
AssertApprox(_interp.Interpret("tan(pi/4)"), 1m, 0.0000000000001m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InverseTrig_ZeroPoints()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("asin(0)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("acos(1)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("atan(0)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("atan2(0, 1)"), 0m, _interp);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InverseTrig_CommonValues()
|
||||
{
|
||||
// asin(1) ~= pi/2, acos(0) ~= pi/2, atan(1) ~= pi/4, atan2(1,0) ~= pi/2
|
||||
AssertApprox(_interp.Interpret("asin(1)"), 1.5707963267948966m, 0.0000000000001m, _interp);
|
||||
AssertApprox(_interp.Interpret("acos(0)"), 1.5707963267948966m, 0.0000000000001m, _interp);
|
||||
AssertApprox(_interp.Interpret("atan(1)"), 0.7853981633974483m, 0.0000000000001m, _interp);
|
||||
AssertApprox(_interp.Interpret("atan2(1, 0)"), 1.5707963267948966m, 0.0000000000001m, _interp);
|
||||
}
|
||||
}
|
||||
|
||||
public class HyperbolicTrigFunctionsTests
|
||||
{
|
||||
private InputInterpreter _interp = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
_interp = new InputInterpreter();
|
||||
Initializer.InitializeAll(_interp);
|
||||
}
|
||||
|
||||
private static void AssertSuccess(decimal result, decimal expected, InputInterpreter interp)
|
||||
{
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
Assert.That(interp.NumericValue, Is.EqualTo(expected));
|
||||
Assert.That(interp.StringValue, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Hyperbolic_ZeroPoints()
|
||||
{
|
||||
AssertSuccess(_interp.Interpret("sinh(0)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("cosh(0)"), 1m, _interp);
|
||||
AssertSuccess(_interp.Interpret("tanh(0)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("asinh(0)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("acosh(1)"), 0m, _interp);
|
||||
AssertSuccess(_interp.Interpret("atanh(0)"), 0m, _interp);
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue