Skip to content

Commit 08cbf7a

Browse files
Merge pull request #4 from DaveLiddament/feature/add-test-tag
Add #[TestTag]
2 parents a23a08f + 23b685f commit 08cbf7a

14 files changed

Lines changed: 334 additions & 7 deletions

README.md

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ This library provides attributes for extending the PHP language (e.g. adding `pa
44
The intention, at least initially, is that these extra language features are enforced by static analysis tools (such as Psalm, PHPStan and, ideally, PhpStorm) and NOT at runtime.
55

66
**Language feature added:**
7-
- [package](#package)
8-
- [friend](#friend)
9-
- [sealed](#sealed)
7+
- [Friend](#friend)
8+
- [Package](#package)
9+
- [Sealed](#sealed)
10+
- [TestTag](#testtag)
1011

1112

1213
### Contents
@@ -15,9 +16,10 @@ The intention, at least initially, is that these extra language features are enf
1516
- [PHPStan](#phpstan)
1617
- [Psalm](#psalm)
1718
- [New Language Features](#new-language-features)
18-
- [package](#package)
19-
- [friend](#friend)
20-
- [sealed](#sealed)
19+
- [Package](#package)
20+
- [Friend](#friend)
21+
- [Sealed](#sealed)
22+
- [TestTag](#testtag)
2123
- [Further examples](#further-examples)
2224
- [Contributing](#contributing)
2325

@@ -148,7 +150,7 @@ namespace Bar {
148150
**NOTES:**
149151

150152
- If adding the `#[Package]` to a method, this method MUST have public visibility.
151-
- If a class is marked with `#[Package]` then all its public methods are treated as having protected visibility.
153+
- If a class is marked with `#[Package]` then all its public methods are treated as having package visibility.
152154
- This is currently limited to method calls (including `__construct`).
153155
- Namespaces must match exactly. E.g. a package level method in `Foo\Bar` is only accessible from `Foo\Bar`. It is not accessible from `Foo` or `Foo\Bar\Baz`
154156

@@ -229,6 +231,46 @@ class Failure extends Result {}
229231
class AnotherClass extends Result {}
230232
```
231233

234+
## TestTag
235+
236+
The `#[TestTag]` attribute is an idea borrowed from hardware testing. Methods marked with this attribute are only available to test code.
237+
238+
E.g.
239+
240+
```php
241+
class Person {
242+
243+
#[TestTag]
244+
public function setId(int $id)
245+
{
246+
$this->id = $id;
247+
}
248+
}
249+
250+
251+
function updatePersonId(Person $person): void
252+
{
253+
$person->setId(10); // ERROR - not test code.
254+
}
255+
256+
257+
class PersonTest
258+
{
259+
public function setup(): void
260+
{
261+
$person = new Person();
262+
$person->setId(10); // OK - This is test code.
263+
}
264+
}
265+
```
266+
267+
NOTES:
268+
- Methods with the`#[TestTag]` MUST have public visibility.
269+
- For determining what is "test code" see the relevant plugin. E.g. the [PHPStan extension](https://github.com/DaveLiddament/phpstan-php-language-extensions) can be setup to either:
270+
- Assume all classes that end `Test` is test code. See [className config option](https://github.com/DaveLiddament/phpstan-php-language-extensions#exclude-checks-on-class-names-ending-with-test).
271+
- Assume all classes within a namespace is test code. See [namespace config option](https://github.com/DaveLiddament/phpstan-php-language-extensions#exclude-checks-based-on-test-namespace).
272+
273+
232274
## Further examples
233275

234276
More detailed examples of how to use attributes is found in [examples](examples/).
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace TestTagOnConstructor;
4+
5+
6+
use DaveLiddament\PhpLanguageExtensions\TestTag;
7+
8+
class Person
9+
{
10+
#[TestTag]
11+
public function __construct()
12+
{
13+
}
14+
15+
public static function create(): Person
16+
{
17+
return new Person(); // ERROR
18+
}
19+
20+
public static function createSelf(): self
21+
{
22+
return new self(); // ERROR
23+
}
24+
}
25+
26+
class AnotherClass
27+
{
28+
public function buildPerson(): Person
29+
{
30+
return new Person(); // ERROR
31+
}
32+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace TestTagOnConstructorIgnoredInTestClass;
4+
5+
use DaveLiddament\PhpLanguageExtensions\TestTag;
6+
7+
class Person
8+
{
9+
#[TestTag]
10+
public function __construct()
11+
{
12+
}
13+
}
14+
15+
class PersonTest
16+
{
17+
public function buildPerson(): Person
18+
{
19+
return new Person(); // OK TetTag called from a test class
20+
}
21+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace TestTagOnConstructorIgnoredInTestNamespace {
4+
5+
use DaveLiddament\PhpLanguageExtensions\TestTag;
6+
7+
class Person
8+
{
9+
#[TestTag]
10+
public function __construct()
11+
{
12+
}
13+
}
14+
15+
}
16+
17+
18+
namespace TestTagOnConstructorIgnoredInTestNamespace\Test {
19+
20+
use TestTagOnConstructorIgnoredInTestNamespace\Person;
21+
22+
class PersonBuilder
23+
{
24+
public function buildPerson(): Person
25+
{
26+
return new Person(); // OK TetTag called from the test namespace
27+
}
28+
}
29+
30+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TestTagOnMethod;
6+
7+
use DaveLiddament\PhpLanguageExtensions\TestTag;
8+
9+
class Person
10+
{
11+
#[TestTag]
12+
public function updateName(): void
13+
{
14+
}
15+
16+
public function update(): void
17+
{
18+
$this->updateName(); // ERROR
19+
}
20+
}
21+
22+
class Updater
23+
{
24+
public function updater(Person $person): void
25+
{
26+
$person->updateName(); // ERROR
27+
}
28+
}
29+
30+
$person = new Person();
31+
$person->updateName(); // ERROR
32+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TestTagOnMethodIgnoredInTestClass;
6+
7+
use DaveLiddament\PhpLanguageExtensions\TestTag;
8+
9+
class Person
10+
{
11+
#[TestTag]
12+
public function updateName(): void
13+
{
14+
}
15+
16+
}
17+
18+
class PersonTest
19+
{
20+
public function updater(Person $person): void
21+
{
22+
$person->updateName(); // OK - Called from Test class
23+
}
24+
}
25+
26+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TestTagOnMethodIgnoredInTestNamespace {
6+
7+
use DaveLiddament\PhpLanguageExtensions\TestTag;
8+
9+
class Person
10+
{
11+
#[TestTag]
12+
public function updateName(): void
13+
{
14+
}
15+
16+
}
17+
}
18+
19+
namespace TestTagOnMethodIgnoredInTestNamespace\Test {
20+
21+
use TestTagOnMethodIgnoredInTestNamespace\Person;
22+
23+
class PersonUpdater
24+
{
25+
public function updater(Person $person): void
26+
{
27+
$person->updateName(); // OK - Called from Test namespace
28+
}
29+
}
30+
}
31+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace TestTagOnStaticMethod;
4+
5+
6+
use DaveLiddament\PhpLanguageExtensions\TestTag;
7+
8+
class Person
9+
{
10+
#[TestTag]
11+
public static function updateName(): void
12+
{
13+
}
14+
15+
public static function update(): void
16+
{
17+
Person::updateName(); // ERROR
18+
}
19+
20+
public static function updateSelf(): void
21+
{
22+
self::updateName(); // ERROR
23+
}
24+
}
25+
26+
class Updater
27+
{
28+
public function updater(): void
29+
{
30+
Person::updateName(); // ERROR
31+
}
32+
}
33+
34+
Person::updateName(); // ERROR
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace TestTagOnStaticMethodIgnoredInTestClass;
4+
5+
6+
use DaveLiddament\PhpLanguageExtensions\TestTag;
7+
8+
class Person
9+
{
10+
#[TestTag]
11+
public static function updateName(): void
12+
{
13+
}
14+
}
15+
16+
class PersonTest
17+
{
18+
public function updater(): void
19+
{
20+
Person::updateName(); // OK - Called from a test class
21+
}
22+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace TestTagOnStaticMethodIgnoredInTestNamepace {
4+
5+
6+
use DaveLiddament\PhpLanguageExtensions\TestTag;
7+
8+
class Person
9+
{
10+
#[TestTag]
11+
public static function updateName(): void
12+
{
13+
}
14+
}
15+
}
16+
17+
namespace TestTagOnStaticMethodIgnoredInTestNamepace\Test {
18+
19+
use TestTagOnStaticMethodIgnoredInTestNamepace\Person;
20+
21+
class PersonUpdater
22+
{
23+
public function updater(): void
24+
{
25+
Person::updateName(); // OK - Called from a test namespace
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)