Skip to content

Commit b2c7877

Browse files
authored
Update tests (#67)
* improve comment and usage for buffer size - no need for single use const, move commentary to code to make usage more clear * fix bug in issue 15 test to actually use declared vars * tests cleanup, fix naming, explicit params * use parallel.for in multithreading test - more reliable tests using partitioner in parallel method instead of list of tasks - wont swallow exceptions inside tasks - decrease total test running time
1 parent 98d7e56 commit b2c7877

3 files changed

Lines changed: 89 additions & 92 deletions

File tree

src/Hashids.net/Hashids.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ public partial class Hashids : IHashids
1616

1717
private const double SEP_DIV = 3.5;
1818
private const double GUARD_DIV = 12.0;
19-
private const int MaxNumberHashLength = 19; // Length of long.MaxValue;
2019

2120
private readonly char[] _alphabet;
2221
private readonly char[] _seps;
@@ -303,7 +302,8 @@ private string GenerateHashFrom(ReadOnlySpan<long> numbers)
303302
var startIndex = 1 + _salt.Length;
304303
var length = _alphabet.Length - startIndex;
305304

306-
Span<char> hashBuffer = stackalloc char[MaxNumberHashLength];
305+
// use buffer size of 19 which is the length of the biggest 64-bit integer (long.MaxValue = 9223372036854775807)
306+
Span<char> hashBuffer = stackalloc char[19];
307307

308308
for (var i = 0; i < numbers.Length; i++)
309309
{

test/Hashids.net.test/GeneralTests.cs

Lines changed: 79 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Linq;
32
using System.Threading.Tasks;
43
using FluentAssertions;
54
using Moq;
@@ -9,33 +8,22 @@ namespace HashidsNet.test
98
{
109
public class GeneralTests
1110
{
12-
private const string salt = "this is my salt";
13-
private readonly Hashids _hashids = new Hashids(salt);
11+
private readonly Hashids _hashids = new Hashids(salt: "this is my salt");
1412

1513
[Fact]
16-
public async Task EncodingIsThreadSafe()
14+
public void EncodingIsThreadSafe()
1715
{
1816
var hashids = new Hashids();
19-
const int threadCount = 6;
20-
const int numberCount = 1000001;
17+
const int numberCount = 10_000;
2118

22-
var tasks = Enumerable.Range(1, threadCount).Select(t => Task.Run(() =>
19+
Parallel.For(0, 100, i =>
2320
{
24-
for (var n = 1; n < numberCount; n++)
21+
for (var n = 0; n < numberCount; n++)
2522
{
26-
var s = hashids.Encode(n);
27-
hashids.Decode(s).Should().Equal(n);
23+
var e = hashids.Encode(n);
24+
hashids.Decode(e).Should().Equal(n);
2825
}
29-
})).ToArray();
30-
31-
await Task.WhenAll(tasks);
32-
}
33-
34-
[Fact]
35-
public void DefaultSaltIsBlank()
36-
{
37-
// default salt of empty string "" should result in this encoded value
38-
new Hashids().Encode(1, 2, 3).Should().Be("o2fXhV");
26+
});
3927
}
4028

4129
[Fact]
@@ -51,7 +39,17 @@ public void SingleInt_Encodes()
5139
}
5240

5341
[Fact]
54-
public void SingleReturn_Decodes()
42+
public void SingleInt_Decodes()
43+
{
44+
_hashids.Decode("NkK9").Should().Equal(new[] { 12345 });
45+
_hashids.Decode("5O8yp5P").Should().Equal(new[] { 666555444 });
46+
_hashids.Decode("Wzo").Should().Equal(new[] { 1337 });
47+
_hashids.Decode("DbE").Should().Equal(new[] { 808 });
48+
_hashids.Decode("yj8").Should().Equal(new[] { 303 });
49+
}
50+
51+
[Fact]
52+
public void SingleInt_DecodesSingleNumber()
5553
{
5654
_hashids.DecodeSingle("NkK9").Should().Be(12345);
5755
_hashids.DecodeSingle("5O8yp5P").Should().Be(666555444);
@@ -64,7 +62,7 @@ public void SingleReturn_Decodes()
6462
}
6563

6664
[Fact]
67-
public void SingleReturnOut_Decodes()
65+
public void SingleInt_DecodesSingleNumberWithTry()
6866
{
6967
int value;
7068

@@ -89,16 +87,6 @@ public void SingleReturnOut_Decodes()
8987
value.Should().Be(303);
9088
}
9189

92-
[Fact]
93-
public void SingleInt_Decodes()
94-
{
95-
_hashids.Decode("NkK9").Should().Equal(new[] { 12345 });
96-
_hashids.Decode("5O8yp5P").Should().Equal(new[] { 666555444 });
97-
_hashids.Decode("Wzo").Should().Equal(new[] { 1337 });
98-
_hashids.Decode("DbE").Should().Equal(new[] { 808 });
99-
_hashids.Decode("yj8").Should().Equal(new[] { 303 });
100-
}
101-
10290
[Fact]
10391
public void SingleLong_Encodes()
10492
{
@@ -107,62 +95,62 @@ public void SingleLong_Encodes()
10795
_hashids.EncodeLong(4294967296L).Should().Be("D54yen6");
10896
_hashids.EncodeLong(666555444333222L).Should().Be("KVO9yy1oO5j");
10997
_hashids.EncodeLong(12345678901112L).Should().Be("4bNP1L26r");
110-
_hashids.EncodeLong(Int64.MaxValue).Should().Be("jvNx4BjM5KYjv");
98+
_hashids.EncodeLong(long.MaxValue).Should().Be("jvNx4BjM5KYjv");
11199
}
112100

113101
[Fact]
114-
public void SingleLong_Decode()
102+
public void SingleLong_Decodes()
115103
{
116104
_hashids.DecodeLong("NV").Should().Equal(new[] { 1L });
117105
_hashids.DecodeLong("21OjjRK").Should().Equal(new[] { 2147483648L });
118106
_hashids.DecodeLong("D54yen6").Should().Equal(new[] { 4294967296L });
119107
_hashids.DecodeLong("KVO9yy1oO5j").Should().Equal(new[] { 666555444333222L });
120108
_hashids.DecodeLong("4bNP1L26r").Should().Equal(new[] { 12345678901112L });
121-
_hashids.DecodeLong("jvNx4BjM5KYjv").Should().Equal(new[] { Int64.MaxValue });
109+
_hashids.DecodeLong("jvNx4BjM5KYjv").Should().Equal(new[] { long.MaxValue });
122110
}
123111

124112
[Fact]
125-
public void SingleReturnLong_Decode()
113+
public void SingleLong_DecodesSingleNumber()
126114
{
127115
_hashids.DecodeSingleLong("NV").Should().Be(1L);
128116
_hashids.DecodeSingleLong("21OjjRK").Should().Be(2147483648L);
129117
_hashids.DecodeSingleLong("D54yen6").Should().Be(4294967296L);
130118
_hashids.DecodeSingleLong("KVO9yy1oO5j").Should().Be(666555444333222L);
131119
_hashids.DecodeSingleLong("4bNP1L26r").Should().Be(12345678901112L);
132-
_hashids.DecodeSingleLong("jvNx4BjM5KYjv").Should().Be(Int64.MaxValue);
120+
_hashids.DecodeSingleLong("jvNx4BjM5KYjv").Should().Be(long.MaxValue);
133121

134122
Assert.Throws<NoResultException>(() => _hashids.DecodeSingleLong(string.Empty));
135123
Assert.Throws<MultipleResultsException>(() => _hashids.DecodeSingleLong("6gH3kPY7MJ9zjM3"));
136124
}
137125

138126
[Fact]
139-
public void SingleReturnOutLong_Decodes()
127+
public void SingleLong_DecodesSingleNumberWithTry()
140128
{
141-
long value;
129+
long decoded;
142130

143-
_hashids.TryDecodeSingleLong("NV,NV", out value).Should().Be(false);
144-
_hashids.TryDecodeSingleLong("NV", out value).Should().Be(true);
145-
value.Should().Be(1L);
131+
_hashids.TryDecodeSingleLong("NV,NV", out decoded).Should().Be(false);
132+
_hashids.TryDecodeSingleLong("NV", out decoded).Should().Be(true);
133+
decoded.Should().Be(1L);
146134

147-
_hashids.TryDecodeSingleLong("21OjjRK,21OjjRK", out value).Should().Be(false);
148-
_hashids.TryDecodeSingleLong("21OjjRK", out value).Should().Be(true);
149-
value.Should().Be(2147483648L);
135+
_hashids.TryDecodeSingleLong("21OjjRK,21OjjRK", out decoded).Should().Be(false);
136+
_hashids.TryDecodeSingleLong("21OjjRK", out decoded).Should().Be(true);
137+
decoded.Should().Be(2147483648L);
150138

151-
_hashids.TryDecodeSingleLong("D54yen6,D54yen6", out value).Should().Be(false);
152-
_hashids.TryDecodeSingleLong("D54yen6", out value).Should().Be(true);
153-
value.Should().Be(4294967296L);
139+
_hashids.TryDecodeSingleLong("D54yen6,D54yen6", out decoded).Should().Be(false);
140+
_hashids.TryDecodeSingleLong("D54yen6", out decoded).Should().Be(true);
141+
decoded.Should().Be(4294967296L);
154142

155-
_hashids.TryDecodeSingleLong("KVO9yy1oO5j,KVO9yy1oO5j", out value).Should().Be(false);
156-
_hashids.TryDecodeSingleLong("KVO9yy1oO5j", out value).Should().Be(true);
157-
value.Should().Be(666555444333222L);
143+
_hashids.TryDecodeSingleLong("KVO9yy1oO5j,KVO9yy1oO5j", out decoded).Should().Be(false);
144+
_hashids.TryDecodeSingleLong("KVO9yy1oO5j", out decoded).Should().Be(true);
145+
decoded.Should().Be(666555444333222L);
158146

159-
_hashids.TryDecodeSingleLong("4bNP1L26r,4bNP1L26r", out value).Should().Be(false);
160-
_hashids.TryDecodeSingleLong("4bNP1L26r", out value).Should().Be(true);
161-
value.Should().Be(12345678901112L);
147+
_hashids.TryDecodeSingleLong("4bNP1L26r,4bNP1L26r", out decoded).Should().Be(false);
148+
_hashids.TryDecodeSingleLong("4bNP1L26r", out decoded).Should().Be(true);
149+
decoded.Should().Be(12345678901112L);
162150

163-
_hashids.TryDecodeSingleLong("jvNx4BjM5KYjv,jvNx4BjM5KYjv", out value).Should().Be(false);
164-
_hashids.TryDecodeSingleLong("jvNx4BjM5KYjv", out value).Should().Be(true);
165-
value.Should().Be(Int64.MaxValue);
151+
_hashids.TryDecodeSingleLong("jvNx4BjM5KYjv,jvNx4BjM5KYjv", out decoded).Should().Be(false);
152+
_hashids.TryDecodeSingleLong("jvNx4BjM5KYjv", out decoded).Should().Be(true);
153+
decoded.Should().Be(long.MaxValue);
166154
}
167155

168156
[Fact]
@@ -192,8 +180,8 @@ public void ListOfInt_Decodes()
192180
public void ListOfInt_Roundtrip()
193181
{
194182
var input = new[] { 12345, 67890, int.MaxValue };
195-
var decodedValue = _hashids.Decode(_hashids.Encode(input));
196-
decodedValue.Should().BeEquivalentTo(input);
183+
var decoded = _hashids.Decode(_hashids.Encode(input));
184+
decoded.Should().BeEquivalentTo(input);
197185
}
198186

199187
[Fact]
@@ -212,8 +200,8 @@ public void ListOfLong_Decodes()
212200
public void ListOfLong_Roundtrip()
213201
{
214202
var input = new[] { 1L, 1234567890123456789, long.MaxValue };
215-
var decodedValue = _hashids.DecodeLong(_hashids.EncodeLong(input));
216-
decodedValue.Should().BeEquivalentTo(input);
203+
var decoded = _hashids.DecodeLong(_hashids.EncodeLong(input));
204+
decoded.Should().BeEquivalentTo(input);
217205
}
218206

219207
[Fact]
@@ -257,16 +245,16 @@ public void HexString_Roundtrip()
257245
public void NumbersIncludingZero_AtStart_Roundtrip()
258246
{
259247
var input = new[] { 0, 1, 2 };
260-
var decodedValue = _hashids.Decode(_hashids.Encode(input));
261-
decodedValue.Should().Equal(input);
248+
var decoded = _hashids.Decode(_hashids.Encode(input));
249+
decoded.Should().Equal(input);
262250
}
263251

264252
[Fact]
265253
public void NumbersIncludingZero_AtEnd_Roundtrip()
266254
{
267255
var input = new[] { 1, 2, 0 };
268-
var decodedValue = _hashids.Decode(_hashids.Encode(input));
269-
decodedValue.Should().Equal(input);
256+
var decoded = _hashids.Decode(_hashids.Encode(input));
257+
decoded.Should().Equal(input);
270258
}
271259

272260
[Fact]
@@ -311,26 +299,19 @@ public void ListWithNegativeNumbers_ReturnsEmptyString()
311299
_hashids.EncodeLong(1, long.MaxValue, -4).Should().Be(string.Empty);
312300
}
313301

314-
[Fact]
315-
public void DifferentSalt_ReturnsEmptyList()
316-
{
317-
_hashids.Decode("NkK9").Should().Equal(new[] { 12345 });
318-
new Hashids("different salt").Decode("NkK9").Should().Equal(new int[0]);
319-
}
320-
321302
[Fact]
322303
public void HashMinLength_EncodesHashWithAtLeastThatLength()
323304
{
324305
var hashLength = 18;
325-
var hashids = new Hashids(salt, hashLength);
306+
var hashids = new Hashids(salt: "this is my salt", minHashLength: hashLength);
326307
hashids.Encode(1).Length.Should().BeGreaterOrEqualTo(hashLength);
327308
hashids.Encode(4140, 21147, 115975, 678570, 4213597, 27644437).Length.Should().BeGreaterOrEqualTo(hashLength);
328309
}
329310

330311
[Fact]
331312
public void HashMinLength_Decodes()
332313
{
333-
var hashids = new Hashids(salt, 8);
314+
var hashids = new Hashids(salt: "this is my salt", minHashLength: 8);
334315
hashids.Decode("gB0NV05e").Should().Equal(new[] { 1 });
335316
hashids.Decode("mxi8XH87").Should().Equal(new[] { 25, 100, 950 });
336317
hashids.Decode("KQcmkIW8hX").Should().Equal(new[] { 5, 200, 195, 1 });
@@ -356,17 +337,20 @@ public void AlphabetWithDashes_Roundtrip()
356337
public void AlphabetLessThanMinLength_ThrowsArgumentException()
357338
{
358339
var tooShortAlphabet = Hashids.DEFAULT_ALPHABET.Substring(0, Hashids.MIN_ALPHABET_LENGTH - 1);
359-
Action invocation = () => new Hashids(alphabet: tooShortAlphabet);
340+
var invocation = () => new Hashids(alphabet: tooShortAlphabet);
360341
invocation.Should().Throw<ArgumentException>();
361342
}
362343

363344
[Fact]
364345
public void AlphabetAtLeastMinLength_ShouldNotThrowException()
365346
{
366347
var minLengthAlphabet = Hashids.DEFAULT_ALPHABET.Substring(0, Hashids.MIN_ALPHABET_LENGTH);
348+
var minLengthCtor = () => new Hashids(alphabet: minLengthAlphabet);
349+
minLengthCtor.Should().NotThrow();
350+
367351
var largerLengthAlphabet = Hashids.DEFAULT_ALPHABET.Substring(0, Hashids.MIN_ALPHABET_LENGTH + 1);
368-
var results1 = new Hashids(alphabet: minLengthAlphabet);
369-
var results2 = new Hashids(alphabet: largerLengthAlphabet);
352+
var largerLengthCtor = () => new Hashids(alphabet: largerLengthAlphabet);
353+
largerLengthCtor.Should().NotThrow();
370354
}
371355

372356
[Fact]
@@ -376,10 +360,24 @@ public void NullAlphabet_ThrowsNullArgumentException()
376360
invocation.Should().Throw<ArgumentNullException>();
377361
}
378362

363+
[Fact]
364+
public void DefaultSaltIsBlank()
365+
{
366+
// default salt of empty string "" should result in this encoded value
367+
new Hashids().Encode(1, 2, 3).Should().Be("o2fXhV");
368+
}
369+
370+
[Fact]
371+
public void DifferentSalt_ReturnsEmptyList()
372+
{
373+
_hashids.Decode("NkK9").Should().Equal(new[] { 12345 });
374+
new Hashids("different salt").Decode("NkK9").Should().Equal(new int[0]);
375+
}
376+
379377
[Fact]
380378
public void CustomAlphabet_Roundtrip()
381379
{
382-
var hashids = new Hashids(salt, 0, "ABCDEFGhijklmn34567890-:");
380+
var hashids = new Hashids(salt: "this is my salt", minHashLength: 0, alphabet: "ABCDEFGhijklmn34567890-:");
383381
var input = new[] { 1, 2, 3, 4, 5 };
384382
hashids.Encode(input).Should().Be("6nhmFDikA0");
385383
hashids.Decode(hashids.Encode(input)).Should().BeEquivalentTo(input);
@@ -388,7 +386,7 @@ public void CustomAlphabet_Roundtrip()
388386
[Fact]
389387
public void CustomAlphabet2_Roundtrip()
390388
{
391-
var hashids = new Hashids(salt, 0, "ABCDEFGHIJKMNOPQRSTUVWXYZ23456789");
389+
var hashids = new Hashids(salt: "this is my salt", minHashLength: 0, alphabet: "ABCDEFGHIJKMNOPQRSTUVWXYZ23456789");
392390
var input = new[] { 1, 2, 3, 4, 5 };
393391
hashids.Encode(input).Should().Be("44HYIRU3TO");
394392
hashids.Decode(hashids.Encode(input)).Should().BeEquivalentTo(input);
@@ -397,8 +395,7 @@ public void CustomAlphabet2_Roundtrip()
397395
[Fact]
398396
public void SaltIsLongerThanAlphabet_Roundtrip()
399397
{
400-
var longSalt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
401-
var hashids = new Hashids(salt: longSalt);
398+
var hashids = new Hashids(salt: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
402399
var input = new[] { 1, 2, 0 };
403400
var decodedValue = hashids.Decode(hashids.Encode(input));
404401
decodedValue.Should().Equal(input);
@@ -408,7 +405,7 @@ public void SaltIsLongerThanAlphabet_Roundtrip()
408405
public void GuardCharacterOnly_DecodesToEmptyArray()
409406
{
410407
// no salt creates guard characters: "abde"
411-
var hashids = new Hashids("");
408+
var hashids = new Hashids(salt: "");
412409
var decodedValue = hashids.Decode("a");
413410
decodedValue.Should().Equal(Array.Empty<int>());
414411
}

test/Hashids.net.test/IssueSpecificTests.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace HashidsNet.test
88
public class IssueSpecificTests
99
{
1010
[Fact]
11-
void issue_8_should_not_throw_out_of_range_exception()
11+
void Issue_8_should_not_throw_out_of_range_exception()
1212
{
1313
var hashids = new Hashids("janottaa", 6);
1414
var numbers = hashids.Decode("NgAzADEANAA=");
@@ -18,7 +18,7 @@ void issue_8_should_not_throw_out_of_range_exception()
1818
// seems to happen when you are encoding A LOT of longs at the same time.
1919
// see if it is possible to make this a faster test (or remove it since it is unlikely that it will reapper).
2020
[Fact]
21-
void issue_12_should_not_throw_out_of_range_exception()
21+
void Issue_12_should_not_throw_out_of_range_exception()
2222
{
2323
var hash = new Hashids("zXZVFf2N38uV");
2424
var longs = new List<long>();
@@ -38,23 +38,23 @@ void issue_12_should_not_throw_out_of_range_exception()
3838
}
3939

4040
[Fact]
41-
void issue_15_it_should_return_emtpy_array_when_decoding_characters_missing_in_alphabet()
41+
void Issue_15_it_should_return_empty_array_when_decoding_characters_missing_in_alphabet()
4242
{
4343
var hashids = new Hashids(salt: "Salty stuff", alphabet: "qwerty1234!¤%&/()=", seps: "1234");
4444
var numbers = hashids.Decode("abcd");
4545
numbers.Length.Should().Be(0);
4646

4747
var hashids2 = new Hashids();
48-
hashids.Decode("13-37").Length.Should().Be(0);
49-
hashids.DecodeLong("32323kldffd!").Length.Should().Be(0);
48+
hashids2.Decode("13-37").Length.Should().Be(0);
49+
hashids2.DecodeLong("32323kldffd!").Length.Should().Be(0);
5050

5151
var hashids3 = new Hashids(alphabet: "1234567890;:_!#¤%&/()=", seps: "!#¤%&/()=");
52-
hashids.Decode("asdfb").Length.Should().Be(0);
53-
hashids.DecodeLong("asdfgfdgdfgkj").Length.Should().Be(0);
52+
hashids3.Decode("asdfb").Length.Should().Be(0);
53+
hashids3.DecodeLong("asdfgfdgdfgkj").Length.Should().Be(0);
5454
}
5555

5656
[Fact]
57-
void issue_64_it_should_be_possible_to_encode_and_decode_long_max_value()
57+
void Issue_64_long_max_value_with_min_alphabet_length()
5858
{
5959
var hashids = new Hashids("salt", alphabet: "0123456789ABCDEF");
6060
var hash = hashids.EncodeLong(long.MaxValue);

0 commit comments

Comments
 (0)