using System; using System.Collections.Generic; using System.Linq; using UnitTestSharp; namespace Blacklight.Bezier.UnitTests { public class SampleSetTests : TestFixture { public class CtorTests : TestFixture { public void KeepsTheNameAndSamples() { var samples = new[] { ShellSample.FromPosition(1, 2, 3) }; var set = new SampleSet("Name", samples); CheckEqual("Name", set.Name); Check(ReferenceEquals(samples, set.Samples)); } } } public class SampleSetsTests : TestFixture { public const int Draws = 2000; public static IEnumerable Draw(Func generator) { var random = new Random(7); for (int i = 0; i < Draws; i++) { yield return generator(random); } } public class UniformTests : TestFixture { public void StaysWithinTheRange() { var random = new Random(1); for (int i = 0; i < Draws; i++) { double value = SampleSets.Uniform(random, 2, 5); Check(value >= 2 && value <= 5); } } } public class LogUniformTests : TestFixture { public void StaysWithinTheRange() { var random = new Random(1); for (int i = 0; i < Draws; i++) { double value = SampleSets.LogUniform(random, 1e-3, 1e3); Check(value >= 1e-3 * (1 - 1e-12) && value <= 1e3 * (1 + 1e-12)); } } } public class NormalTests : TestFixture { public void HasTheRequestedSpreadAroundZero() { var random = new Random(1); double[] values = Enumerable.Range(0, 20000).Select(i => SampleSets.Normal(random, 3)).ToArray(); double mean = values.Average(); double deviation = Math.Sqrt(values.Select(value => (value - mean) * (value - mean)).Average()); CheckGreater(0.1, Math.Abs(mean)); CheckGreater(0.05, Math.Abs(deviation / 3 - 1)); } } public class RandomSignTests : TestFixture { public void ReturnsBothSignsAndNothingElse() { var random = new Random(1); double[] signs = Enumerable.Range(0, 100).Select(i => SampleSets.RandomSign(random)).ToArray(); Check(signs.All(sign => sign == 1 || sign == -1)); Check(signs.Contains(1) && signs.Contains(-1)); } } public class EndTests : TestFixture { public void IsAFloatWithinTheRange() { var random = new Random(1); for (int i = 0; i < Draws; i++) { double end = SampleSets.End(random); CheckEqual(end, (double)(float)end); Check(end >= 1e-3 * (1 - 1e-6) && end <= 1e7); } } } public class AlongNormalTests : TestFixture { public void LandsAtTheOffsetFromTheFoot() { ReferenceResult result = ReferenceDistance.Solve(SampleSets.AlongNormal(foot: 3, offset: 0.25, end: 10)); CheckGreater(1e-12, Math.Abs(result.Distance - 0.25)); CheckGreater(1e-9, Math.Abs(result.ClosestX - 3)); } public void PhiAgreesWithThePosition() { ShellSample sample = SampleSets.AlongNormal(foot: 3, offset: 0.25, end: 10); CheckGreater(1e-12, Math.Abs(sample.Phi - (sample.Y - sample.X * sample.X / 2))); } } public class NearCurveTests : TestFixture { public void OnAPieceHoldingTheFoot_EveryPointIsWithinTheLargestOffset() { foreach (ShellSample sample in Draw(SampleSets.NearCurve(1e-4, 1e1))) { var onLongPiece = new ShellSample(sample.X, sample.Y, sample.Phi, end: 1e7); CheckGreater(1e2 * (1 + 1e-9), ReferenceDistance.Solve(onLongPiece).Distance); } } } public class DoubleRootTests : TestFixture { public void LiesJustOffThePiecesOwnEvolute() { foreach (ShellSample sample in Draw(SampleSets.DoubleRoot)) { double foot = Math.Sqrt((sample.Y - 1) / 1.5); CheckGreater(1.02, sample.X / (-foot * foot * foot)); CheckLess(0.98, sample.X / (-foot * foot * foot)); } } } public class TieLineTests : TestFixture { public void LiesAcrossTheAxisAboveTheVertexCentreOfCurvature() { foreach (ShellSample sample in Draw(SampleSets.TieLine)) { CheckGreater(0.0, sample.X); CheckLess(1.0, sample.Y); } } } public class WholePlaneTests : TestFixture { public void StaysWithinTheRadiusRange() { foreach (ShellSample sample in Draw(SampleSets.WholePlane)) { double radius = Math.Sqrt(sample.X * sample.X + sample.Y * sample.Y); Check(radius >= 1e-4 * (1 - 1e-9) && radius <= 1e6 * (1 + 1e-9)); } } } public class EvolutesTests : TestFixture { public void LiesNearAnEvolute() { foreach (ShellSample sample in Draw(SampleSets.Evolutes)) { double onEvolute = 1 + 1.5 * Math.Pow(Math.Abs(sample.X), 2.0 / 3.0); CheckGreater(0.02, Math.Abs(sample.Y / onEvolute - 1)); } } } public class VertexAndFocusTests : TestFixture { public void StaysNearTheVertexCentreOfCurvature() { foreach (ShellSample sample in Draw(SampleSets.VertexAndFocus)) { CheckGreater(1e-2, Math.Abs(sample.X)); CheckGreater(1e-2, Math.Abs(sample.Y - 1)); } } } public class WorstShapeTests : TestFixture { public void KeepsTheTwoStartBoundsComparable() { foreach (ShellSample sample in Draw(SampleSets.WorstShape)) { double ratio = Math.Sqrt(2 * (sample.Y - 1)) / Math.Pow(2 * sample.X, 1.0 / 3.0); Check(ratio >= Math.Sqrt(1.3) * (1 - 1e-9) && ratio <= Math.Sqrt(2.0) * (1 + 1e-9)); } } } public class NearAxisTests : TestFixture { public void StaysWithinUnitDistanceOfTheAxis() { foreach (ShellSample sample in Draw(SampleSets.NearAxis)) { CheckGreater(1.0 + 1e-12, Math.Abs(sample.X)); } } } public class CreateTests : TestFixture { public void MakesTwelveDistinctlyNamedSetsOfTheRequestedSize() { List sets = SampleSets.Create(samplesPerSet: 10, seed: 1); CheckEqual(12, sets.Count); CheckEqual(12, sets.Select(set => set.Name).Distinct().Count()); Check(sets.All(set => set.Samples.Length == 10)); } public void SameSeed_SameSamples() { List first = SampleSets.Create(samplesPerSet: 10, seed: 1); List second = SampleSets.Create(samplesPerSet: 10, seed: 1); Check(first.Zip(second, (left, right) => left.Samples.SequenceEqual(right.Samples)).All(same => same)); } public void DifferentSeed_DifferentSamples() { List first = SampleSets.Create(samplesPerSet: 10, seed: 1); List second = SampleSets.Create(samplesPerSet: 10, seed: 2); CheckFalse(first[0].Samples.SequenceEqual(second[0].Samples)); } } } }