From ab3ebafccbb29da61a5649506ce3c8ab2109bd6e Mon Sep 17 00:00:00 2001 From: James Lao Date: Sat, 9 Mar 2019 18:27:51 -0800 Subject: [PATCH] Add explicit test for hash collision handling. --- UnitTests/BadHashCode.cs | 13 +++++++ UnitTests/CacheTableTestBase.cs | 49 +++++++++++++++++++------- UnitTests/CacheTableTests.cs | 6 ++-- UnitTests/ConcurrentCacheTableTests.cs | 8 ++--- 4 files changed, 56 insertions(+), 20 deletions(-) create mode 100644 UnitTests/BadHashCode.cs diff --git a/UnitTests/BadHashCode.cs b/UnitTests/BadHashCode.cs new file mode 100644 index 0000000..fb925f0 --- /dev/null +++ b/UnitTests/BadHashCode.cs @@ -0,0 +1,13 @@ +namespace UnitTests +{ + struct BadHashCode + { + public int Value; + + public override int GetHashCode() => 42; + + public static implicit operator BadHashCode(int i) => new BadHashCode { Value = i }; + + public static implicit operator int(BadHashCode bhc) => bhc.Value; + } +} diff --git a/UnitTests/CacheTableTestBase.cs b/UnitTests/CacheTableTestBase.cs index d8e4b61..90e07a8 100644 --- a/UnitTests/CacheTableTestBase.cs +++ b/UnitTests/CacheTableTestBase.cs @@ -8,7 +8,7 @@ namespace UnitTests { - public abstract class CacheTableTestBase where TCacheTable : ICacheTable + public abstract class CacheTableTestBase { protected ITestOutputHelper output; @@ -17,12 +17,12 @@ protected CacheTableTestBase(ITestOutputHelper output) this.output = output; } - protected abstract TCacheTable CreateTable(int numRows, int numColumns); + protected abstract ICacheTable CreateTable(int numRows, int numColumns); [Fact] public void SetAndTryGetValue() { - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); table[1] = 2; table.TryGetValue(1, out int val).Should().BeTrue(); val.Should().Be(2); @@ -31,7 +31,7 @@ public void SetAndTryGetValue() [Fact] public void TryGetNonExistentValue() { - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); table.TryGetValue(1, out int val).Should().BeFalse(); val.Should().Be(default(int)); } @@ -39,7 +39,7 @@ public void TryGetNonExistentValue() [Fact] public void SetAndIndex() { - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); table[1] = 2; table[1].Should().Be(2); } @@ -47,7 +47,7 @@ public void SetAndIndex() [Fact] public void Update() { - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); for (int i = 0; i < 4; i++) { @@ -72,7 +72,7 @@ public void Update() [Fact] public void IndexNonExistentKeyThrows() { - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); Action act = () => Console.WriteLine(table[0]); act.Should().Throw() .WithMessage("No value found for 0"); @@ -81,7 +81,7 @@ public void IndexNonExistentKeyThrows() [Fact] public void ContainsKey() { - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); table.ContainsKey(0).Should().BeFalse(); table[0] = 1; table.ContainsKey(0).Should().BeTrue(); @@ -90,7 +90,7 @@ public void ContainsKey() [Fact] public void Remove() { - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); table[1] = 2; table.Remove(1).Should().BeTrue(); table.TryGetValue(1, out int val).Should().BeFalse(); @@ -103,7 +103,7 @@ public void Clear() { const int numInserts = 40; - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); for (int i = 0; i < numInserts; i++) { table[i] = i; @@ -123,7 +123,7 @@ public void Clear() [Fact] public void Count() { - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); table.Count.Should().Be(0); for (int i = 0; i < 4; i++) @@ -142,7 +142,7 @@ public void Count() [Fact] public void Enumerate() { - var table = this.CreateTable(10, 4); + var table = this.CreateTable(10, 4); var rng = new Random(); List> expected = new List>(); @@ -160,7 +160,7 @@ public void Enumerate() [Fact] public void InsertOnFullTableOverwrites() { - var table = this.CreateTable(5, 4); + var table = this.CreateTable(5, 4); int i = 0; do @@ -183,5 +183,28 @@ public void InsertOnFullTableOverwrites() after.Count.Should().Be(1); after.First().Should().Be(i); } + + [Theory] + [InlineData(4)] + [InlineData(7)] + public void ResolvesHashCollisions(int numColumns) + { + var table = this.CreateTable(5, numColumns); + + for (int i = 0; i < numColumns; i++) + { + table[i] = i; + } + + for (int i = 0; i < numColumns; i++) + { + table[i].Should().Be(i); + } + + // This is going to overwrite a value + table[numColumns] = numColumns; + table[numColumns].Should().Be(numColumns); + table.Count.Should().Be(numColumns); + } } } diff --git a/UnitTests/CacheTableTests.cs b/UnitTests/CacheTableTests.cs index 6a979e8..8c51c4a 100644 --- a/UnitTests/CacheTableTests.cs +++ b/UnitTests/CacheTableTests.cs @@ -3,15 +3,15 @@ namespace UnitTests { - public class CacheTableTests : CacheTableTestBase> + public class CacheTableTests : CacheTableTestBase { public CacheTableTests(ITestOutputHelper output) : base(output) { } - protected override CacheTable CreateTable(int numRows, int numColumns) + protected override ICacheTable CreateTable(int numRows, int numColumns) { - return new CacheTable(numRows, numColumns); + return new CacheTable(numRows, numColumns); } } } diff --git a/UnitTests/ConcurrentCacheTableTests.cs b/UnitTests/ConcurrentCacheTableTests.cs index 2edd8f8..ee29ee2 100644 --- a/UnitTests/ConcurrentCacheTableTests.cs +++ b/UnitTests/ConcurrentCacheTableTests.cs @@ -6,21 +6,21 @@ namespace UnitTests { - public class ConcurrentCacheTableTests : CacheTableTestBase> + public class ConcurrentCacheTableTests : CacheTableTestBase { public ConcurrentCacheTableTests(ITestOutputHelper output) : base(output) { } - protected override ConcurrentCacheTable CreateTable(int numRows, int numColumns) + protected override ICacheTable CreateTable(int numRows, int numColumns) { - return new ConcurrentCacheTable(numRows, numColumns, 3); + return new ConcurrentCacheTable(numRows, numColumns, 3); } [Fact] public async Task ConcurrentWrites() { - var table = CreateTable(5, 4); + var table = this.CreateTable(5, 4); const int numWrites = 1000;