Test Failed
Push — master ( 6aac34...7ebad7 )
by Magnar Ovedal
02:23
created

CharacterClass::__construct()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 4
nop 3
dl 0
loc 15
ccs 9
cts 9
cp 1
crap 5
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stadly\PasswordPolice\Rule;
6
7
use InvalidArgumentException;
8
use Stadly\PasswordPolice\Password;
9
use Stadly\PasswordPolice\Policy;
10
11
abstract class CharacterClass implements RuleInterface
12
{
13
    /**
14
     * @var string Characters matched by the rule.
15
     */
16
    protected $characters;
17
18
    /**
19
     * @var int Minimum number of characters matching the rule.
20
     */
21
    protected $min;
22
23
    /**
24
     * @var int|null Maximum number of characters matching the rule.
25
     */
26
    protected $max;
27
28
    /**
29
     * @param string $characters Characters matched by the rule.
30
     * @param int $min Minimum number of characters matching the rule.
31
     * @param int|null $max Maximum number of characters matching the rule.
32
     */
33 16
    public function __construct(string $characters, int $min = 1, ?int $max = null)
34
    {
35 16
        if ($characters === '') {
36 2
            throw new InvalidArgumentException('At least one character must be specified.');
37
        }
38 14
        if ($min < 0) {
39 2
            throw new InvalidArgumentException('Min cannot be negative.');
40
        }
41 12
        if ($max !== null && $max < $min) {
42 2
            throw new InvalidArgumentException('Max cannot be smaller than min.');
43
        }
44 10
45 2
        $this->characters = $characters;
46
        $this->min = $min;
47
        $this->max = $max;
48 8
    }
49 8
50 8
    /**
51 8
     * @return string Characters matched by the rule.
52
     */
53
    public function getCharacters(): string
54
    {
55
        return $this->characters;
56 2
    }
57
58 2
    /**
59
     * @return int Minimum number of characters matching the rule.
60
     */
61
    public function getMin(): int
62
    {
63
        return $this->min;
64 3
    }
65
66 3
    /**
67
     * @return int|null Maximum number of characters matching the rule.
68
     */
69
    public function getMax(): ?int
70
    {
71
        return $this->max;
72 3
    }
73
74 3
    /**
75
     * Check whether a password is in compliance with the rule.
76
     *
77
     * @param Password|string $password Password to check.
78
     * @return bool Whether the password is in compliance with the rule.
79
     */
80
    public function test($password): bool
81
    {
82
        $count = $this->getNoncompliantCount((string)$password);
83 12
84
        return $count === null;
85 12
    }
86
87 12
    /**
88
     * Enforce that a password is in compliance with the rule.
89
     *
90
     * @param Password|string $password Password that must adhere to the rule.
91
     * @throws RuleException If the password does not adhrere to the rule.
92
     */
93
    public function enforce($password): void
94
    {
95
        $count = $this->getNoncompliantCount((string)$password);
96 6
97
        if ($count !== null) {
98 6
            throw new RuleException($this, $this->getMessage());
99
        }
100 6
    }
101 3
102
    /**
103 3
     * @param string $password Password to count characters in.
104
     * @return int Number of characters matching the rule if not in compliance with the rule.
105
     */
106
    private function getNoncompliantCount(string $password): ?int
107
    {
108
        $count = $this->getCount($password);
109 18
110
        if ($count < $this->min) {
111 18
            return $count;
112
        }
113 18
114 6
        if (null !== $this->max && $this->max < $count) {
115
            return $count;
116
        }
117 12
118 3
        return null;
119
    }
120
121 9
    /**
122
     * @param string $password Password to count characters in.
123
     * @return int Number of characters matching the rule.
124
     */
125
    private function getCount(string $password): int
126
    {
127
        $escapedCharacters = preg_quote($this->characters);
128 18
        $count = preg_match_all('{['.$escapedCharacters.']}u', $password);
129
        assert(false !== $count);
130 18
131 18
        return $count;
132 18
    }
133
}
134