Skip to content

Commit

Permalink
Merge pull request #14 from bolorundurowb/feature/add-short-id-options
Browse files Browse the repository at this point in the history
feature/add short id options
  • Loading branch information
Bolorunduro Winner-Timothy B authored Jun 29, 2020
2 parents f846552 + 174f7c5 commit 72f2d06
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 26 deletions.
71 changes: 71 additions & 0 deletions shortid.Test/Configuration/GenerationOptions.Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using FluentAssertions;
using shortid.Configuration;
using Xunit;

namespace shortid.Test.Configuration
{
public class GenerationOptionsTests
{
[Fact]
public void ShouldSetDefaultsOnInstantiation()
{
var options = new GenerationOptions();

options
.Length
.Should()
.BeGreaterThan(0);
options
.UseNumbers
.Should()
.BeFalse();
options
.UseSpecialCharacters
.Should()
.BeTrue();
}

[Fact]
public void ShouldAssignRandomLengthOnInstantiation()
{
var options = new GenerationOptions();

options
.Length
.Should()
.BeGreaterThan(7);
options
.Length
.Should()
.BeLessThan(15);
}

[Fact]
public void ShouldAllowDefaultsToBeChanged()
{
const bool useNumbers = true;
const bool useSpecial = false;
const int length = 17;

var options = new GenerationOptions
{
UseNumbers = useNumbers,
UseSpecialCharacters = useSpecial,
Length = length
};

options
.Length
.Should()
.Be(length);
options
.UseNumbers
.Should()
.Be(useNumbers);
options
.UseSpecialCharacters
.Should()
.Be(useSpecial);
}
}
}
24 changes: 19 additions & 5 deletions shortid.Test/ShortId.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,30 @@ public void GenerateCreatesIdsWithoutSpecialCharacters()
{
var id = ShortId.Generate(true, false);
var ans = new[] {"-", "_"}.Any(x => id.Contains(x));

ans.Should().BeFalse();
}

[Fact]
public void GenerateCreatesIdsOfASpecifiedLength()
{
var id = ShortId.Generate(false, true, 8);
id.Length.Should().Be(8);

id
.Length
.Should()
.Be(8);
}

[Fact]
public void SetSeedThrowsWhenCharacterSetIsEmptyOrNull()
{
var seed = string.Empty;
Action action = () => { ShortId.SetCharacters(seed); };
action.Should().Throw<ArgumentException>()

action
.Should()
.Throw<ArgumentException>()
.WithMessage("The replacement characters must not be null or empty.");
}

Expand All @@ -52,7 +60,10 @@ public void SetSeedThrowsWhenCharacterSetIsLessThan20Characters()
{
const string seed = "783ujrcuei039kj4";
Action action = () => { ShortId.SetCharacters(seed); };
action.Should().Throw<InvalidOperationException>()

action
.Should()
.Throw<InvalidOperationException>()
.WithMessage(
"The replacement characters must be at least 20 letters in length and without whitespace.");
}
Expand All @@ -61,7 +72,10 @@ public void SetSeedThrowsWhenCharacterSetIsLessThan20Characters()
public void DoesNotAllowLengthsLessThan7()
{
Action action = () => { ShortId.Generate(6); };
action.Should().ThrowExactly<ArgumentException>()

action
.Should()
.ThrowExactly<ArgumentException>()
.WithMessage("The specified length of 6 is less than the lower limit of 7.");
}

Expand All @@ -81,4 +95,4 @@ public void ShouldAllowForACustomSeed()
.NotThrow<Exception>();
}
}
}
}
2 changes: 1 addition & 1 deletion shortid.Test/shortid.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.msbuild" Version="2.8.0">
<PackageReference Include="coverlet.msbuild" Version="2.9.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
26 changes: 26 additions & 0 deletions shortid/Configuration/GenerationOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using shortid.Utils;

namespace shortid.Configuration
{
public class GenerationOptions
{
/// <summary>
/// Determines whether numbers are used in generating the id
/// Default: false
/// </summary>
public bool UseNumbers { get; set; }

/// <summary>
/// Determines whether special characters are used in generating the id
/// Default: true
/// </summary>
public bool UseSpecialCharacters { get; set; } = true;

/// <summary>
/// Determines the length of the generated id
/// Default: a random length between 7 and 15
/// </summary>
public int Length { get; set; } =
RandomUtils.GenerateNumberInRange(Constants.MinimumAutoLength, Constants.MaximumAutoLength);
}
}
70 changes: 51 additions & 19 deletions shortid/ShortId.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Text;
using shortid.Configuration;

