├── .editorconfig
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── README.md
├── composer.json
├── phpstan.neon
├── phpunit.xml.dist
├── src
├── AccessibilityHelperTrait.php
└── CompareTrait.php
└── tests
├── TestCase
├── AccessibilityHelperTraitTest.php
├── CompareTraitTest.php
├── html
│ ├── attributes.html
│ ├── empty.html
│ ├── nested.html
│ └── simple.html
├── json
│ ├── empty.json
│ ├── simple-array.json
│ ├── simple-dict.json
│ └── simple-int.json
└── xml
│ ├── empty.xml
│ └── simple.xml
└── comparisons
└── CompareTrait
├── attributes.html
├── empty.html
├── empty.json
├── empty.xml
├── nested.html
├── simple-array.json
├── simple-dict.json
├── simple-int.json
├── simple.html
└── simple.xml
/.editorconfig:
--------------------------------------------------------------------------------
1 | # .editorconfig
2 | # http://editorconfig.org/
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | indent_size = 4
9 | indent_style = space
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.yml]
14 | indent_size = 2
15 |
16 | [*.neon]
17 | indent_style = tab
18 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | branches:
9 | - '*'
10 |
11 | jobs:
12 | testsuite:
13 | runs-on: ubuntu-22.04
14 | strategy:
15 | fail-fast: false
16 | matrix:
17 | php-version: ['8.2']
18 | prefer-lowest: ['']
19 | include:
20 | - php-version: '8.1'
21 | prefer-lowest: 'prefer-lowest'
22 |
23 | steps:
24 | - uses: actions/checkout@v4
25 |
26 | - name: Setup PHP
27 | uses: shivammathur/setup-php@v2
28 | with:
29 | php-version: ${{ matrix.php-version }}
30 | extensions: mbstring, intl
31 | coverage: none
32 |
33 | - name: Composer install
34 | run: |
35 | if ${{ matrix.prefer-lowest == 'prefer-lowest' }}; then
36 | composer update --prefer-lowest --prefer-stable
37 | else
38 | composer update
39 | fi
40 |
41 | - name: Run PHPUnit
42 | run: vendor/bin/phpunit
43 |
44 | cs-stan:
45 | name: Coding Standard & Static Analysis
46 | runs-on: ubuntu-22.04
47 |
48 | steps:
49 | - uses: actions/checkout@v4
50 |
51 | - name: Setup PHP
52 | uses: shivammathur/setup-php@v2
53 | with:
54 | php-version: '8.1'
55 | extensions: mbstring, intl
56 | coverage: none
57 | tools: phpstan:1.10,cs2pr
58 |
59 | - name: Composer Install
60 | run: composer require cakephp/cakephp-codesniffer
61 |
62 | - name: Run phpcs
63 | run: vendor/bin/phpcs --report=checkstyle --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/ | cs2pr
64 |
65 | - name: Run phpstan
66 | if: always()
67 | run: phpstan --error-format=github
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | composer.lock
2 | phpunit.xml
3 | vendor
4 | .phpunit.cache
5 | .phpunit.result.cache
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Test utilities
2 |
3 | This package contains support traits to ease unit testing.
4 |
5 | ## Installing via composer
6 |
7 | You should install this package into your project using composer. To do so you
8 | can run the following command:
9 |
10 | ```bash
11 | composer require friendsofcake/cakephp-test-utilities
12 | ```
13 |
14 | ## Traits
15 |
16 | At this point there are two traits:
17 |
18 | 1. [`AccessibilityHelperTrait`](#accessibilityhelpertrait) : Gain access protected properties and methods.
19 | 2. [`CompareTrait`](#comparetrait) : Assert methods, comparing to files for: HTML, JSON, XML
20 |
21 | ### AccessibilityHelperTrait
22 |
23 | This trait gains you access to protected properties and methods. You don't need
24 | of a new class with pass-through methods. It uses reflection to achieve this.
25 |
26 | #### Setup
27 |
28 | Add the trait at the top of your test case:
29 |
30 | ``` php
31 | use \FriendsOfCake\TestUtilities\AccessibilityHelperTrait;
32 | ```
33 |
34 | Now that you have the trait you need to set which object you want to access.
35 | You can do this globally for the entire test in `setUp()` or in your test
36 | methods:
37 |
38 | ``` php
39 | $object = new ObjectIAmGoingToTest();
40 | $this->setReflectionClassInstance($object);
41 | $this->defaultReflectionTarget = $object; // (optional)
42 | ```
43 |
44 | #### Protected properties
45 |
46 | You can get and set the protected properties:
47 |
48 | ``` php
49 | $data = 'FriendsOfCake';
50 | $this->setProtectedProperty('_myProperty', $data, $object);
51 |
52 | $expected = $data;
53 | $actual = $this->getProtectedProperty('_myProperty', $object);
54 | $this->assertEquals($expected, $actual);
55 | ```
56 |
57 | #### Protected methods
58 |
59 | You can directly call protected methods:
60 |
61 | ``` php
62 | $parameters = [$argument1, $argument2];
63 |
64 | $expected = $expectedReturnValue;
65 | $actual = $this->callProtectedMethod('_myMethod', $parameters, $object);
66 | $this->assertEquals($expected, $actual);
67 | ```
68 |
69 | ### CompareTrait
70 |
71 | This trait helps with comparing test results as string
72 |
73 | #### Setup
74 |
75 | Add the trait at the top of your test case and define the `_compareBasePath`
76 | property so the trait knows where to look for comparison files:
77 |
78 | ``` php
79 | ...
80 | use \FriendsOfCake\TestUtilities\CompareTrait;
81 |
82 | class MyTest extends TestCase
83 | {
84 | use CompareTrait;
85 |
86 | public function setUp(): void
87 | {
88 | parent::setUp();
89 |
90 | $this->_compareBasePath = 'comparisons/MyTest/';
91 | }
92 | }
93 | ```
94 |
95 | #### Usage
96 |
97 | Each of the methods acts similar to the core `assertSameAsFile` method:
98 |
99 | ```php
100 | public function testExample()
101 | {
102 | $html = '
Some html
';
103 | $xml = '...';
104 | $json = ['actually' => 'this is an array'];
105 |
106 | $this->assertHtmlSameAsFile('some.html', $html);
107 | $this->assertXmlSameAsFile('some.xml', $xml);
108 | $this->assertJsonSameAsFile('some.json', $json);
109 | }
110 | ```
111 |
112 | See [Cake's docs](https://book.cakephp.org/5/en/development/testing.html#comparing-test-results-to-a-file)
113 | for more details on usage of `assertSameAsFile` on which these methods are
114 | based.
115 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "friendsofcake/cakephp-test-utilities",
3 | "description": "Package with support traits to ease unit testing.",
4 | "keywords": ["test", "unit testing", "unittesting", "phpunit"],
5 | "homepage": "https://github.com/friendsofcake/cakephp-test-utilities",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Christian Winther",
10 | "role": "Author"
11 | },
12 | {
13 | "name": "Andy Dawson",
14 | "role": "Author"
15 | },
16 | {
17 | "name": "Frank de Graaf",
18 | "role": "Polisher"
19 | }
20 | ],
21 | "require": {
22 | "cakephp/cakephp": "^5.0"
23 | },
24 | "require-dev": {
25 | "phpunit/phpunit": "^10.1"
26 | },
27 | "autoload": {
28 | "psr-4": {
29 | "FriendsOfCake\\TestUtilities\\": "src",
30 | "FriendsOfCake\\TestUtilities\\Test\\": "tests"
31 | }
32 | },
33 | "config": {
34 | "sort-packages": true,
35 | "allow-plugins": {
36 | "dealerdirect/phpcodesniffer-composer-installer": true
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 7
3 | paths:
4 | - src/
5 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ./tests/
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/AccessibilityHelperTrait.php:
--------------------------------------------------------------------------------
1 | instances used for invocation.
41 | *
42 | * @var array
43 | */
44 | protected array $_reflectionInstanceCache = [];
45 |
46 | /**
47 | * Reset the internal reflection caches.
48 | *
49 | * @return void
50 | */
51 | public function resetReflectionCache(): void
52 | {
53 | $this->_reflectionPropertyCache = [];
54 | $this->_reflectionMethodCache = [];
55 | $this->_reflectionInstanceCache = [];
56 | }
57 |
58 | /**
59 | * Map an instance of an object to its class name.
60 | *
61 | * @param object $instance an instance of a class
62 | * @param string|null $class the key used in the reflection instance class
63 | * @return void
64 | */
65 | public function setReflectionClassInstance(object $instance, ?string $class = null): void
66 | {
67 | $class = $class ?: get_class($instance);
68 | $this->_reflectionInstanceCache[$class] = $instance;
69 | }
70 |
71 | /**
72 | * Get working instance of "$class".
73 | *
74 | * @param string|null $class the class name
75 | * @return object
76 | * @throws \Exception
77 | */
78 | public function getReflectionInstance(?string $class = null): object
79 | {
80 | $class = $this->_getReflectionTargetClass($class);
81 | if (empty($this->_reflectionInstanceCache[$class])) {
82 | throw new Exception(sprintf(
83 | 'Unable to find instance of %s in the reflection cache. '
84 | . 'Have you added it using "setReflectionClassInstance"?',
85 | $class
86 | ));
87 | }
88 |
89 | return $this->_reflectionInstanceCache[$class];
90 | }
91 |
92 | /**
93 | * Helper method to call a protected method.
94 | *
95 | * @param string $method the method name
96 | * @param array $args Argument list to call $method with (call_user_func_array style)
97 | * @param object|string|null $class Target reflection class
98 | * @return mixed
99 | */
100 | public function callProtectedMethod(string $method, array $args = [], object|string|null $class = null): mixed
101 | {
102 | $class = $this->_getReflectionTargetClass($class);
103 | $cacheKey = $class . '_' . $method;
104 |
105 | if (!isset($this->_reflectionMethodCache[$cacheKey])) {
106 | $this->_reflectionMethodCache[$cacheKey] = $this->_getNewReflectionMethod($class, $method);
107 | $this->_reflectionMethodCache[$cacheKey]->setAccessible(true);
108 | }
109 |
110 | return $this->_reflectionMethodCache[$cacheKey]->invokeArgs($this->getReflectionInstance($class), $args);
111 | }
112 |
113 | /**
114 | * Helper method to get the value of a protected property.
115 | *
116 | * @param string $property the property to access/manipulate
117 | * @param string $class Target reflection class
118 | * @return mixed
119 | */
120 | public function getProtectedProperty(string $property, ?string $class = null): mixed
121 | {
122 | $Instance = $this->_getReflectionPropertyInstance($property, $class);
123 |
124 | return $Instance->getValue($this->getReflectionInstance($class));
125 | }
126 |
127 | /**
128 | * Helper method to set the value of a protected property.
129 | *
130 | * @param string $property the property to change
131 | * @param mixed $value the value to set the property to
132 | * @param string $class Target reflection class
133 | * @return void
134 | */
135 | public function setProtectedProperty(string $property, mixed $value, ?string $class = null): void
136 | {
137 | $this->_getReflectionPropertyInstance($property, $class)
138 | ->setValue($this->getReflectionInstance($class), $value);
139 | }
140 |
141 | /**
142 | * Get a reflection property object.
143 | *
144 | * @param string $property the property to access/manipulate
145 | * @param string|null $class the class name
146 | * @return \ReflectionProperty
147 | */
148 | protected function _getReflectionPropertyInstance(string $property, ?string $class = null): ReflectionProperty
149 | {
150 | $class = $this->_getReflectionTargetClass($class);
151 | $cacheKey = $class . '_' . $property;
152 |
153 | if (!isset($this->_reflectionPropertyCache[$cacheKey])) {
154 | $this->_reflectionPropertyCache[$cacheKey] = $this->_getNewReflectionProperty($class, $property);
155 | $this->_reflectionPropertyCache[$cacheKey]->setAccessible(true);
156 | }
157 |
158 | return $this->_reflectionPropertyCache[$cacheKey];
159 | }
160 |
161 | /**
162 | * Get the reflection class name.
163 | *
164 | * @param object|string|null $class the class name
165 | * @return string
166 | * @throws \Exception
167 | */
168 | protected function _getReflectionTargetClass(object|string|null $class = null): string
169 | {
170 | if ($class === null) {
171 | if (!isset($this->defaultReflectionTarget)) {
172 | throw new Exception(
173 | 'Unable to find reflection target. '
174 | . 'Have you set $defaultReflectionTarget or passed in a class name?'
175 | );
176 | }
177 |
178 | $class = $this->defaultReflectionTarget;
179 | }
180 |
181 | if (is_string($class)) {
182 | return $class;
183 | }
184 |
185 | return get_class($class);
186 | }
187 |
188 | /**
189 | * Gets a new ReflectionMethod instance. Extracted for testing purposes.
190 | *
191 | * @param string $class the class name
192 | * @param string $method the method name
193 | * @return \ReflectionMethod
194 | */
195 | protected function _getNewReflectionMethod(string $class, string $method): ReflectionMethod
196 | {
197 | return new ReflectionMethod($class, $method);
198 | }
199 |
200 | /**
201 | * Gets a new ReflectionProperty instance. Extracted for testing purposes.
202 | *
203 | * @param string $class the class name
204 | * @param string $property the property to access/manipulate
205 | * @return \ReflectionProperty
206 | */
207 | protected function _getNewReflectionProperty(string $class, string $property): ReflectionProperty
208 | {
209 | return new ReflectionProperty($class, $property);
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/CompareTrait.php:
--------------------------------------------------------------------------------
1 | indentHtml($result);
32 | $this->assertSameAsFile($path, $indented);
33 | }
34 |
35 | /**
36 | * Assert json is the same as a file
37 | *
38 | * Compares the array representation
39 | *
40 | * @param string $path partial path to test comparison file
41 | * @param mixed $result test result as an array
42 | * @return void
43 | */
44 | public function assertJsonSameAsFile(string $path, mixed $result): void
45 | {
46 | if (!file_exists($path)) {
47 | $path = $this->_compareBasePath . $path;
48 |
49 | $dir = dirname($path);
50 | if (!is_dir($dir)) {
51 | mkdir($dir, 0777, true);
52 | }
53 | }
54 | $this->_updateComparisons ??= getenv('UPDATE_TEST_COMPARISON_FILES') ?: false;
55 | if ($this->_updateComparisons) {
56 | $indented = json_encode(
57 | $result,
58 | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
59 | ) . "\n";
60 | file_put_contents($path, $indented);
61 | }
62 |
63 | $expected = json_decode(file_get_contents($path), true);
64 | $this->assertEquals($expected, $result);
65 | }
66 |
67 | /**
68 | * Asert xml is the same as a comparison file
69 | *
70 | * @param string $path partial path to test comparison file
71 | * @param string $result test result as a string
72 | * @return void
73 | */
74 | public function assertXmlSameAsFile(string $path, string $result): void
75 | {
76 | $indented = $this->indentXml($result);
77 | $this->assertSameAsFile($path, $indented);
78 | }
79 |
80 | /**
81 | * If compare base path has not been set, use the test file as the base
82 | *
83 | * @return void
84 | */
85 | protected function initComparePath(): void
86 | {
87 | if ($this->_compareBasePath) {
88 | return;
89 | }
90 |
91 | $reflector = new ReflectionClass($this);
92 | $this->_compareBasePath = str_replace(
93 | 'TestCase',
94 | 'comparisons',
95 | substr($reflector->getFileName(), 0, -8)
96 | ) . DIRECTORY_SEPARATOR;
97 | }
98 |
99 | /**
100 | * Indent html for consistent whitespace and indentation
101 | *
102 | * Start from everything on one line
103 | * Indent tags
104 | * Indent atttributes one level more than the tag
105 | *
106 | * @param string $html the html string
107 | * @return string
108 | */
109 | protected function indentHtml(string $html): string
110 | {
111 | $html = trim(preg_replace("/\s+/", ' ', $html));
112 |
113 | $counter = 0;
114 | $callback = function ($match) use (&$counter) {
115 | $isTag = $match[1][0] === '<';
116 |
117 | $indent = str_repeat(' ', $counter);
118 |
119 | if ($isTag) {
120 | $match[1] = preg_replace(
121 | '@ ([\w-]+="[^"]*")@',
122 | "\n $indent\\1",
123 | $match[1]
124 | );
125 | $isClosingTag = (bool)$match[2];
126 | $isSelfClosingTag = (bool)$match[3];
127 |
128 | if ($isClosingTag) {
129 | $counter--;
130 | $indent = str_repeat(' ', $counter);
131 | } elseif (!$isSelfClosingTag) {
132 | $counter++;
133 | }
134 | }
135 |
136 | return $indent . rtrim($match[1]) . "\n";
137 | };
138 |
139 | return ltrim(preg_replace_callback('@(<(/?)[^>]+?(/?)>|[^<]+)(?:\s*)@', $callback, $html));
140 | }
141 |
142 | /**
143 | * Use exactly the same routine as for html
144 | *
145 | * However stash the xml header so there isn't an extra level of unwanted
146 | * indentation
147 | *
148 | * @param string $xml the xml string
149 | * @return string
150 | */
151 | protected function indentXml(string $xml): string
152 | {
153 | $header = '';
154 | $headerPos = strpos($xml, '?>');
155 | if ($headerPos) {
156 | $headerPos += 2;
157 | $header = trim(substr($xml, 0, $headerPos)) . "\n";
158 | $xml = trim(substr($xml, $headerPos));
159 | }
160 |
161 | return $header . $this->indentHtml($xml);
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/tests/TestCase/AccessibilityHelperTraitTest.php:
--------------------------------------------------------------------------------
1 | _trait = $this->getMockForTrait(self::TRAIT_NAME);
34 | $this->setReflectionClassInstance($this->_trait);
35 | $this->defaultReflectionTarget = $this->_trait;
36 | }
37 |
38 | /**
39 | * Tests AccessibilityHelperTrait::resetReflectionCache().
40 | */
41 | public function testResetReflectionCache()
42 | {
43 | $this->setProtectedProperty('_reflectionPropertyCache', ['_reflectionPropertyCache']);
44 | $this->setProtectedProperty('_reflectionMethodCache', ['_reflectionMethodCache']);
45 | $this->setProtectedProperty('_reflectionInstanceCache', ['_reflectionInstanceCache']);
46 |
47 | $this->assertNotEmpty($this->getProtectedProperty('_reflectionPropertyCache'));
48 | $this->assertNotEmpty($this->getProtectedProperty('_reflectionMethodCache'));
49 | $this->assertNotEmpty($this->getProtectedProperty('_reflectionInstanceCache'));
50 |
51 | $this->_trait->resetReflectionCache();
52 |
53 | $this->assertEmpty($this->getProtectedProperty('_reflectionPropertyCache'));
54 | $this->assertEmpty($this->getProtectedProperty('_reflectionMethodCache'));
55 | $this->assertEmpty($this->getProtectedProperty('_reflectionInstanceCache'));
56 | }
57 |
58 | /**
59 | * Tests AccessibilityHelperTrait::setReflectionClassInstance().
60 | */
61 | public function testSetReflectionClassInstance()
62 | {
63 | $this->_trait->setReflectionClassInstance($this);
64 | $this->_trait->setReflectionClassInstance($this, 'MyTestInstance');
65 | $this->_trait->setReflectionClassInstance($this->_trait, 'MyTestInstance');
66 |
67 | $expected = [
68 | static::class => $this,
69 | 'MyTestInstance' => $this->_trait,
70 | ];
71 | $actual = $this->getProtectedProperty('_reflectionInstanceCache');
72 | $this->assertSame($expected, $actual);
73 | }
74 |
75 | /**
76 | * Tests AccessibilityHelperTrait::setReflectionClassInstance().
77 | *
78 | * Get existing objects from the cache.
79 | */
80 | public function testGetReflectionInstanceExisting()
81 | {
82 | $this->_trait->setReflectionClassInstance($this, 'MyTestInstance');
83 |
84 | $expected = $this;
85 | $actual = $this->_trait->getReflectionInstance('MyTestInstance');
86 | $this->assertSame($expected, $actual);
87 | }
88 |
89 | /**
90 | * Tests AccessibilityHelperTrait::setReflectionClassInstance().
91 | *
92 | * Get missing objects from the cache.
93 | */
94 | public function testGetReflectionInstanceMissing()
95 | {
96 | $this->expectException(Exception::class);
97 |
98 | $this->_trait->getReflectionInstance('MyTestInstance');
99 | }
100 |
101 | /**
102 | * Tests AccessibilityHelperTrait::callProtectedMethod().
103 | *
104 | * Call a new protected method. One that hasn't been called before.
105 | */
106 | public function testCallProtectedMethodNewInstance()
107 | {
108 | $this->_trait = $this->getMockForTrait(self::TRAIT_NAME, [], '', true, true, true, [
109 | '_getReflectionTargetClass', '_getNewReflectionMethod', 'getReflectionInstance',
110 | ]);
111 | $this->setReflectionClassInstance($this->_trait);
112 | $this->defaultReflectionTarget = $this->_trait;
113 |
114 | $method = $this->getMockBuilder('\ReflectionMethod')
115 | ->disableOriginalConstructor()
116 | ->getMock();
117 |
118 | $this->_trait->expects($this->once())
119 | ->method('_getReflectionTargetClass')
120 | ->with('FOC')
121 | ->will($this->returnValue('FocClass'));
122 |
123 | $this->_trait->expects($this->once())
124 | ->method('_getNewReflectionMethod')
125 | ->with('FocClass', 'getFOC')
126 | ->will($this->returnValue($method));
127 |
128 | $method->expects($this->once())
129 | ->method('setAccessible')
130 | ->with(true);
131 |
132 | $this->_trait->expects($this->once())
133 | ->method('getReflectionInstance')
134 | ->with('FocClass')
135 | ->will($this->returnValue($this->_trait));
136 |
137 | $method->expects($this->once())
138 | ->method('invokeArgs')
139 | ->with($this->_trait, [42, true])
140 | ->will($this->returnValue('FriendsOfCake'));
141 |
142 | $expected = 'FriendsOfCake';
143 | $actual = $this->_trait->callProtectedMethod('getFOC', [42, true], 'FOC');
144 | $this->assertEquals($expected, $actual);
145 |
146 | $expected = ['FocClass_getFOC' => $method];
147 | $actual = $this->getProtectedProperty('_reflectionMethodCache');
148 | $this->assertSame($expected, $actual);
149 | }
150 |
151 | /**
152 | * Tests AccessibilityHelperTrait::callProtectedMethod().
153 | *
154 | * Call an existing protected method. One that has been called before.
155 | */
156 | public function testCallProtectedMethodExistingInstance()
157 | {
158 | $this->_trait = $this->getMockForTrait(self::TRAIT_NAME, [], '', true, true, true, [
159 | '_getReflectionTargetClass', '_getNewReflectionMethod', 'getReflectionInstance',
160 | ]);
161 | $this->setReflectionClassInstance($this->_trait);
162 | $this->defaultReflectionTarget = $this->_trait;
163 |
164 | $method = $this->getMockBuilder('\ReflectionMethod')
165 | ->disableOriginalConstructor()
166 | ->getMock();
167 | $cache = ['FocClass_getFOC' => $method];
168 | $this->setProtectedProperty('_reflectionMethodCache', $cache);
169 |
170 | $this->_trait->expects($this->once())
171 | ->method('_getReflectionTargetClass')
172 | ->with('FOC')
173 | ->will($this->returnValue('FocClass'));
174 |
175 | $this->_trait->expects($this->never())
176 | ->method('_getNewReflectionMethod');
177 |
178 | $method->expects($this->never())
179 | ->method('setAccessible');
180 |
181 | $this->_trait->expects($this->once())
182 | ->method('getReflectionInstance')
183 | ->with('FocClass')
184 | ->will($this->returnValue($this->_trait));
185 |
186 | $method->expects($this->once())
187 | ->method('invokeArgs')
188 | ->with($this->_trait, [42, true])
189 | ->will($this->returnValue('FriendsOfCake'));
190 |
191 | $expected = 'FriendsOfCake';
192 | $actual = $this->_trait->callProtectedMethod('getFOC', [42, true], 'FOC');
193 | $this->assertEquals($expected, $actual);
194 |
195 | $expected = $cache;
196 | $actual = $this->getProtectedProperty('_reflectionMethodCache');
197 | $this->assertSame($expected, $actual);
198 | }
199 |
200 | /**
201 | * Tests AccessibilityHelperTrait::getProtectedProperty().
202 | */
203 | public function testGetProtectedProperty()
204 | {
205 | $this->_trait = $this->getMockForTrait(self::TRAIT_NAME, [], '', true, true, true, [
206 | '_getReflectionPropertyInstance', 'getReflectionInstance',
207 | ]);
208 |
209 | $property = $this->getMockBuilder('\ReflectionProperty')
210 | ->disableOriginalConstructor()
211 | ->getMock();
212 |
213 | $this->_trait->expects($this->once())
214 | ->method('_getReflectionPropertyInstance')
215 | ->with('_myProperty', 'MyClass')
216 | ->will($this->returnValue($property));
217 |
218 | $this->_trait->expects($this->once())
219 | ->method('getReflectionInstance')
220 | ->with('MyClass')
221 | ->will($this->returnValue($this->_trait));
222 |
223 | $property->expects($this->once())
224 | ->method('getValue')
225 | ->with($this->_trait)
226 | ->will($this->returnValue('FriendsOfCake'));
227 |
228 | $expected = 'FriendsOfCake';
229 | $actual = $this->_trait->getProtectedProperty('_myProperty', 'MyClass');
230 | $this->assertEquals($expected, $actual);
231 | }
232 |
233 | /**
234 | * Tests AccessibilityHelperTrait::setProtectedProperty().
235 | */
236 | public function testSetProtectedProperty()
237 | {
238 | $this->_trait = $this->getMockForTrait(self::TRAIT_NAME, [], '', true, true, true, [
239 | '_getReflectionPropertyInstance', 'getReflectionInstance',
240 | ]);
241 |
242 | $property = $this->getMockBuilder('\ReflectionProperty')
243 | ->disableOriginalConstructor()
244 | ->getMock();
245 |
246 | $this->_trait->expects($this->once())
247 | ->method('_getReflectionPropertyInstance')
248 | ->with('_myProperty', 'MyClass')
249 | ->will($this->returnValue($property));
250 |
251 | $this->_trait->expects($this->once())
252 | ->method('getReflectionInstance')
253 | ->with('MyClass')
254 | ->will($this->returnValue($this->_trait));
255 |
256 | $property->expects($this->once())
257 | ->method('setValue')
258 | ->with($this->_trait, 'FriendsOfCake')
259 | ->will($this->returnValue('FriendsOfCake'));
260 |
261 | $this->_trait->setProtectedProperty('_myProperty', 'FriendsOfCake', 'MyClass');
262 | }
263 |
264 | /**
265 | * Tests AccessibilityHelperTrait::_getReflectionPropertyInstance().
266 | *
267 | * Without any previously stored properties.
268 | */
269 | public function testProtectedGetReflectionPropertyInstanceWithoutCache()
270 | {
271 | $this->_trait = $this->getMockForTrait(self::TRAIT_NAME, [], '', true, true, true, [
272 | '_getReflectionTargetClass', '_getNewReflectionProperty',
273 | ]);
274 | $this->setReflectionClassInstance($this->_trait);
275 | $this->defaultReflectionTarget = $this->_trait;
276 |
277 | $property = $this->getMockBuilder('\ReflectionProperty')
278 | ->disableOriginalConstructor()
279 | ->getMock();
280 |
281 | $this->_trait->expects($this->once())
282 | ->method('_getReflectionTargetClass')
283 | ->with('FocClass')
284 | ->will($this->returnValue('FocTargetClass'));
285 |
286 | $this->_trait->expects($this->once())
287 | ->method('_getNewReflectionProperty')
288 | ->with('FocTargetClass', '_focValue')
289 | ->will($this->returnValue($property));
290 |
291 | $property->expects($this->once())
292 | ->method('setAccessible')
293 | ->with(true);
294 |
295 | $expected = $property;
296 | $actual = $this->callProtectedMethod('_getReflectionPropertyInstance', ['_focValue', 'FocClass']);
297 | $this->assertEquals($expected, $actual);
298 |
299 | $expected = ['FocTargetClass__focValue' => $property];
300 | $actual = $this->getProtectedProperty('_reflectionPropertyCache');
301 | $this->assertSame($expected, $actual);
302 | }
303 |
304 | /**
305 | * Tests AccessibilityHelperTrait::_getReflectionPropertyInstance().
306 | *
307 | * With a previously stored property.
308 | */
309 | public function testProtectedGetReflectionPropertyInstanceWithCache()
310 | {
311 | $this->_trait = $this->getMockForTrait(self::TRAIT_NAME, [], '', true, true, true, [
312 | '_getReflectionTargetClass', '_getNewReflectionProperty',
313 | ]);
314 | $this->setReflectionClassInstance($this->_trait);
315 | $this->defaultReflectionTarget = $this->_trait;
316 |
317 | $property = $this->getMockBuilder('\ReflectionProperty')
318 | ->disableOriginalConstructor()
319 | ->getMock();
320 | $cache = ['FocTargetClass__focValue' => $property];
321 |
322 | $this->setProtectedProperty('_reflectionPropertyCache', $cache);
323 |
324 | $this->_trait->expects($this->once())
325 | ->method('_getReflectionTargetClass')
326 | ->with('FocClass')
327 | ->will($this->returnValue('FocTargetClass'));
328 |
329 | $this->_trait->expects($this->never())
330 | ->method('_getNewReflectionProperty');
331 |
332 | $expected = $property;
333 | $actual = $this->callProtectedMethod('_getReflectionPropertyInstance', ['_focValue', 'FocClass']);
334 | $this->assertEquals($expected, $actual);
335 |
336 | $expected = $cache;
337 | $actual = $this->getProtectedProperty('_reflectionPropertyCache');
338 | $this->assertSame($expected, $actual);
339 | }
340 |
341 | /**
342 | * Tests AccessibilityHelperTrait::_getReflectionTargetClass().
343 | *
344 | * With valid values.
345 | */
346 | public function testProtectedGetReflectionTargetClassValidValues()
347 | {
348 | $expected = 'MyClass';
349 | $actual = $this->callProtectedMethod('_getReflectionTargetClass', ['MyClass']);
350 | $this->assertSame($expected, $actual);
351 |
352 | $expected = static::class;
353 | $actual = $this->callProtectedMethod('_getReflectionTargetClass', [$this]);
354 | $this->assertSame($expected, $actual);
355 |
356 | $this->_trait->defaultReflectionTarget = 'MyClass';
357 |
358 | $expected = 'MyClass';
359 | $actual = $this->callProtectedMethod('_getReflectionTargetClass', [null]);
360 | $this->assertSame($expected, $actual);
361 |
362 | $this->_trait->defaultReflectionTarget = $this;
363 |
364 | $expected = static::class;
365 | $actual = $this->callProtectedMethod('_getReflectionTargetClass', [null]);
366 | $this->assertSame($expected, $actual);
367 |
368 | $expected = 'MyClass';
369 | $actual = $this->callProtectedMethod('_getReflectionTargetClass', ['MyClass']);
370 | $this->assertSame($expected, $actual);
371 | }
372 |
373 | /**
374 | * Tests AccessibilityHelperTrait::_getReflectionTargetClass().
375 | *
376 | * With invalid values to trigger the exception.
377 | */
378 | public function testProtectedGetReflectionTargetClassInvalidValues()
379 | {
380 | $this->expectException(Exception::class);
381 |
382 | $this->callProtectedMethod('_getReflectionTargetClass', [null]);
383 | }
384 | }
385 |
--------------------------------------------------------------------------------
/tests/TestCase/CompareTraitTest.php:
--------------------------------------------------------------------------------
1 | initComparePath();
18 | }
19 |
20 | /**
21 | * testAssertHtmlSameAsFile
22 | *
23 | * @dataProvider htmlInputFilesProvider
24 | * @param mixed $name
25 | */
26 | public function testAssertHtmlSameAsFile($name)
27 | {
28 | $input = file_get_contents($name);
29 | $this->assertHtmlSameAsFile(basename($name), $input);
30 | }
31 |
32 | /**
33 | * testAssertJsonSameAsFile
34 | *
35 | * @dataProvider jsonInputFilesProvider
36 | * @param mixed $name
37 | */
38 | public function testAssertJsonSameAsFile($name)
39 | {
40 | $input = json_decode(file_get_contents($name), true);
41 | $this->assertJsonSameAsFile(basename($name), $input);
42 | }
43 |
44 | /**
45 | * testAssertXmlSameAsFile
46 | *
47 | * @dataProvider xmlInputFilesProvider
48 | * @param mixed $name
49 | */
50 | public function testAssertXmlSameAsFile($name)
51 | {
52 | $input = file_get_contents($name);
53 | $this->assertXmlSameAsFile(basename($name), $input);
54 | }
55 |
56 | public static function htmlInputFilesProvider()
57 | {
58 | return self::findFiles('html');
59 | }
60 |
61 | public static function jsonInputFilesProvider()
62 | {
63 | return self::findFiles('json');
64 | }
65 |
66 | public static function xmlInputFilesProvider()
67 | {
68 | return self::findFiles('xml');
69 | }
70 |
71 | protected static function findFiles($format)
72 | {
73 | // phpcs:ignore
74 | $reflector = new ReflectionClass(__CLASS__);
75 | $path = dirname($reflector->getFileName()) . '/' . $format . '/';
76 |
77 | $return = [];
78 | foreach (glob("{$path}*.$format") as $file) {
79 | $return[str_replace($path, '', $file)] = [$file];
80 | }
81 |
82 | return $return;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/tests/TestCase/html/attributes.html:
--------------------------------------------------------------------------------
1 | Stuff
2 |
--------------------------------------------------------------------------------
/tests/TestCase/html/empty.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FriendsOfCake/cakephp-test-utilities/d6f2fd7a3a4b44d6db5e44353142db995c62661d/tests/TestCase/html/empty.html
--------------------------------------------------------------------------------
/tests/TestCase/html/nested.html:
--------------------------------------------------------------------------------
1 | Some indented Stuff
2 |
--------------------------------------------------------------------------------
/tests/TestCase/html/simple.html:
--------------------------------------------------------------------------------
1 | A paragraph.
2 |
--------------------------------------------------------------------------------
/tests/TestCase/json/empty.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FriendsOfCake/cakephp-test-utilities/d6f2fd7a3a4b44d6db5e44353142db995c62661d/tests/TestCase/json/empty.json
--------------------------------------------------------------------------------
/tests/TestCase/json/simple-array.json:
--------------------------------------------------------------------------------
1 | ["one", "two"]
2 |
--------------------------------------------------------------------------------
/tests/TestCase/json/simple-dict.json:
--------------------------------------------------------------------------------
1 | {"one": 1, "two": 2}
2 |
--------------------------------------------------------------------------------
/tests/TestCase/json/simple-int.json:
--------------------------------------------------------------------------------
1 | 1
2 |
--------------------------------------------------------------------------------
/tests/TestCase/xml/empty.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FriendsOfCake/cakephp-test-utilities/d6f2fd7a3a4b44d6db5e44353142db995c62661d/tests/TestCase/xml/empty.xml
--------------------------------------------------------------------------------
/tests/TestCase/xml/simple.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/attributes.html:
--------------------------------------------------------------------------------
1 |
6 | Stuff
7 |
8 |
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/empty.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FriendsOfCake/cakephp-test-utilities/d6f2fd7a3a4b44d6db5e44353142db995c62661d/tests/comparisons/CompareTrait/empty.html
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/empty.json:
--------------------------------------------------------------------------------
1 | null
2 |
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/empty.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FriendsOfCake/cakephp-test-utilities/d6f2fd7a3a4b44d6db5e44353142db995c62661d/tests/comparisons/CompareTrait/empty.xml
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/nested.html:
--------------------------------------------------------------------------------
1 |
2 | Some
3 |
4 | indented
5 |
6 | Stuff
7 |
8 |
9 | -
10 | one
11 |
12 | -
13 | two
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/simple-array.json:
--------------------------------------------------------------------------------
1 | [
2 | "one",
3 | "two"
4 | ]
5 |
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/simple-dict.json:
--------------------------------------------------------------------------------
1 | {
2 | "one": 1,
3 | "two": 2
4 | }
5 |
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/simple-int.json:
--------------------------------------------------------------------------------
1 | 1
2 |
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/simple.html:
--------------------------------------------------------------------------------
1 |
2 | A paragraph.
3 |
4 |
--------------------------------------------------------------------------------
/tests/comparisons/CompareTrait/simple.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------