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
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,35 @@ string password = generator.Generate(16);
Console.WriteLine(password); // Example output: kAj79uV@E?m7_8eS
```

## Additional Methods

### `GenerateRandomLength(int minPasswordLength, int maxPasswordLength)`

Generates a password of **random length within a specified range**.

- Ensures the generated password meets all defined character requirements.
- Uses secure randomness to choose the length.

**Example:**
```csharp
string password = generator.GenerateRandomLength(12, 20);
```

---

### `Validate(string password)`

Validates whether a password meets the current `PasswordSettings` policy.

- Checks overall length.
- Verifies that the required number of characters from each character pool are present.
- Returns `true` if all rules pass, otherwise `false`.

- **Example:**
```csharp
bool isValid = generator.Validate("abcD123!");
```

## Installation

Install via NuGet:
Expand Down
85 changes: 85 additions & 0 deletions src/KPasswordGenerator.Tests/PasswordGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,89 @@ public void Generate_DoesNotReturnSamePasswordEveryTime()

Assert.NotEqual(password1, password2); // May rarely fail on pure randomness
}

[Theory]
[InlineData(6, 12)]
[InlineData(10, 10)] // exact length
[InlineData(4, 5)]
public void GenerateRandomLength_ReturnsPasswordWithinRange(int min, int max)
{
var generator = CreateDefaultGenerator();

string password = generator.GenerateRandomLength(min, max);

Assert.InRange(password.Length, min, max);
}

[Fact]
public void GenerateRandomLength_Throws_WhenMinGreaterThanMax()
{
var generator = CreateDefaultGenerator(); ;

Assert.Throws<ArgumentOutOfRangeException>(() =>
generator.GenerateRandomLength(10, 5));
}

[Fact]
public void GenerateRandomLength_Throws_WhenMinLessThanRequired()
{
var generator = CreateDefaultGenerator();
int tooSmall = 3;

Assert.Throws<ArgumentOutOfRangeException>(() =>
generator.GenerateRandomLength(tooSmall, 10));
}

[Fact]
public void Validate_ReturnsTrue_WhenPasswordMeetsAllRequirements()
{
var generator = CreateDefaultGenerator();

// 'a', 'b' (from "abc"), '1' (from "123"), '!' (from "!@#")
string validPassword = "ab1!xyz";

Assert.True(generator.Validate(validPassword));
}

[Fact]
public void Validate_ReturnsFalse_WhenPasswordTooShort()
{
var generator = CreateDefaultGenerator();

string shortPassword = "a1!";

Assert.False(generator.Validate(shortPassword));
}

[Fact]
public void Validate_ReturnsFalse_WhenRequirementNotMet()
{
var generator = CreateDefaultGenerator();

// Missing digits
string invalidPassword = "ab!!xyz";

Assert.False(generator.Validate(invalidPassword));
}

[Fact]
public void Validate_Throws_WhenPasswordIsNull()
{
var generator = CreateDefaultGenerator();

Assert.Throws<ArgumentNullException>(() =>
generator.Validate(null!));
}

private static PasswordGenerator CreateDefaultGenerator()
{
List<CharacterRequirement> requirements =
[
new CharacterRequirement(2, "abc"),
new CharacterRequirement(1, "123"),
new CharacterRequirement(1, "!@#")
];

return new PasswordGenerator(new PasswordSettings(requirements));
}
}
26 changes: 26 additions & 0 deletions src/KPasswordGenerator/PasswordGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,30 @@ public string Generate(int passwordLength)

return buffer.ToString();
}

public string GenerateRandomLength(int minPasswordLength, int maxPasswordLength)
{
ArgumentOutOfRangeException.ThrowIfGreaterThan(minPasswordLength, maxPasswordLength);
ArgumentOutOfRangeException.ThrowIfLessThan(minPasswordLength, _passwordSettings.MinimumPasswordLength);

int length = RandomNumberGenerator.GetInt32(minPasswordLength, maxPasswordLength + 1);

return Generate(length);
}

public bool Validate(string password)
{
ArgumentNullException.ThrowIfNull(password);

if (password.Length < _passwordSettings.MinimumPasswordLength) return false;

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

if (count < requirement.MinRequired) return false;
}

return true;
}
}