namespace shortid
{
Expand All @@ -22,10 +23,15 @@ public static class ShortId
/// <param name="useNumbers">Whether or not to include numbers.</param>
/// <param name="useSpecial">Whether or not special characters are included.</param>
/// <returns>A random string.</returns>
[Obsolete("Use the Generate(options) overload instead")]
public static string Generate(bool useNumbers = false, bool useSpecial = true)
{
var length = _random.Next(7, 15);
return Generate(useNumbers, useSpecial, length);
var options = new GenerationOptions
{
UseNumbers = useNumbers,
UseSpecialCharacters = useSpecial
};
return Generate(options);
}

/// <summary>
Expand All @@ -35,11 +41,44 @@ public static string Generate(bool useNumbers = false, bool useSpecial = true)
/// <param name="useSpecial">Whether or not special characters are included.</param>
/// <param name="length">The length of the generated string.</param>
/// <returns>A random string.</returns>
[Obsolete("Use the Generate(options) overload instead")]
public static string Generate(bool useNumbers, bool useSpecial, int length)
{
if (length < 7)
var options = new GenerationOptions
{
throw new ArgumentException($"The specified length of {length} is less than the lower limit of 7.");
UseNumbers = useNumbers,
UseSpecialCharacters = useSpecial,
Length = length
};
return Generate(options);
}

/// <summary>
/// Generates a random string of a specified length with special characters and without numbers.
/// </summary>
/// <param name="length">The length of the generated string.</param>
/// <returns>A random string.</returns>
[Obsolete("Use the Generate(options) overload instead")]
public static string Generate(int length)
{
var options = new GenerationOptions
{
Length = length
};
return Generate(options);
}

/// <summary>
/// Generates a random string of a specified length with the option to add numbers and special characters.
/// </summary>
/// <param name="options">The length of the generated string.</param>
/// <returns>A random string.</returns>
public static string Generate(GenerationOptions options)
{
if (options.Length < 7)
{
throw new ArgumentException(
$"The specified length of {options.Length} is less than the lower limit of 7.");
}

string characterPool;
Expand All @@ -52,20 +91,20 @@ public static string Generate(bool useNumbers, bool useSpecial, int length)
}

var poolBuilder = new StringBuilder(characterPool);
if (useNumbers)
if (options.UseNumbers)
{
poolBuilder.Append(Numbers);
}

if (useSpecial)
if (options.UseSpecialCharacters)
{
poolBuilder.Append(Specials);
}

var pool = poolBuilder.ToString();

var output = new char[length];
for (var i = 0; i < length; i++)
var output = new char[options.Length];
for (var i = 0; i < options.Length; i++)
{
var charIndex = rand.Next(0, pool.Length);
output[i] = pool[charIndex];
Expand All @@ -74,16 +113,6 @@ public static string Generate(bool useNumbers, bool useSpecial, int length)
return new string(output);
}

/// <summary>
/// Generates a random string of a specified length with special characetrs and without numbers.
/// </summary>
/// <param name="length">The length of the generated string.</param>
/// <returns>A random string.</returns>
public static string Generate(int length)
{
return Generate(false, true, length);
}

/// <summary>
/// Changes the character set that id's are generated from.
/// </summary>
Expand Down Expand Up @@ -111,7 +140,10 @@ public static void SetCharacters(string characters)
"The replacement characters must be at least 20 letters in length and without whitespace.");
}

_pool = stringBuilder.ToString();
lock (ThreadLock)
{
_pool = stringBuilder.ToString();
}
}

/// <summary>
Expand Down
9 changes: 9 additions & 0 deletions shortid/Utils/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace shortid.Utils
{
internal static class Constants
{
public const int MinimumAutoLength = 7;

public const int MaximumAutoLength = 15;
}
}
18 changes: 18 additions & 0 deletions shortid/Utils/RandomUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace shortid.Utils
{
internal static class RandomUtils
{
private static readonly Random Random = new Random();
private static readonly object ThreadLock = new object();

public static int GenerateNumberInRange(int min, int max)
{
lock (ThreadLock)
{
return Random.Next(min, max);
}
}
}
}
4 changes: 3 additions & 1 deletion shortid/shortid.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
<PackageIconUrl>https://members.orcid.org/sites/default/files/vector_iD_icon.svg</PackageIconUrl>
<RepositoryUrl>https://github.com/bolorundurowb/shortid/</RepositoryUrl>
<PackageTags>shortid short id databse key primarykey mongodb sql</PackageTags>
<PackageReleaseNotes>update net standard support</PackageReleaseNotes>
<PackageReleaseNotes>- add a new configuration option
- add better thread safety features</PackageReleaseNotes>
<Authors>Bolorunduro Winner-Timothy</Authors>
<Description>A library that generates random Id's from 7 to 14 characters. Id's generated can be used as primary keys for databases or unique identifiers</Description>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Title>shortid</Title>
<RepositoryType>git</RepositoryType>
<PackageVersion>2.0.2</PackageVersion>
</PropertyGroup>
</Project>

0 comments on commit 72f2d06

Please sign in to comment.