Skip to content

Commit

Permalink
Symbol rule
Browse files Browse the repository at this point in the history
  • Loading branch information
Stadly committed Dec 14, 2018
1 parent cbce73d commit 075f5ae
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 131 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip
## [Unreleased](https://github.com/Stadly/PasswordPolice/compare/v0.9.0...HEAD)

### Added
- Nothing
- Rule enforcing the use of symbols in passwords.

### Changed
- Improved exception messages.
- The character class rule can not be used directly anymore. Use the symbol rule instead.

### Fixed
- Nothing
Expand Down
59 changes: 1 addition & 58 deletions src/Rule/CharacterClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Stadly\PasswordPolice\Password;
use Stadly\PasswordPolice\Policy;

class CharacterClass implements RuleInterface
abstract class CharacterClass implements RuleInterface
{
/**
* @var string Characters matched by the rule.
Expand Down Expand Up @@ -133,61 +133,4 @@ private function getCount(string $password): int

return $count;
}

/**
* {@inheritDoc}
*/
public function getMessage(): string
{
$translator = Policy::getTranslator();

if ($this->max === null) {
return $translator->trans(
'There must be at least one character matching %characters%.|'.
'There must be at least %count% characters matching %characters%.',
[
'%count%' => $this->min,
'%characters%' => $this->characters,
]
);
}

if ($this->max === 0) {
return $translator->trans(
'There must be no characters matching %characters%.',
['%characters%' => $this->characters]
);
}

if ($this->min === 0) {
return $translator->trans(
'There must be at most one character matching %characters%.|'.
'There must be at most %count% characters matching %characters%.',
[
'%count%' => $this->max,
'%characters%' => $this->characters,
]
);
}

if ($this->min === $this->max) {
return $translator->trans(
'There must be exactly one character matching %characters%.|'.
'There must be exactly %count% characters matching %characters%.',
[
'%count%' => $this->min,
'%characters%' => $this->characters,
]
);
}

return $translator->trans(
'There must be between %min% and %max% characters matching %characters%.',
[
'%min%' => $this->min,
'%max%' => $this->max,
'%characters%' => $this->characters,
]
);
}
}
67 changes: 67 additions & 0 deletions src/Rule/Symbol.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace Stadly\PasswordPolice\Rule;

use Stadly\PasswordPolice\Policy;

final class Symbol extends CharacterClass
{
/**
* {@inheritDoc}
*/
public function getMessage(): string
{
$translator = Policy::getTranslator();

if ($this->max === null) {
return $translator->trans(
'There must be at least one symbol (%characters%).|'.
'There must be at least %count% symbols (%characters%).',
[
'%count%' => $this->min,
'%characters%' => $this->characters,
]
);
}

if ($this->max === 0) {
return $translator->trans(
'There must be no symbols (%characters%).',
['%characters%' => $this->characters]
);
}

if ($this->min === 0) {
return $translator->trans(
'There must be at most one symbol (%characters%).|'.
'There must be at most %count% symbols (%characters%).',
[
'%count%' => $this->max,
'%characters%' => $this->characters,
]
);
}

if ($this->min === $this->max) {
return $translator->trans(
'There must be exactly one symbol (%characters%).|'.
'There must be exactly %count% symbols (%characters%).',
[
'%count%' => $this->min,
'%characters%' => $this->characters,
]
);
}

return $translator->trans(
'There must be between %min% and %max% symbols (%characters%).',
[
'%min%' => $this->min,
'%max%' => $this->max,
'%characters%' => $this->characters,
]
);
}
}
94 changes: 22 additions & 72 deletions tests/Rule/CharacterClassTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ final class CharacterClassTest extends TestCase
*/
public function testCanConstructRuleWithMinConstraint(): void
{
$rule = new CharacterClass('$%&@!', 5, null);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 5, null]);

// Force generation of code coverage
$ruleConstruct = new CharacterClass('$%&@!', 5, null);
$ruleConstruct = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 5, null]);
self::assertEquals($rule, $ruleConstruct);
}

Expand All @@ -31,10 +31,10 @@ public function testCanConstructRuleWithMinConstraint(): void
*/
public function testCanConstructRuleWithMaxConstraint(): void
{
$rule = new CharacterClass('$%&@!', 0, 10);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 0, 10]);

// Force generation of code coverage
$ruleConstruct = new CharacterClass('$%&@!', 0, 10);
$ruleConstruct = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 0, 10]);
self::assertEquals($rule, $ruleConstruct);
}

Expand All @@ -43,10 +43,10 @@ public function testCanConstructRuleWithMaxConstraint(): void
*/
public function testCanConstructRuleWithBothMinAndMaxConstraint(): void
{
$rule = new CharacterClass('$%&@!', 5, 10);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 5, 10]);

// Force generation of code coverage
$ruleConstruct = new CharacterClass('$%&@!', 5, 10);
$ruleConstruct = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 5, 10]);
self::assertEquals($rule, $ruleConstruct);
}

Expand All @@ -57,7 +57,7 @@ public function testCannotConstructRuleWithNegativeMinConstraint(): void
{
$this->expectException(InvalidArgumentException::class);

$rule = new CharacterClass('$%&@!', -10, null);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', -10, null]);
}

