Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ string password = generator.Generate(16);
Console.WriteLine(password); // Example output: kAj79uV@E?m7_8eS
```

### Using WithDefaults
Quickly generate a password using default pools:
```csharp
PasswordSettings settings = PasswordSettings.WithDefaults(minLower: 2, minUpper: 2, minDigits: 2, minSpecial: 1);
PasswordGenerator generator = new(settings);

string password = generator.Generate(12);
```

## Additional Methods

### `GenerateRandomLength(int minPasswordLength, int maxPasswordLength)`
Expand Down
46 changes: 46 additions & 0 deletions src/KPasswordGenerator.Tests/PasswordSettingsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
namespace KPasswordGenerator.Tests;

public class PasswordSettingsTests
{
[Fact]
public void WithDefaults_UsesExpectedDefaults()
{
var settings = PasswordSettings.WithDefaults();

Assert.Equal(4, settings.CharacterRequirements.Count);
Assert.Contains(settings.CharacterRequirements, r =>
r.MinRequired == 1 && r.CharacterPool == CharacterPools.LowerCase);
Assert.Contains(settings.CharacterRequirements, r =>
r.MinRequired == 1 && r.CharacterPool == CharacterPools.UpperCase);
Assert.Contains(settings.CharacterRequirements, r =>
r.MinRequired == 1 && r.CharacterPool == CharacterPools.Digits);
Assert.Contains(settings.CharacterRequirements, r =>
r.MinRequired == 1 && r.CharacterPool == CharacterPools.Special);
}

[Fact]
public void WithDefaults_AllZero_ReturnsEmptyRequirements()
{
var settings = PasswordSettings.WithDefaults(0, 0, 0, 0);

Assert.Empty(settings.CharacterRequirements);
}

[Fact]
public void WithDefaults_CreatesRequirementsWithCorrectValues()
{
int lower = 2, upper = 3, digits = 4, special = 5;

var settings = PasswordSettings.WithDefaults(lower, upper, digits, special);

Assert.Equal(4, settings.CharacterRequirements.Count);
Assert.Contains(settings.CharacterRequirements, r =>
r.MinRequired == lower && r.CharacterPool == CharacterPools.LowerCase);
Assert.Contains(settings.CharacterRequirements, r =>
r.MinRequired == upper && r.CharacterPool == CharacterPools.UpperCase);
Assert.Contains(settings.CharacterRequirements, r =>
r.MinRequired == digits && r.CharacterPool == CharacterPools.Digits);
Assert.Contains(settings.CharacterRequirements, r =>
r.MinRequired == special && r.CharacterPool == CharacterPools.Special);
}
}
2 changes: 2 additions & 0 deletions src/KPasswordGenerator/CharacterPools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ public static class CharacterPools

public const string UpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

public const string Digits = "0123456789";

public const string Special = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
}
14 changes: 11 additions & 3 deletions src/KPasswordGenerator/PasswordGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Security.Cryptography;
using System.Security.Cryptography;

namespace KPasswordGenerator;

Expand Down Expand Up @@ -53,9 +53,17 @@ public bool Validate(string password)

foreach (var requirement in _passwordSettings.CharacterRequirements)
{
int count = password.Count(requirement.CharacterPool.Contains);
int count = 0;

if (count < requirement.MinRequired) return false;
for (int i = 0; i < password.Length && count < requirement.MinRequired; i++)
{
if (requirement.CharacterPool.Contains(password[i]))
{
count++;
}
}

if (count != requirement.MinRequired) return false;
}

return true;
Expand Down
19 changes: 19 additions & 0 deletions src/KPasswordGenerator/PasswordSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,23 @@ public PasswordSettings(ICollection<CharacterRequirement> characterRequirements)
}

public ICollection<CharacterRequirement> CharacterRequirements { get; }

public static PasswordSettings WithDefaults(int minLower = 1, int minUpper = 1, int minDigits = 1, int minSpecial = 1)
{
List<CharacterRequirement> requirements = [];

if (minLower > 0)
requirements.Add(new CharacterRequirement(minLower, CharacterPools.LowerCase));

if (minUpper > 0)
requirements.Add(new CharacterRequirement(minUpper, CharacterPools.UpperCase));

if (minDigits > 0)
requirements.Add(new CharacterRequirement(minDigits, CharacterPools.Digits));

if (minSpecial > 0)
requirements.Add(new CharacterRequirement(minSpecial, CharacterPools.Special));

return new PasswordSettings(requirements);
}
}