Skip to content

Commit e0d8569

Browse files
committed
TASK: add tests
1 parent d8731f9 commit e0d8569

15 files changed

+444
-45
lines changed

.github/workflows/ci.yml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: CI-coverage
2+
3+
on: [ push ]
4+
5+
jobs:
6+
build-test:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
php-version: [ 8.1, 8.2, 8.3 ]
11+
12+
steps:
13+
- uses: actions/checkout@v3
14+
15+
- uses: php-actions/composer@v6
16+
17+
- name: PHPUnit Tests
18+
uses: php-actions/phpunit@v3
19+
with:
20+
php_version: ${{ matrix.php-version }}
21+
php_extensions: xdebug
22+
bootstrap: vendor/autoload.php
23+
configuration: phpunit.xml
24+
coverage_text: true
25+
env:
26+
XDEBUG_MODE: coverage

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
composer.lock
33
vendor
44
Packages
5+
.phpunit.cache

Classes/Factory/PolicyFactory.php

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ class PolicyFactory
1212
{
1313
/**
1414
* @throws InvalidDirectiveException
15+
* @param string[][] $defaultDirective
16+
* @param string[][] $customDirective
1517
*/
1618
public static function create(Nonce $nonce, array $defaultDirective, array $customDirective): Policy
1719
{

Classes/Helpers/TagHelper.php

+12-15
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
class TagHelper
88
{
9-
public const NONCE = 'nonce';
10-
119
public static function tagHasAttribute(
1210
string $tag,
1311
string $name,
@@ -18,15 +16,15 @@ public static function tagHasAttribute(
1816
self::buildMatchAttributeNameReqex($name),
1917
$tag
2018
);
21-
} else {
22-
return ! ! preg_match(
23-
self::buildMatchAttributeNameWithSpecificValueReqex(
24-
$name,
25-
$value
26-
),
27-
$tag
28-
);
2919
}
20+
21+
return ! ! preg_match(
22+
self::buildMatchAttributeNameWithSpecificValueReqex(
23+
$name,
24+
$value
25+
),
26+
$tag
27+
);
3028
}
3129

3230
public static function tagChangeAttributeValue(
@@ -63,9 +61,9 @@ function ($hits) use ($name, $value) {
6361
$value.
6462
'"'.
6563
$hits["end"];
66-
} else {
67-
return $hits["start"].' '.$name.$hits["end"];
6864
}
65+
66+
return $hits["start"].' '.$name.$hits["end"];
6967
},
7068
$tag
7169
);
@@ -82,9 +80,8 @@ private static function buildMatchEndOfOpeningTagReqex(): string
8280
return '/(?<start><[a-z]+.*?)(?<end>>|\/>)/';
8381
}
8482

