From 2ead3cbb8adb2c071045c5949e87e46b229e290a Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Mon, 25 Apr 2022 22:14:11 +0100 Subject: [PATCH] Add exhaustive Random tests Introduces NextInt16 and NextByte --- X10D.Tests/src/Core/RandomTests.cs | 245 ++++++++++++++++++ .../RandomExtensions.cs | 166 +++++++++++- 2 files changed, 407 insertions(+), 4 deletions(-) create mode 100644 X10D.Tests/src/Core/RandomTests.cs rename X10D/src/{RandomExtensions => Core}/RandomExtensions.cs (57%) diff --git a/X10D.Tests/src/Core/RandomTests.cs b/X10D.Tests/src/Core/RandomTests.cs new file mode 100644 index 0000000..41d182b --- /dev/null +++ b/X10D.Tests/src/Core/RandomTests.cs @@ -0,0 +1,245 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Core; + +namespace X10D.Tests.Core; + +[TestClass] +public class RandomTests +{ + [TestMethod] + public void NextBoolean_ShouldBeFalse_GivenSeed1234() + { + var random = new Random(1234); + Assert.IsFalse(random.NextBoolean()); + } + + [TestMethod] + public void NextBoolean_ShouldThrow_GivenNull() + { + Random? random = null; + Assert.ThrowsException(() => random!.NextBoolean()); + } + + [TestMethod] + public void NextByte_ShouldBe101_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(101, random.NextByte()); + } + + [TestMethod] + public void NextByte_WithMax10_ShouldBe3_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(3, random.NextByte(10)); + } + + [TestMethod] + public void NextByte_WithMin0Max10_ShouldBe3_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(3, random.NextByte(0, 10)); + } + + [TestMethod] + public void NextByte_ShouldThrow_GivenNull() + { + Random? random = null; + Assert.ThrowsException(() => random!.NextByte()); + Assert.ThrowsException(() => random!.NextByte(10)); + Assert.ThrowsException(() => random!.NextByte(0, 10)); + } + + [TestMethod] + public void NextDouble_WithMax10_ShouldBe3point9908097935797695_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(3.9908097935797695, random.NextDouble(10)); + } + + [TestMethod] + public void NextDouble_WithMin0Max10_ShouldBe3point9908097935797695_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(3.9908097935797695, random.NextDouble(0, 10)); + } + + [TestMethod] + public void NextDouble_ShouldThrow_GivenNull() + { + Random? random = null; + Assert.ThrowsException(() => random!.NextDouble(10)); + Assert.ThrowsException(() => random!.NextDouble(0, 10)); + } + + [TestMethod] + public void NextDouble_ShouldThrow_GivenMaxLessThan0() + { + var random = new Random(1234); + Assert.ThrowsException(() => random.NextDouble(-1)); + } + + [TestMethod] + public void NextDouble_ShouldThrow_GivenMaxLessThanMin() + { + var random = new Random(1234); + Assert.ThrowsException(() => random.NextDouble(0, -1)); + } + + [TestMethod] + public void NextEnum_ShouldBeTuesday_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(DayOfWeek.Tuesday, random.Next()); + } + + [TestMethod] + public void NextEnum_ShouldThrow_GivenNull() + { + Random? random = null; + Assert.ThrowsException(() => random!.Next()); + } + + [TestMethod] + public void NextFrom_ShouldThrow_GivenNullRandom() + { + Random? random = null; + Assert.ThrowsException(() => random!.NextFrom("")); + } + + [TestMethod] + public void NextFrom_ShouldThrow_GivenNullSource() + { + var random = new Random(1234); + Assert.ThrowsException(() => random.NextFrom((string?)null!)); + } + + [TestMethod] + public void NextFrom_ShouldEnumerate_GivenNonList() + { + IEnumerable Source() + { + yield return 0; + } + + var random = new Random(1234); + Assert.AreEqual(0, random.NextFrom(Source())); + } + + [TestMethod] + public void NextInt16_ShouldBe13076_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(13076, random.NextInt16()); + } + + [TestMethod] + public void NextInt16_WithMax10_ShouldBe3_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(3, random.NextInt16(10)); + } + + [TestMethod] + public void NextInt16_WithMin0Max10_ShouldBe3_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(3, random.NextInt16(0, 10)); + } + + [TestMethod] + public void NextInt16_ShouldThrow_GivenMaxLessThan0() + { + var random = new Random(1234); + Assert.ThrowsException(() => random.NextInt16(-1)); + } + + [TestMethod] + public void NextInt16_ShouldThrow_GivenNull() + { + Random? random = null; + Assert.ThrowsException(() => random!.NextInt16()); + Assert.ThrowsException(() => random!.NextInt16(10)); + Assert.ThrowsException(() => random!.NextInt16(0, 10)); + } + + [TestMethod] + public void NextSingle_WithMax10_ShouldBe3point99081_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(3.99081f, random.NextSingle(10)); + } + + [TestMethod] + public void NextSingle_WithMin0Max10_ShouldBe3point99081_GivenSeed1234() + { + var random = new Random(1234); + Assert.AreEqual(3.99081f, random.NextSingle(0, 10)); + } + + [TestMethod] + public void NextSingle_ShouldThrow_GivenNull() + { + Random? random = null; + Assert.ThrowsException(() => random!.NextSingle(10)); + Assert.ThrowsException(() => random!.NextSingle(0, 10)); + } + + [TestMethod] + public void NextSingle_ShouldThrow_GivenMaxLessThan0() + { + var random = new Random(1234); + Assert.ThrowsException(() => random.NextSingle(-1)); + } + + [TestMethod] + public void NextSingle_ShouldThrow_GivenMaxLessThanMin() + { + var random = new Random(1234); + Assert.ThrowsException(() => random.NextSingle(0, -1)); + } + + [TestMethod] + public void NextString_ShouldBe_kxiyiyvnqi_GivenSeed1234() + { + const string alphabet = "abcdefghijklmnopqrstuvwxyz"; + + var random = new Random(1234); + Assert.AreEqual("kxiyiyvnqi", random.NextString(alphabet.ToCharArray(), 10)); + } + + [TestMethod] + public void NextString_ShouldBeEmpty_GivenLength0() + { + var random = new Random(1234); + Assert.AreEqual(string.Empty, random.NextString(ArraySegment.Empty, 0)); + } + + [TestMethod] + public void NextString_ShouldBeLength1_GivenLength1() + { + var random = new Random(1234); + Assert.AreEqual(1, random.NextString("hello world".ToCharArray(), 1).Length); + } + + [TestMethod] + public void NextString_ShouldThrow_GivenNullRandom() + { + Random? random = null; + Assert.ThrowsException(() => random!.NextString(ArraySegment.Empty, 0)); + } + + [TestMethod] + public void NextString_ShouldThrow_GivenNullSource() + { + var random = new Random(1234); + Assert.ThrowsException(() => random.NextString(null!, 0)); + } + + [TestMethod] + public void NextString_ShouldThrow_GivenNegativeLength() + { + var random = new Random(1234); + Assert.ThrowsException(() => random.NextString(ArraySegment.Empty, -1)); + } +} diff --git a/X10D/src/RandomExtensions/RandomExtensions.cs b/X10D/src/Core/RandomExtensions.cs similarity index 57% rename from X10D/src/RandomExtensions/RandomExtensions.cs rename to X10D/src/Core/RandomExtensions.cs index 1271c01..a2c4ac9 100644 --- a/X10D/src/RandomExtensions/RandomExtensions.cs +++ b/X10D/src/Core/RandomExtensions.cs @@ -2,7 +2,7 @@ using System.Text; using X10D.Math; -namespace X10D; +namespace X10D.Core; /// /// Extension methods for . @@ -64,7 +64,7 @@ public static class RandomExtensions /// . /// /// is . - /// is less than 0. + /// is less than 0. public static double NextDouble(this Random random, double maxValue) { if (random is null) @@ -106,7 +106,7 @@ public static class RandomExtensions if (maxValue < minValue) { - throw new ArgumentOutOfRangeException(ExceptionMessages.MaxValueGreaterThanEqualToMinValue); + throw new ArgumentException(ExceptionMessages.MaxValueGreaterThanEqualToMinValue); } return MathUtility.Lerp(minValue, maxValue, random.NextDouble()); @@ -156,6 +156,154 @@ public static class RandomExtensions return list[random.Next(list.Count)]; } + /// + /// Returns a non-negative random integer. + /// + /// The instance. + /// + /// An 8-bit unsigned integer that is greater than or equal to 0, and less than . + /// + /// is . + public static byte NextByte(this Random random) + { + if (random is null) + { + throw new ArgumentNullException(nameof(random)); + } + + return random.NextByte(byte.MaxValue); + } + + /// + /// Returns a non-negative random integer. + /// + /// The instance. + /// + /// The exclusive upper bound of the random number to be generated. must be greater than or + /// equal to 0. + /// + /// + /// An 8-bit unsigned integer that is greater than or equal to 0, and less than ; that is, the + /// range of return values ordinarily includes 0 but not . However, if + /// equals 0, is returned. + /// + /// is . + public static byte NextByte(this Random random, byte maxValue) + { + if (random is null) + { + throw new ArgumentNullException(nameof(random)); + } + + return random.NextByte(0, maxValue); + } + + /// + /// Returns a non-negative random integer. + /// + /// The instance. + /// The inclusive lower bound of the random number to be generated. + /// + /// The exclusive upper bound of the random number to be generated. must be greater than or + /// equal to . + /// + /// + /// An 8-bit unsigned integer greater than or equal to and less than + /// ; that is, the range of return values includes but not + /// . If equals , + /// is returned. + /// + /// is . + /// + /// is greater than . + /// + public static byte NextByte(this Random random, byte minValue, byte maxValue) + { + if (random is null) + { + throw new ArgumentNullException(nameof(random)); + } + + return (byte)random.Next(minValue, maxValue); + } + + /// + /// Returns a non-negative random integer. + /// + /// The instance. + /// + /// An 16-bit signed integer that is greater than or equal to 0, and less than . + /// + /// is . + public static short NextInt16(this Random random) + { + if (random is null) + { + throw new ArgumentNullException(nameof(random)); + } + + return random.NextInt16(short.MaxValue); + } + + /// + /// Returns a non-negative random integer that is less than the specified maximum. + /// + /// The instance. + /// + /// The exclusive upper bound of the random number to be generated. must be greater than or + /// equal to 0. + /// + /// + /// A 16-bit signed integer that is greater than or equal to 0, and less than ; that is, the + /// range of return values ordinarily includes 0 but not . However, if + /// equals 0, is returned. + /// + /// is . + /// is less than 0. + public static short NextInt16(this Random random, short maxValue) + { + if (random is null) + { + throw new ArgumentNullException(nameof(random)); + } + + if (maxValue < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxValue)); + } + + return random.NextInt16(0, maxValue); + } + + /// + /// Returns a random integer that is within a specified range. + /// + /// The instance. + /// The inclusive lower bound of the random number to be generated. + /// + /// The exclusive upper bound of the random number to be generated. must be greater than or + /// equal to . + /// + /// + /// An 8-bit unsigned integer greater than or equal to and less than + /// ; that is, the range of return values includes but not + /// . If equals , + /// is returned. + /// + /// + /// is greater than . + /// + /// is . + public static short NextInt16(this Random random, short minValue, short maxValue) + { + if (random is null) + { + throw new ArgumentNullException(nameof(random)); + } + + return (short)random.Next(minValue, maxValue); + } + /// /// Returns a non-negative random single-precision floating point number that is less than the specified maximum. /// @@ -178,7 +326,7 @@ public static class RandomExtensions if (maxValue < 0) { - throw new ArgumentOutOfRangeException(ExceptionMessages.MaxValueGreaterThanEqualTo0); + throw new ArgumentOutOfRangeException(nameof(maxValue)); } return random.NextSingle(0, maxValue); @@ -203,6 +351,16 @@ public static class RandomExtensions /// public static float NextSingle(this Random random, float minValue, float maxValue) { + if (random is null) + { + throw new ArgumentNullException(nameof(random)); + } + + if (maxValue < minValue) + { + throw new ArgumentException(ExceptionMessages.MaxValueGreaterThanEqualToMinValue); + } + return MathUtility.Lerp(minValue, maxValue, random.NextSingle()); }