Skip to content

Commit f3891f8

Browse files
committed
cleanup and consolidate tests
1 parent 4049cb6 commit f3891f8

7 files changed

Lines changed: 353 additions & 416 deletions

File tree

src/Hashids.net/Hashids.net.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<RepositoryUrl>https://github.com/ullmark/hashids.net</RepositoryUrl>
1515
<TargetFrameworks>net461;net5.0;netstandard2.0</TargetFrameworks>
1616
<OutputType>Library</OutputType>
17-
<LangVersion>default</LangVersion>
17+
<LangVersion>9</LangVersion>
1818
</PropertyGroup>
1919

2020
<ItemGroup>

test/Hashids.net.benchmark/Hashids.net.benchmark.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
<OutputType>Exe</OutputType>
55
<TargetFramework>net5.0</TargetFramework>
66
<IsPackable>false</IsPackable>
7-
<LangVersion>default</LangVersion>
7+
<LangVersion>9</LangVersion>
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="BenchmarkDotNet" Version="0.12.1"/>
11+
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
1212
</ItemGroup>
1313

1414
<ItemGroup>
15-
<ProjectReference Include="..\..\src\Hashids.net\Hashids.net.csproj"/>
15+
<ProjectReference Include="..\..\src\Hashids.net\Hashids.net.csproj" />
1616
</ItemGroup>
1717