/**
Expand All @@ -67,7 +67,7 @@ public function testCannotConstructRuleWithMaxConstraintSmallerThanMinConstraint
{
$this->expectException(InvalidArgumentException::class);

$rule = new CharacterClass('$%&@!', 10, 5);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 10, 5]);
}

/**
Expand All @@ -77,18 +77,18 @@ public function testCannotConstructUnconstrainedRule(): void
{
$this->expectException(InvalidArgumentException::class);

$rule = new CharacterClass('$%&@!', 0, null);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 0, null]);
}

/**
* @covers ::__construct
*/
public function testCanConstructRuleWithMinConstraintEqualToMaxConstraint(): void
{
$rule = new CharacterClass('$%&@!', 5, 5);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 5, 5]);

// Force generation of code coverage
$ruleConstruct = new CharacterClass('$%&@!', 5, 5);
$ruleConstruct = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 5, 5]);
self::assertEquals($rule, $ruleConstruct);
}

Expand All @@ -99,15 +99,15 @@ public function testCannotConstructRuleWithNoCharacters(): void
{
$this->expectException(InvalidArgumentException::class);

$rule = new CharacterClass('');
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['']);
}

/**
* @covers ::getCharacters
*/
public function testCanGetCharacters(): void
{
$rule = new CharacterClass('$%&@!');
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!']);

self::assertSame('$%&@!', $rule->getCharacters());
}
Expand All @@ -117,7 +117,7 @@ public function testCanGetCharacters(): void
*/
public function testCanGetMinConstraint(): void
{
$rule = new CharacterClass('$%&@!', 5, 10);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 5, 10]);

self::assertSame(5, $rule->getMin());
}
Expand All @@ -127,7 +127,7 @@ public function testCanGetMinConstraint(): void
*/
public function testCanGetMaxConstraint(): void
{
$rule = new CharacterClass('$%&@!', 5, 10);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 5, 10]);

self::assertSame(10, $rule->getMax());
}
Expand All @@ -137,7 +137,7 @@ public function testCanGetMaxConstraint(): void
*/
public function testMinConstraintCanBeSatisfied(): void
{
$rule = new CharacterClass('$%&@!', 2, null);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 2, null]);

self::assertTrue($rule->test('FOO bar $$@'));
}
Expand All @@ -147,7 +147,7 @@ public function testMinConstraintCanBeSatisfied(): void
*/
public function testMinConstraintCanBeUnsatisfied(): void
{
$rule = new CharacterClass('$%&@!', 2, null);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 2, null]);

self::assertFalse($rule->test('FOO BAR $'));
}
Expand All @@ -157,7 +157,7 @@ public function testMinConstraintCanBeUnsatisfied(): void
*/
public function testMaxConstraintCanBeSatisfied(): void
{
$rule = new CharacterClass('$%&@!', 0, 3);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 0, 3]);

self::assertTrue($rule->test('FOO bar $$@'));
}
Expand All @@ -167,7 +167,7 @@ public function testMaxConstraintCanBeSatisfied(): void
*/
public function testMaxConstraintCanBeUnsatisfied(): void
{
$rule = new CharacterClass('$%&@!', 0, 3);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 0, 3]);

self::assertFalse($rule->test('foo bar $$@!'));
}
Expand All @@ -177,12 +177,12 @@ public function testMaxConstraintCanBeUnsatisfied(): void
*/
public function testEnforceDoesNotThrowExceptionWhenRuleIsSatisfied(): void
{
$rule = new CharacterClass('$%&@!', 1, null);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 1, null]);

$rule->enforce('&');

// Force generation of code coverage
$ruleConstruct = new CharacterClass('$%&@!', 1, null);
$ruleConstruct = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 1, null]);
self::assertEquals($rule, $ruleConstruct);
}

Expand All @@ -191,60 +191,10 @@ public function testEnforceDoesNotThrowExceptionWhenRuleIsSatisfied(): void
*/
public function testEnforceThrowsExceptionWhenRuleIsNotSatisfied(): void
{
$rule = new CharacterClass('$%&@!', 1, null);
$rule = $this->getMockForAbstractClass(CharacterClass::class, ['$%&@!', 1, null]);

$this->expectException(RuleException::class);

$rule->enforce('');
}

/**
* @covers ::getMessage
*/
public function testCanGetMessageForRuleWithMinConstraint(): void
{
$rule = new CharacterClass('$%&@!', 5, null);

self::assertSame('There must be at least 5 characters matching $%&@!.', $rule->getMessage());
}

/**
* @covers ::getMessage
*/
public function testCanGetMessageForRuleWithMaxConstraint(): void
{
$rule = new CharacterClass('$%&@!', 0, 10);

self::assertSame('There must be at most 10 characters matching $%&@!.', $rule->getMessage());
}

/**
* @covers ::getMessage
*/
public function testCanGetMessageForRuleWithBothMinAndMaxConstraint(): void
{
$rule = new CharacterClass('$%&@!', 5, 10);

self::assertSame('There must be between 5 and 10 characters matching $%&@!.', $rule->getMessage());
}

/**
* @covers ::getMessage
*/
public function testCanGetMessageForRuleWithMaxConstraintEqualToZero(): void
{
$rule = new CharacterClass('$%&@!', 0, 0);

self::assertSame('There must be no characters matching $%&@!.', $rule->getMessage());
}

/**
* @covers ::getMessage
*/
public function testCanGetMessageForRuleWithMinConstraintEqualToMaxConstraint(): void
{
$rule = new CharacterClass('$%&@!', 3, 3);

self::assertSame('There must be exactly 3 characters matching $%&@!.', $rule->getMessage());
}
}
Loading

0 comments on commit 075f5ae

Please sign in to comment.