|
| 1 | +// |
| 2 | +// Copyright (c) 2019-2022 Angouri. |
| 3 | +// AngouriMath is licensed under MIT. |
| 4 | +// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md. |
| 5 | +// Website: https://am.angouri.org. |
| 6 | +// |
| 7 | + |
| 8 | +using AngouriMath; |
| 9 | +using AngouriMath.Core; |
| 10 | +using AngouriMath.Extensions; |
| 11 | +using Xunit; |
| 12 | + |
| 13 | +namespace AngouriMath.Tests.Common |
| 14 | +{ |
| 15 | + /// <summary> |
| 16 | + /// Issues that are open in the tracker but no longer reproduce. Nothing here is a |
| 17 | + /// fix: each test pins behaviour that already works, so that its issue can be closed |
| 18 | + /// without leaving the fix that closed it unprotected. Every case is the reporter's |
| 19 | + /// own, taken from the issue. |
| 20 | + /// </summary> |
| 21 | + public sealed class AlreadyFixedIssuesTest |
| 22 | + { |
| 23 | + private static readonly System.TimeSpan Budget = System.TimeSpan.FromSeconds(30); |
| 24 | + |
| 25 | + /// <summary> |
| 26 | + /// Runs work that used to hang or overflow the stack, and fails if it does not |
| 27 | + /// finish. Asserted as termination rather than as a duration, so the test does not |
| 28 | + /// turn flaky on a slow machine, and so a regression fails the run instead of |
| 29 | + /// hanging it. |
| 30 | + /// </summary> |
| 31 | + private static T Terminates<T>(System.Func<T> work, string what) |
| 32 | + { |
| 33 | + var task = System.Threading.Tasks.Task.Run(work); |
| 34 | + Assert.True(task.Wait(Budget), $"{what} did not finish within {Budget.TotalSeconds}s"); |
| 35 | + return task.Result; |
| 36 | + } |
| 37 | + |
| 38 | + // https://github.com/asc-community/AngouriMath/issues/263 |
| 39 | + // InnerSimplify never returned on the reporter's quotient, and neither did the |
| 40 | + // limit it was reached from. |
| 41 | + private const string Issue263Quotient = |
| 42 | + "(x ^ 15 - 3 ^ 15 - 15 * 3 ^ 14 * (x - 3)) / (x - 3) ^ 2"; |
| 43 | + |
| 44 | + [Fact] |
| 45 | + public void Issue263_InnerSimplifyTerminates() => |
| 46 | + Terminates(() => Issue263Quotient.ToEntity().InnerSimplified, |
| 47 | + "InnerSimplify of the #263 quotient"); |
| 48 | + |
| 49 | + [Fact] |
| 50 | + public void Issue263_LimitTerminates() => |
| 51 | + Terminates(() => Issue263Quotient.ToEntity().Limit("x", 3, ApproachFrom.Left), |
| 52 | + "the #263 limit"); |
| 53 | + |
| 54 | + // https://github.com/asc-community/AngouriMath/issues/347 |
| 55 | + // Taking a limit of a boolean expression overflowed the stack. It is still not |
| 56 | + // evaluated -- there is nothing to evaluate -- but it comes back rather than |
| 57 | + // taking the process down. |
| 58 | + [Fact] |
| 59 | + public void Issue347_LimitOfABooleanDoesNotCrash() => |
| 60 | + Terminates(() => "a and x".ToEntity().Limit("x", "+oo"), "lim (a and x)"); |
| 61 | + |
| 62 | + // https://github.com/asc-community/AngouriMath/issues/362 |
| 63 | + // Simplified to (-3/2 * d - d / 2) * t, which is the same number written worse. |
| 64 | + [Fact] |
| 65 | + public void Issue362_CoefficientsAreCollected() => |
| 66 | + Assert.Equal("(-2) * d * t", "(-1/2d-3/2d)t".ToEntity().Simplify().Stringize()); |
| 67 | + |
| 68 | + // https://github.com/asc-community/AngouriMath/issues/424 |
| 69 | + // Piecewise was to become compileable. |
| 70 | + [Theory] |
| 71 | + [InlineData("5 provided x = 3", 3.0, 5.0)] |
| 72 | + [InlineData("x provided true", 7.0, 7.0)] |
| 73 | + [InlineData("2 * x provided x > 0", 4.0, 8.0)] |
| 74 | + public void Issue424_PiecewiseCompiles(string expression, double argument, double expected) => |
| 75 | + Assert.Equal(expected, expression.ToEntity().Compile<double, double>("x")(argument), 9); |
| 76 | + |
| 77 | + // https://github.com/asc-community/AngouriMath/issues/415 |
| 78 | + // Intersections and unions of intervals were to be simplified. |
| 79 | + [Fact] |
| 80 | + public void Issue415_IntervalsIntersect() => |
| 81 | + Assert.Equal(@"[3; 5]".ToEntity(), @"[1; 5] /\ [3; 8]".ToEntity().Simplify()); |
| 82 | + |
| 83 | + [Fact] |
| 84 | + public void Issue415_IntervalsUnite() => |
| 85 | + Assert.Equal(@"[1; 8]".ToEntity(), @"[1; 5] \/ [3; 8]".ToEntity().Simplify()); |
| 86 | + |
| 87 | + // https://github.com/asc-community/AngouriMath/issues/550 |
| 88 | + // The reporter's small system did not solve. The 25x26 one from the same report |
| 89 | + // is a question of scale and is tracked separately at #608. |
| 90 | + [Fact] |
| 91 | + public void Issue550_SmallLinearSystemSolves() |
| 92 | + { |
| 93 | + var equations = new[] |
| 94 | + { |
| 95 | + "x - y + 2 * z - 6", |
| 96 | + "2 * x + 3 * y + 2 * z - 11", |
| 97 | + "x + 2 * y + z - 8" |
| 98 | + }; |
| 99 | + var solution = MathS.Equations(equations[0], equations[1], equations[2]).Solve("x", "y", "z"); |
| 100 | + Assert.NotNull(solution); |
| 101 | + var (x, y, z) = (solution![0, 0], solution[0, 1], solution[0, 2]); |
| 102 | + // Checked by substitution rather than against printed values, so the test does |
| 103 | + // not depend on which form the solver hands the roots back in. |
| 104 | + foreach (var equation in equations) |
| 105 | + { |
| 106 | + var residual = equation.ToEntity() |
| 107 | + .Substitute("x", x).Substitute("y", y).Substitute("z", z) |
| 108 | + .EvalNumerical(); |
| 109 | + Assert.True(residual.Abs().EDecimal.ToDouble() < 1e-9, |
| 110 | + $"{equation} left {residual.Stringize()} at the reported solution"); |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + // https://github.com/asc-community/AngouriMath/issues/164 |
| 115 | + // Reported as leaving sixteen uncollected terms. |
| 116 | + [Fact] |
| 117 | + public void Issue164_RepeatedFactorCollects() => |
| 118 | + Assert.Equal("(1 + x) ^ 4".ToEntity(), "(x+1)^2*(x+2-1)^2".ToEntity().Simplify()); |
| 119 | + } |
| 120 | +} |
0 commit comments