1818
</Project>
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
using System;
2+
using System.Linq;
3+
using System.Threading.Tasks;
4+
using FluentAssertions;
5+
using Moq;
6+
using Xunit;
7+
8+
namespace HashidsNet.test
9+
{
10+
public class GeneralTests
11+
{
12+
private const string salt = "this is my salt";
13+
private readonly Hashids _hashids = new Hashids(salt);
14+
15+
[Fact]
16+
public async Task EncodingIsThreadSafe()
17+
{
18+
var hashids = new Hashids();
19+
const int threadCount = 6;
20+
const int numberCount = 1000001;
21+
22+
var tasks = Enumerable.Range(1, threadCount).Select(t => Task.Run(() =>
23+
{
24+
for (var n = 1; n < numberCount; n++)
25+
{
26+
var s = hashids.Encode(n);
27+
hashids.Decode(s).Should().Equal(n);
28+
}
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");
39+
}
40+
41+
[Fact]
42+
public void SingleInt_Encodes()
43+
{
44+
_hashids.Encode(1).Should().Be("NV");
45+
_hashids.Encode(22).Should().Be("K4");
46+
_hashids.Encode(333).Should().Be("OqM");
47+
_hashids.Encode(9999).Should().Be("kQVg");
48+
_hashids.Encode(123000).Should().Be("58LzD");
49+
_hashids.Encode(456000000).Should().Be("5gn6mQP");
50+
_hashids.Encode(987654321).Should().Be("oyjYvry");
51+
}
52+
53+
[Fact]
54+
public void SingleInt_Decodes()
55+
{
56+
_hashids.Decode("NkK9").Should().Equal(new[] { 12345 });
57+
_hashids.Decode("5O8yp5P").Should().Equal(new[] { 666555444 });
58+
_hashids.Decode("Wzo").Should().Equal(new[] { 1337 });
59+
_hashids.Decode("DbE").Should().Equal(new[] { 808 });
60+
_hashids.Decode("yj8").Should().Equal(new[] { 303 });
61+
}
62+
63+
[Fact]
64+
public void SingleLong_Encodes()
65+
{
66+
_hashids.EncodeLong(1L).Should().Be("NV");
67+
_hashids.EncodeLong(2147483648L).Should().Be("21OjjRK");
68+
_hashids.EncodeLong(4294967296L).Should().Be("D54yen6");
69+
_hashids.EncodeLong(666555444333222L).Should().Be("KVO9yy1oO5j");
70+
_hashids.EncodeLong(12345678901112L).Should().Be("4bNP1L26r");
71+
_hashids.EncodeLong(Int64.MaxValue).Should().Be("jvNx4BjM5KYjv");
72+
}
73+
74+
[Fact]
75+
public void SingleLong_Decode()
76+
{
77+
_hashids.DecodeLong("NV").Should().Equal(new[] { 1L });
78+
_hashids.DecodeLong("21OjjRK").Should().Equal(new[] { 2147483648L });
79+
_hashids.DecodeLong("D54yen6").Should().Equal(new[] { 4294967296L });
80+
_hashids.DecodeLong("KVO9yy1oO5j").Should().Equal(new[] { 666555444333222L });
81+
_hashids.DecodeLong("4bNP1L26r").Should().Equal(new[] { 12345678901112L });
82+
_hashids.DecodeLong("jvNx4BjM5KYjv").Should().Equal(new[] { Int64.MaxValue });
83+
}
84+
85+
[Fact]
86+
public void ListOfInt_Encodes()
87+
{
88+
_hashids.Encode(1, 2, 3).Should().Be("laHquq");
89+
_hashids.Encode(2, 4, 6).Should().Be("44uotN");
90+
_hashids.Encode(99, 25).Should().Be("97Jun");
91+
_hashids.Encode(1337, 42, 314).Should().Be("7xKhrUxm");
92+
_hashids.Encode(683, 94108, 123, 5).Should().Be("aBMswoO2UB3Sj");
93+
_hashids.Encode(547, 31, 241271, 311, 31397, 1129, 71129).Should().Be("3RoSDhelEyhxRsyWpCx5t1ZK");
94+
_hashids.Encode(21979508, 35563591, 57543099, 93106690, 150649789).Should().Be("p2xkL3CK33JjcrrZ8vsw4YRZueZX9k");
95+
}
96+
97+
[Fact]
98+
public void ListOfInt_Decodes()
99+
{
100+
_hashids.Decode("1gRYUwKxBgiVuX").Should().Equal(new[] { 66655, 5444333, 2, 22 });
101+
_hashids.Decode("aBMswoO2UB3Sj").Should().Equal(new[] { 683, 94108, 123, 5 });
102+
_hashids.Decode("jYhp").Should().Equal(new[] { 3, 4 });
103+
_hashids.Decode("k9Ib").Should().Equal(new[] { 6, 5 });
104+
_hashids.Decode("EMhN").Should().Equal(new[] { 31, 41 });
105+
_hashids.Decode("glSgV").Should().Equal(new[] { 13, 89 });
106+
}
107+
108+
[Fact]
109+
public void ListOfInt_Roundtrip()
110+
{
111+
var input = new[] { 12345, 67890, int.MaxValue };
112+
var decodedValue = _hashids.Decode(_hashids.Encode(input));
113+
decodedValue.Should().BeEquivalentTo(input);
114+
}
115+
116+
[Fact]
117+
public void ListOfLong_Encodes()
118+
{
119+
_hashids.EncodeLong(666555444333222L, 12345678901112L).Should().Be("mPVbjj7yVMzCJL215n69");
120+
}
121+
122+
[Fact]
123+
public void ListOfLong_Decodes()
124+
{
125+
_hashids.DecodeLong("mPVbjj7yVMzCJL215n69").Should().Equal(new[] { 666555444333222L, 12345678901112L });
126+
}
127+
128+
[Fact]
129+
public void ListOfLong_Roundtrip()
130+
{
131+
var input = new[] { 1L, 1234567890123456789, long.MaxValue };
132+
var decodedValue = _hashids.DecodeLong(_hashids.EncodeLong(input));
133+
decodedValue.Should().BeEquivalentTo(input);
134+
}
135+
136+
[Fact]
137+
public void HexString_Encode()
138+
{
139+
_hashids.EncodeHex("FA").Should().Be("lzY");
140+
_hashids.EncodeHex("26dd").Should().Be("MemE");
141+
_hashids.EncodeHex("FF1A").Should().Be("eBMrb");
142+
_hashids.EncodeHex("12abC").Should().Be("D9NPE");
143+
_hashids.EncodeHex("185b0").Should().Be("9OyNW");
144+
_hashids.EncodeHex("17b8d").Should().Be("MRWNE");
145+
_hashids.EncodeHex("1d7f21dd38").Should().Be("4o6Z7KqxE");
146+
_hashids.EncodeHex("20015111d").Should().Be("ooweQVNB");
147+
}
148+
149+
[Fact]
150+
public void HexString_Decode()
151+
{
152+
_hashids.DecodeHex("lzY").Should().Be("FA");
153+
_hashids.DecodeHex("eBMrb").Should().Be("FF1A");
154+
_hashids.DecodeHex("D9NPE").Should().Be("12ABC");
155+
}
156+
157+
[Fact]
158+
public void HexString_Roundtrip()
159+
{
160+
var hashids = new Hashids("this is my salt");
161+
162+
var encoded = hashids.EncodeHex("DEADBEEF");
163+
encoded.Should().Be("kRNrpKlJ");
164+
165+
var decoded = hashids.DecodeHex(encoded);
166+
decoded.Should().Be("DEADBEEF");
167+
168+
var input2 = "1234567890ABCDEF";
169+
var decoded2 = hashids.DecodeHex(hashids.EncodeHex(input2));
170+
decoded2.Should().Be(input2);
171+
}
172+
173+
[Fact]
174+
public void NumbersIncludingZero_AtStart_Roundtrip()
175+
{
176+
var input = new[] { 0, 1, 2 };
177+
var decodedValue = _hashids.Decode(_hashids.Encode(input));
178+
decodedValue.Should().Equal(input);
179+
}
180+
181+
[Fact]
182+
public void NumbersIncludingZero_AtEnd_Roundtrip()
183+
{
184+
var input = new[] { 1, 2, 0 };
185+
var decodedValue = _hashids.Decode(_hashids.Encode(input));
186+
decodedValue.Should().Equal(input);
187+
}
188+
189+
[Fact]
190+
public void ListOfIdenticalNumbers_DoNotProducePattern()
191+
{
192+
_hashids.Encode(5, 5, 5, 5).Should().Be("1Wc8cwcE");
193+
}
194+
195+
[Fact]
196+
public void ListOfIncrementingNumbers_DoNotProducePattern()
197+
{
198+
_hashids.Encode(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Should().Be("kRHnurhptKcjIDTWC3sx");
199+
}
200+
201+
[Fact]
202+
public void IncrementingNumbers_DoNotProduceSimilarPattern()
203+
{
204+
_hashids.Encode(1).Should().Be("NV");
205+
_hashids.Encode(2).Should().Be("6m");
206+
_hashids.Encode(3).Should().Be("yD");
207+
_hashids.Encode(4).Should().Be("2l");
208+
_hashids.Encode(5).Should().Be("rD");
209+
}
210+
211+
[Fact]
212+
public void NoNumbers_ReturnsEmptyString()
213+
{
214+
_hashids.Encode().Should().Be(string.Empty);
215+
_hashids.EncodeLong().Should().Be(string.Empty);
216+
}
217+
218+
[Fact]
219+
public void DecodeInvalidHexString_ReturnsEmptyString()
220+
{
221+
_hashids.EncodeHex("XYZ123").Should().Be(string.Empty);
222+
}
223+
224+
[Fact]
225+
public void ListWithNegativeNumbers_ReturnsEmptyString()
226+
{
227+
_hashids.Encode(1, int.MaxValue, -3).Should().Be(string.Empty);
228+
_hashids.EncodeLong(1, long.MaxValue, -4).Should().Be(string.Empty);
229+
}
230+
231+
[Fact]
232+
public void DifferentSalt_ReturnsEmptyList()
233+
{
234+
_hashids.Decode("NkK9").Should().Equal(new[] { 12345 });
235+
new Hashids("different salt").Decode("NkK9").Should().Equal(new int [0]);
236+
}
237+
238+
[Fact]
239+
public void HashMinLength_EncodesHashWithAtLeastThatLength()
240+
{
241+
var hashLength = 18;
242+
var hashids = new Hashids(salt, hashLength);
243+
hashids.Encode(1).Length.Should().BeGreaterOrEqualTo(hashLength);
244+
hashids.Encode(4140, 21147, 115975, 678570, 4213597, 27644437).Length.Should().BeGreaterOrEqualTo(hashLength);
245+
}
246+
247+
[Fact]
248+
public void HashMinLength_Decodes()
249+
{
250+
var hashids = new Hashids(salt, 8);
251+
hashids.Decode("gB0NV05e").Should().Equal(new[] { 1 });
252+
hashids.Decode("mxi8XH87").Should().Equal(new[] { 25, 100, 950 });
253+
hashids.Decode("KQcmkIW8hX").Should().Equal(new[] { 5, 200, 195, 1 });
254+
}
255+
256+
[Fact]
257+
public void AlphabetContainsLessThan4UniqueChars_ThrowsArgumentException()
258+
{
259+
Action invocation = () => new Hashids(alphabet: "aadsss");
260+
invocation.Should().Throw<ArgumentException>();
261+
}
262+
263+
[Fact]
264+
public void AlphabetWithDashes_Roundtrip()
265+
{
266+
var hashids = new Hashids(alphabet: "abcdefghijklmnopqrstuvwxyz1234567890_-");
267+
var input = new long[] { 1, 2, 3 };
268+
var decodedValue = hashids.DecodeLong(hashids.EncodeLong(input));
269+
decodedValue.Should().BeEquivalentTo(input);
270+
}
271+
272+
[Fact]
273+
public void AlphabetLessThanMinLength_ThrowsArgumentException()
274+
{
275+
var tooShortAlphabet = Hashids.DEFAULT_ALPHABET.Substring(0, Hashids.MIN_ALPHABET_LENGTH - 1);
276+
Action invocation = () => new Hashids(alphabet: tooShortAlphabet);
277+
invocation.Should().Throw<ArgumentException>();
278+
}
279+
280+
[Fact]
281+
public void AlphabetAtLeastMinLength_ShouldNotThrowException()
282+
{
283+
var minLengthAlphabet = Hashids.DEFAULT_ALPHABET.Substring(0, Hashids.MIN_ALPHABET_LENGTH);
284+
var largerLengthAlphabet = Hashids.DEFAULT_ALPHABET.Substring(0, Hashids.MIN_ALPHABET_LENGTH + 1);
285+
var results1 = new Hashids(alphabet: minLengthAlphabet);
286+
var results2 = new Hashids(alphabet: largerLengthAlphabet);
287+
}
288+
289+
[Fact]
290+
public void NullAlphabet_ThrowsNullArgumentException()
291+
{
292+
Action invocation = () => new Hashids(alphabet: null);
293+
invocation.Should().Throw<ArgumentNullException>();
294+
}
295+
296+
[Fact]
297+
public void CustomAlphabet_Roundtrip()
298+
{
299+
var hashids = new Hashids(salt, 0, "ABCDEFGhijklmn34567890-:");
300+
var input = new[] { 1, 2, 3, 4, 5 };
301+
hashids.Encode(input).Should().Be("6nhmFDikA0");
302+
hashids.Decode(hashids.Encode(input)).Should().BeEquivalentTo(input);
303+
}
304+
305+
[Fact]
306+
public void CustomAlphabet2_Roundtrip()
307+
{
308+
var hashids = new Hashids(salt, 0, "ABCDEFGHIJKMNOPQRSTUVWXYZ23456789");
309+
var input = new[] { 1, 2, 3, 4, 5 };
310+
hashids.Encode(input).Should().Be("44HYIRU3TO");
311+
hashids.Decode(hashids.Encode(input)).Should().BeEquivalentTo(input);
312+
}
313+
314+
[Fact]
315+
public void SaltIsLongerThanAlphabet_Roundtrip()
316+
{
317+
var longSalt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
318+
var hashids = new Hashids(salt: longSalt);
319+
var input = new[] { 1, 2, 0 };
320+
var decodedValue = hashids.Decode(hashids.Encode(input));
321+
decodedValue.Should().Equal(input);
322+
}
323+
324+
[Fact]
325+
public void GuardCharacterOnly_DecodesToEmptyArray()
326+
{
327+
// no salt creates guard characters: "abde"
328+
var hashids = new Hashids("");
329+
var decodedValue = hashids.Decode("a");
330+
decodedValue.Should().Equal(Array.Empty<int>());
331+
}
332+
333+
[Fact]
334+
public void PublicMethodsCanBeMocked()
335+
{
336+
var mock = new Mock<Hashids>();
337+
mock.Setup(hashids => hashids.Encode(It.IsAny<int[]>())).Returns("It works");
338+
mock.Object.Encode(new[] { 1 }).Should().Be("It works");
339+
}
340+
}
341+
}

test/Hashids.net.test/Hashids.net.test.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@
33
<PropertyGroup>
44
<TargetFramework>net5.0</TargetFramework>
55
<IsPackable>false</IsPackable>
6-
<LangVersion>default</LangVersion>
6+
<LangVersion>9</LangVersion>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="FluentAssertions" Version="5.10.3"/>
11-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4"/>
12-
<PackageReference Include="Moq" Version="4.16.1"/>
13-
<PackageReference Include="xunit" Version="2.4.1"/>
10+
<PackageReference Include="FluentAssertions" Version="5.10.3" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
12+
<PackageReference Include="Moq" Version="4.16.1" />
13+
<PackageReference Include="xunit" Version="2.4.1" />
1414
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
1515
<PrivateAssets>all</PrivateAssets>
1616
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1717
</PackageReference>
1818
</ItemGroup>
1919

2020
<ItemGroup>
21-
<ProjectReference Include="..\..\src\Hashids.net\Hashids.net.csproj"/>
21+
<ProjectReference Include="..\..\src\Hashids.net\Hashids.net.csproj" />
2222
</ItemGroup>
2323

2424
</Project>

0 commit comments

Comments
 (0)