85-
private static function buildMatchAttributeNameWithAnyValueReqex(
86-
string $name
87-
): string {
83+
private static function buildMatchAttributeNameWithAnyValueReqex(string $name): string
84+
{
8885
$nameQuoted = self::escapeReqexCharsInString($name);
8986

9087
return '/(?<pre><.*? )(?<name>'.

Classes/Http/CspHeaderMiddleware.php

+5-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
class CspHeaderMiddleware implements MiddlewareInterface
2222
{
23+
private const NONCE = 'nonce';
24+
2325
/**
2426
* @Flow\InjectConfiguration(path="enabled")
2527
*/
@@ -101,11 +103,11 @@ private function addNonceToTags(string $markup): string
101103
return $this->checkTagAndReplaceUsingACallback($tagNames, $markup, function (
102104
$tagMarkup,
103105
) {
104-
if (TagHelper::tagHasAttribute($tagMarkup, TagHelper::NONCE)) {
105-
return TagHelper::tagChangeAttributeValue($tagMarkup, TagHelper::NONCE, $this->nonce->getValue());
106+
if (TagHelper::tagHasAttribute($tagMarkup, self::NONCE)) {
107+
return TagHelper::tagChangeAttributeValue($tagMarkup, self::NONCE, $this->nonce->getValue());
106108
}
107109

108-
return TagHelper::tagAddAttribute($tagMarkup, TagHelper::NONCE, $this->nonce->getValue());
110+
return TagHelper::tagAddAttribute($tagMarkup, self::NONCE, $this->nonce->getValue());
109111
});
110112
}
111113

Classes/Model/Nonce.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ public function getValue(): string
2929
return $this->value;
3030
}
3131

32-
public function __toString()
32+
public function __toString(): string
3333
{
34-
return $this->value;
34+
return $this->getValue();
3535
}
3636

3737
/**

Classes/Model/Policy.php

+11-25
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,9 @@ public function setNonce(Nonce $nonce): Policy
4040
return $this;
4141
}
4242

43-
public function isReportOnly(): bool
44-
{
45-
return $this->reportOnly;
46-
}
47-
4843
public function getSecurityHeaderKey(): string
4944
{
50-
if ($this->isReportOnly()) {
45+
if ($this->reportOnly) {
5146
return self::SECURITY_HEADER_KEY_REPORT_ONLY;
5247
}
5348

@@ -59,10 +54,16 @@ public function getDirectives(): array
5954
return $this->directives;
6055
}
6156

57+
public function hasNonceDirectiveValue(): bool
58+
{
59+
return $this->hasNonceDirectiveValue;
60+
}
61+
6262
/**
63+
* @param string[] $values
6364
* @throws InvalidDirectiveException
6465
*/
65-
public function addDirective(string $directive, $values): self
66+
public function addDirective(string $directive, array $values): self
6667
{
6768
if (! Directive::isValidDirective($directive)) {
6869
throw new InvalidDirectiveException($directive);
@@ -74,16 +75,6 @@ public function addDirective(string $directive, $values): self
7475
return $this;
7576
}
7677

77-
public function getNonce(): Nonce
78-
{
79-
return $this->nonce;
80-
}
81-
82-
public function hasNonceDirectiveValue(): bool
83-
{
84-
return $this->hasNonceDirectiveValue;
85-
}
86-
8778
public function __toString(): string
8879
{
8980
$directives = $this->getDirectives();
@@ -95,26 +86,21 @@ public function __toString(): string
9586
return "$directive $value";
9687
}, $directives, $keys);
9788

98-
return implode(';', $items).';';
89+
return implode('; ', $items).';';
9990
}
10091

10192
private function sanitizeValue(string $value): string
10293
{
103-
if ($this->isSpecialValue($value)) {
94+
if (in_array($value, self::SPECIAL_DIRECTIVES)) {
10495
return "'$value'";
10596
}
10697

10798
if ($value === '{nonce}') {
10899
$this->hasNonceDirectiveValue = true;
109100

110-
return "'nonce-".$this->getNonce()->getValue()."'";
101+
return "'nonce-".$this->nonce->getValue()."'";
111102
}
112103

113104
return $value;
114105
}
115-
116-
private function isSpecialValue(string $directive): bool
117-
{
118-
return in_array($directive, self::SPECIAL_DIRECTIVES);
119-
}
120106
}
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Unit\Factory;
6+
7+
use Flowpack\ContentSecurityPolicy\Factory\PolicyFactory;
8+
use Flowpack\ContentSecurityPolicy\Model\Directive;
9+
use Flowpack\ContentSecurityPolicy\Model\Nonce;
10+
use Flowpack\ContentSecurityPolicy\Model\Policy;
11+
use PHPUnit\Framework\Attributes\CoversClass;
12+
use PHPUnit\Framework\Attributes\UsesClass;
13+
use PHPUnit\Framework\TestCase;
14+
15+
#[CoversClass(PolicyFactory::class)]
16+
#[UsesClass(Policy::class)]
17+
#[UsesClass(Directive::class)]
18+
class PolicyFactoryTest extends TestCase
19+
{
20+
public function testCreateShouldReturnPolicy(): void
21+
{
22+
$nonceMock = $this->createMock(Nonce::class);
23+
24+
$defaultDirective = [
25+
'base-uri' => [
26+
'self',
27+
],
28+
'script-src' => [
29+
'self',
30+
],
31+
];
32+
$customDirective = [
33+
'script-src' => [
34+
'{nonce}',
35+
],
36+
];
37+
38+
$expected = [
39+
'base-uri' => [
40+
"'self'",
41+
],
42+
'script-src' => [
43+
"'self'",
44+
"'nonce-'",
45+
],
46+
];
47+
48+
$result = PolicyFactory::create($nonceMock, $defaultDirective, $customDirective);
49+
50+
self::assertSame($expected, $result->getDirectives());
51+
}
52+
}

Tests/Unit/Helpers/TagHelperTest.php

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Unit\Helpers;
6+
7+
use Flowpack\ContentSecurityPolicy\Helpers\TagHelper;
8+
use PHPUnit\Framework\Attributes\CoversClass;
9+
use PHPUnit\Framework\TestCase;
10+
11+
#[CoversClass(TagHelper::class)]
12+
class TagHelperTest extends TestCase
13+
{
14+
public function testTagHasAttributeWithoutValueShouldReturnTrue(): void
15+
{
16+
$tag = '<script src="https://google.com"></script>';
17+
self::assertTrue(TagHelper::tagHasAttribute($tag, 'src'));
18+
}
19+
20+
public function testTagHasAttributeWithoutValueShouldReturnFalse(): void
21+
{
22+
$tag = '<script src="https://google.com"></script>';
23+
self::assertFalse(TagHelper::tagHasAttribute($tag, 'bar'));
24+
}
25+
26+
public function testTagHasAttributeWithValueShouldReturnTrue(): void
27+
{
28+
$tag = '<script src="https://google.com"></script>';
29+
self::assertTrue(TagHelper::tagHasAttribute($tag, 'src', 'https://google.com'));
30+
}
31+
32+
public function testTagHasAttributeWithValueShouldReturnFalse(): void
33+
{
34+
$tag = '<script src="https://google.com"></script>';
35+
self::assertFalse(TagHelper::tagHasAttribute($tag, 'src', 'another value'));
36+
}
37+
38+
public function testTagChangeAttributeValueShouldChangeValue(): void
39+
{
40+
$tag = '<script src="https://google.com"></script>';
41+
42+
self::assertSame(
43+
'<script src="https://test.com"></script>',
44+
TagHelper::tagChangeAttributeValue($tag, 'src', 'https://test.com')
45+
);
46+
}
47+
48+
public function testTagChangeAttributeValueShouldDoNothingIfAttributeDoesntExist(): void
49+
{
50+
$tag = '<script src="https://google.com"></script>';
51+
52+
self::assertSame(
53+
'<script src="https://google.com"></script>',
54+
TagHelper::tagChangeAttributeValue($tag, 'nonce', 'da65sf1g')
55+
);
56+
}
57+
58+
public function testTagAddAttributeShouldAddAttributeWithValue(): void
59+
{
60+
$tag = '<script src="https://google.com"></script>';
61+
62+
self::assertSame(
63+
'<script src="https://google.com" nonce="da65sf1g"></script>',
64+
TagHelper::tagAddAttribute($tag, 'nonce', 'da65sf1g')
65+
);
66+
}
67+
68+
public function testTagAddAttributeShouldAddAttributeWithoutValue(): void
69+
{
70+
$tag = '<script src="https://google.com"></script>';
71+
72+
self::assertSame(
73+
'<script src="https://google.com" defer></script>',
74+
TagHelper::tagAddAttribute($tag, 'defer')
75+
);
76+
}
77+
}

0 commit comments

Comments
 (0)