├── .travis.yml
├── composer.json
├── inc
└── functions.php
├── phpcs.xml.dist
├── phpunit.xml.dist
├── src
├── FunctionExpectations.php
├── Generators.php
├── MonkeyWpUser.php
├── Provider
│ ├── Comment.php
│ ├── Error.php
│ ├── FunctionMockerProvider.php
│ ├── Post.php
│ ├── PostType.php
│ ├── Provider.php
│ ├── Site.php
│ ├── Taxonomy.php
│ ├── Term.php
│ └── User.php
└── Providers.php
└── tests
├── cases
├── functional
│ └── BrainFakerTest.php
└── unit
│ ├── GeneratorsTest.php
│ ├── Provider
│ ├── CommentTest.php
│ ├── ErrorTest.php
│ ├── PostTest.php
│ ├── PostTypeTest.php
│ ├── SiteTest.php
│ ├── TaxonomyTest.php
│ ├── TermTest.php
│ └── UserTest.php
│ ├── ProvidersInitTest.php
│ └── ProvidersTest.php
└── src
├── FunctionalTestCase.php
├── ProviderTestCase.php
└── TestCase.php
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.2
5 | - 7.3
6 | - 7.4
7 |
8 | stages:
9 | - name: analyze
10 | - name: test
11 |
12 | jobs:
13 | fast_finish: true
14 | include:
15 | - stage: analyze
16 | php: 7.4
17 | script:
18 | - composer phpcs
19 | after_success: skip
20 |
21 | before_script:
22 | - travis_retry composer update --no-interaction --prefer-source --classmap-authoritative
23 |
24 | script:
25 | - composer tests:coverage
26 |
27 | after_success:
28 | - bash <(curl -s https://codecov.io/bash)
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "brain/faker",
3 | "description": "Faker (phpfaker/faker) for WordPress via Brain Monkey",
4 | "minimum-stability": "stable",
5 | "license": "MIT",
6 | "keywords": [
7 | "wordpress",
8 | "faker",
9 | "test data",
10 | "unit tests data",
11 | "fake data",
12 | "testing",
13 | "test",
14 | "mockery",
15 | "patchwork",
16 | "mock",
17 | "mock functions",
18 | "runkit",
19 | "redefinition",
20 | "monkey patching",
21 | "interception"
22 | ],
23 | "authors": [
24 | {
25 | "name": "Giuseppe Mazzapica",
26 | "email": "giuseppe.mazzapica@gmail.com",
27 | "homepage": "https://gmazzap.me",
28 | "role": "Developer"
29 | }
30 | ],
31 | "support": {
32 | "issues": "https://github.com/Brain-WP/BrainFaker/issues",
33 | "source": "https://github.com/Brain-WP/BrainFaker"
34 | },
35 | "require": {
36 | "php": ">=7.2",
37 | "brain/monkey": "^2.3.1",
38 | "fakerphp/faker": "^1.20"
39 | },
40 | "require-dev": {
41 | "phpunit/phpunit": "^9.5",
42 | "inpsyde/php-coding-standards": "^1.0"
43 | },
44 | "autoload": {
45 | "files": [
46 | "inc/functions.php"
47 | ],
48 | "psr-4": {
49 | "Brain\\Faker\\": "src/"
50 | }
51 | },
52 | "autoload-dev": {
53 | "psr-4": {
54 | "Brain\\Faker\\Tests\\": [
55 | "tests/src/",
56 | "tests/cases/unit"
57 | ]
58 | }
59 | },
60 | "scripts": {
61 | "tests": "@php ./vendor/phpunit/phpunit/phpunit --no-coverage",
62 | "tests:coverage": "@php ./vendor/phpunit/phpunit/phpunit --coverage-clover=coverage.xml",
63 | "phpcs": [
64 | "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs -p . --ignore=*/vendor/* --extensions=php --basepath=./ --runtime-set testVersion 7.2-",
65 | "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs -p . --standard=PHPCompatibility --ignore=*/vendor/* --extensions=php --basepath=./ --runtime-set testVersion 7.2-"
66 | ]
67 | },
68 | "config": {
69 | "optimize-autoloader": true,
70 | "allow-plugins": {
71 | "dealerdirect/phpcodesniffer-composer-installer": true
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/inc/functions.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ./src
5 | ./tests
6 | ./inc
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | ./src
12 |
13 | ./vendor
14 |
15 |
16 |
17 |
18 |
19 | ./tests/cases/unit
20 |
21 |
22 | ./tests/cases/unit/Provider
23 |
24 |
25 | ./tests/cases/functional
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/FunctionExpectations.php:
--------------------------------------------------------------------------------
1 | functionExpectations[$function] = Functions\expect($function);
31 |
32 | return $this->functionExpectations[$function];
33 | }
34 |
35 | /**
36 | * @param string $function
37 | * @return Expectation
38 | */
39 | public function replace(string $function): Expectation
40 | {
41 | if (isset($this->functionExpectations[$function])) {
42 | /** @var Expectation $expectation */
43 | $expectation = $this->functionExpectations[$function];
44 | /** @noinspection PhpUndefinedMethodInspection */
45 | $expectation->byDefault();
46 |
47 | return $expectation->andAlsoExpectIt();
48 | }
49 |
50 | return Functions\expect($function);
51 | }
52 |
53 | /**
54 | * @return void
55 | */
56 | public function reset(): void
57 | {
58 | foreach ($this->functionExpectations as $expectation) {
59 | /** @noinspection PhpUndefinedMethodInspection */
60 | $expectation->byDefault();
61 | }
62 |
63 | $this->functionExpectations = [];
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Generators.php:
--------------------------------------------------------------------------------
1 | ['post', 'posts'],
25 | Provider\User::class => ['user', 'users'],
26 | Provider\PostType::class => ['postType', 'postTypes'],
27 | Provider\Term::class => ['term', 'terms'],
28 | Provider\Taxonomy::class => ['taxonomy', 'taxonomies'],
29 | Provider\Comment::class => ['comment', 'comments'],
30 | Provider\Site::class => ['site', 'sites'],
31 | Provider\Error::class => ['error', 'errors'],
32 | ];
33 |
34 | /**
35 | * @var array
36 | */
37 | private static $generators = [];
38 |
39 | /**
40 | * @param string $locale
41 | * @return Generator
42 | */
43 | public static function create(string $locale = FakerFactory::DEFAULT_LOCALE): Generator
44 | {
45 | return static::fromGenerator(FakerFactory::create($locale), $locale);
46 | }
47 |
48 | /**
49 | * @param Generator $faker
50 | * @param string $locale
51 | * @return Generator
52 | */
53 | public static function fromGenerator(
54 | Generator $faker,
55 | string $locale = FakerFactory::DEFAULT_LOCALE
56 | ): Generator {
57 |
58 | if (array_key_exists($locale, static::$generators)) {
59 | return static::$generators[$locale][0];
60 | }
61 |
62 | $provider = new Providers($faker);
63 |
64 | foreach (self::PROVIDERS as $className => [$methodOne, $methodMany]) {
65 | $provider->__addProviderClass($className, $methodOne, $methodMany);
66 | }
67 |
68 | $faker->addProvider($provider);
69 |
70 | static::$generators[$locale] = [$faker, $provider];
71 |
72 | return $faker;
73 | }
74 |
75 | /**
76 | * @return void
77 | */
78 | public static function reset(): void
79 | {
80 | /**
81 | * @var Generator $generator
82 | * @var Providers $providers
83 | */
84 | foreach (static::$generators as [$generator, $providers]) {
85 | $generator->unique(true);
86 | $providers->__reset();
87 | }
88 |
89 | static::$generators = [];
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/MonkeyWpUser.php:
--------------------------------------------------------------------------------
1 | 'comment_post_ID',
33 | 'comment_author_ip' => 'comment_author_IP',
34 | ];
35 |
36 | /** @var array $properties */
37 | $properties = array_change_key_case($properties, CASE_LOWER);
38 |
39 | $hasCommentId = array_key_exists('comment_id', $properties);
40 | $id = $hasCommentId || array_key_exists('id', $properties)
41 | ? ($hasCommentId ? $properties['comment_id'] : $properties['id'])
42 | : $this->uniqueGenerator->numberBetween(1, 99999999);
43 |
44 | $date = $this->generator->dateTime('now', $this->generator->timezone);
45 | $gmt = new \DateTimeZone('GMT');
46 |
47 | $type = $this->generator->randomElement(['comment', 'trackback', 'pingback']);
48 |
49 | $defaults = [
50 | 'comment_post_id' => $this->generator->randomNumber(),
51 | 'comment_author' => $this->generator->name,
52 | 'comment_author_email' => $this->generator->email,
53 | 'comment_author_url' => $this->generator->url,
54 | 'comment_author_ip' => $this->generator->ipv4,
55 | 'comment_date' => $date->format('Y-m-d H:i:s'),
56 | 'comment_date_gmt' => $date->setTimezone($gmt)->format('Y-m-d H:i:s'),
57 | 'comment_content' => $this->generator->randomHtml(4, 8),
58 | 'comment_karma' => 0,
59 | 'comment_approved' => $this->generator->randomElement(self::STATUSES),
60 | 'comment_agent' => $this->generator->userAgent,
61 | 'comment_type' => $type,
62 | 'comment_parent' => rand(1, 100) > 75 ? 0 : $this->generator->numberBetween(1, 999999),
63 | 'user_id' => $this->generator->numberBetween(0, 999999),
64 | ];
65 |
66 | $comment = \Mockery::mock(\WP_Comment::class);
67 | $comment->comment_ID = (int)$id;
68 |
69 | $toArray = ['comment_ID' => (int)$id];
70 | foreach ($defaults as $key => $value) {
71 | $hasKey = array_key_exists($key, $properties);
72 | if (!$hasKey && strpos($key, 'comment_') === 0) {
73 | $noPrefixKey = substr($key, 8);
74 | $hasKey = array_key_exists($noPrefixKey, $properties);
75 | $hasKey and $properties[$key] = $properties[$noPrefixKey];
76 | }
77 |
78 | $mappedKey = $keysMap[$key] ?? $key;
79 | $field = $hasKey ? $properties[$key] : $value;
80 | $toArray[$mappedKey] = $field;
81 | $comment->{$mappedKey} = $field;
82 | }
83 |
84 | $comment->shouldReceive('to_array')->andReturn($toArray)->byDefault();
85 |
86 | return $comment;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/Provider/Error.php:
--------------------------------------------------------------------------------
1 | generator->word;
36 | $errors[$code] = [$single];
37 | unset($properties['message'], $properties['error'], $properties['code']);
38 | }
39 |
40 | $error = \Mockery::mock(\WP_Error::class);
41 | $error->errors = $errors;
42 | $error->error_data = $errorData;
43 |
44 | $error->shouldReceive('has_errors')
45 | ->andReturnUsing(
46 | static function () use (&$error) { // phpcs:ignore
47 | return isset($error->errors) && $error->errors;
48 | }
49 | )
50 | ->byDefault();
51 |
52 | $error->shouldReceive('get_error_codes')
53 | ->andReturnUsing(
54 | static function () use (&$error) { // phpcs:ignore
55 | return $error->has_errors() ? array_keys($error->errors) : [];
56 | }
57 | )
58 | ->byDefault();
59 |
60 | $error->shouldReceive('get_error_code')
61 | ->andReturnUsing(
62 | static function () use (&$error) { // phpcs:ignore
63 | return $error->get_error_codes()[0] ?? '';
64 | }
65 | )
66 | ->byDefault();
67 |
68 | $error->shouldReceive('get_error_messages')
69 | ->withNoArgs()
70 | ->andReturnUsing(
71 | static function () use (&$error) { // phpcs:ignore
72 | $allMessages = [];
73 | foreach ($error->errors as $codeMessages) {
74 | $allMessages = array_merge($allMessages, $codeMessages);
75 | }
76 |
77 | return $allMessages;
78 | }
79 | )
80 | ->byDefault();
81 |
82 | $error->shouldReceive('get_error_messages')
83 | ->with(\Mockery::type('scalar'))
84 | ->andReturnUsing(
85 | static function ($code) use (&$error) { // phpcs:ignore
86 | if (!$code) {
87 | return $error->get_error_messages();
88 | }
89 |
90 | return $error->errors[$code] ?? [];
91 | }
92 | )
93 | ->byDefault();
94 |
95 | $error->shouldReceive('get_error_message')
96 | ->withNoArgs()
97 | ->andReturnUsing(
98 | static function () use (&$error) { // phpcs:ignore
99 | return $error->errors[$error->get_error_code()][0] ?? '';
100 | }
101 | )
102 | ->byDefault();
103 |
104 | $error->shouldReceive('get_error_message')
105 | ->with(\Mockery::type('scalar'))
106 | ->andReturnUsing(
107 | static function ($code) use (&$error) { // phpcs:ignore
108 | return $error->errors[$code ?: $error->get_error_code()][0] ?? '';
109 | }
110 | )
111 | ->byDefault();
112 |
113 | $error->shouldReceive('get_error_data')
114 | ->withNoArgs()
115 | ->andReturnUsing(
116 | static function () use (&$error) { // phpcs:ignore
117 | return $error->error_data[$error->get_error_code()] ?? null;
118 | }
119 | )
120 | ->byDefault();
121 |
122 | $error->shouldReceive('get_error_data')
123 | ->with(\Mockery::type('scalar'))
124 | ->andReturnUsing(
125 | static function ($code) use (&$error) { // phpcs:ignore
126 | return $error->error_data[$code ?: $error->get_error_code()] ?? null;
127 | }
128 | )
129 | ->byDefault();
130 |
131 | $error->shouldReceive('add')
132 | ->with(\Mockery::type('scalar'), \Mockery::type('string'))
133 | ->andReturnUsing(
134 | static function ($code, $message) use (&$error) { // phpcs:ignore
135 | array_key_exists($code, $error->errors) or $error->errors[$code] = [];
136 | $error->errors[$code][] = $message;
137 | }
138 | )
139 | ->byDefault();
140 |
141 | $error->shouldReceive('add')
142 | ->with(\Mockery::type('scalar'), \Mockery::type('string'), \Mockery::any())
143 | ->andReturnUsing(
144 | static function ($code, $message, $data) use (&$error) { // phpcs:ignore
145 | array_key_exists($code, $error->errors) or $error->errors[$code] = [];
146 | $error->errors[$code][] = $message;
147 | if (!$data) {
148 | return;
149 | }
150 | array_key_exists($code, $error->error_data) or $error->error_data[$code] = [];
151 | $error->error_data[$code] = $data;
152 | }
153 | )
154 | ->byDefault();
155 |
156 | $error->shouldReceive('add_data')
157 | ->with(\Mockery::any())
158 | ->andReturnUsing(
159 | static function ($data) use (&$error) { // phpcs:ignore
160 | $code = $error->get_error_code();
161 | array_key_exists($code, $error->error_data) or $error->error_data[$code] = [];
162 | $error->error_data[$code] = $data;
163 | }
164 | )
165 | ->byDefault();
166 |
167 | $error->shouldReceive('add_data')
168 | ->with(\Mockery::any(), \Mockery::type('scalar'))
169 | ->andReturnUsing(
170 | static function ($data, $code) use (&$error) { // phpcs:ignore
171 | array_key_exists($code, $error->error_data) or $error->error_data[$code] = [];
172 | $error->error_data[$code] = $data;
173 | }
174 | )
175 | ->byDefault();
176 |
177 | $error->shouldReceive('remove')
178 | ->with(\Mockery::type('scalar'))
179 | ->andReturnUsing(
180 | static function ($code) use (&$error) { // phpcs:ignore
181 | unset($error->errors[$code]);
182 | unset($error->error_data[$code]);
183 | }
184 | )
185 | ->byDefault();
186 |
187 | return $error;
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/src/Provider/FunctionMockerProvider.php:
--------------------------------------------------------------------------------
1 | functionExpectations = $expectations;
37 | }
38 |
39 | /**
40 | * @return void
41 | */
42 | public function reset(): void
43 | {
44 | $this->functionsMocked = false;
45 | parent::reset();
46 | }
47 |
48 | /**
49 | * @return bool
50 | */
51 | public function canMockFunctions(): bool
52 | {
53 | return !$this->functionsMocked;
54 | }
55 |
56 | /**
57 | * @return void
58 | */
59 | public function stopMockingFunctions(): void
60 | {
61 | $this->functionsMocked = true;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Provider/Post.php:
--------------------------------------------------------------------------------
1 | ID === (int)$post->ID;
66 | };
67 | }
68 |
69 | /**
70 | * @return void
71 | */
72 | public function reset(): void
73 | {
74 | $this->posts = [];
75 | parent::reset();
76 | }
77 |
78 | /**
79 | * @param array $properties
80 | * @return \WP_Post
81 | *
82 | * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
83 | */
84 | public function __invoke(array $properties = []): \WP_Post
85 | {
86 | // phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
87 |
88 | $zone = $this->generator->timezone;
89 |
90 | $properties = array_change_key_case($properties, CASE_LOWER);
91 | $properties = $this->setupDateProperties($properties, $zone);
92 |
93 | $id = array_key_exists('id', $properties)
94 | ? $properties['id']
95 | : $this->uniqueGenerator->numberBetween(1, 99999);
96 |
97 | $publish = ($properties['post_status'] ?? null) === 'publish';
98 |
99 | $gmt = new \DateTimeZone('GMT');
100 |
101 | $date = $this->generator->dateTimeThisCentury($publish ? '-1 hour' : '+10 years', $zone);
102 | $dateMod = $this->generator->dateTimeThisCentury('now', $zone);
103 |
104 | $title = $this->generator->sentence($this->generator->numberBetween(1, 5));
105 |
106 | $content = $properties['post_content']
107 | ?? $properties['content']
108 | ?? $this->generateRandomHtml();
109 |
110 | $contentFiltered = $properties['post_content_filtered']
111 | ?? $properties['content_filtered']
112 | ?? trim(strip_tags($content));
113 |
114 | $defaults = [
115 | 'post_author' => (string)$this->generator->numberBetween(1, 99999),
116 | 'post_date' => $date->format('Y-m-d H:i:s'),
117 | 'post_date_gmt' => $date->setTimezone($gmt)->format('Y-m-d H:i:s'),
118 | 'post_title' => $title,
119 | 'post_excerpt' => $this->generator->sentences(3, true),
120 | 'post_status' => '',
121 | 'comment_status' => $this->generator->randomElement(['open', 'closed']),
122 | 'ping_status' => $this->generator->randomElement(['open', 'closed']),
123 | 'post_password' => rand(1, 100) > 80 ? $this->generator->password(4, 8) : '',
124 | 'post_name' => preg_replace('/[^a-z0-9-_]/i', '-', $title),
125 | 'to_ping' => '',
126 | 'pinged' => '',
127 | 'post_modified' => $dateMod->format('Y-m-d H:i:s'),
128 | 'post_modified_gmt' => $dateMod->setTimezone($gmt)->format('Y-m-d H:i:s'),
129 | 'post_parent' => rand(1, 100) > 75 ? $this->generator->numberBetween(1, 99999) : 0,
130 | 'guid' => sprintf('http://%s?p=%d', $this->generator->domainName, $id),
131 | 'menu_order' => $this->generator->numberBetween(0, 100),
132 | 'post_type' => $this->generator->randomElement(['post', 'page']),
133 | 'post_mime_type' => '',
134 | 'comment_count' => '0',
135 | 'filter' => $this->generator->randomElement(['raw', null]),
136 | 'ancestors' => [],
137 | 'page_template' => '',
138 | 'post_category' => [],
139 | 'tags_input' => [],
140 | ];
141 |
142 | $post = \Mockery::mock(\WP_Post::class);
143 | $post->ID = (int)$id;
144 |
145 | $toArray = ['ID' => (int)$id];
146 | foreach ($defaults as $key => $value) {
147 | $hasKey = array_key_exists($key, $properties);
148 | if (!$hasKey && strpos($key, 'post_') === 0) {
149 | $noPrefixKey = substr($key, 5);
150 | $hasKey = array_key_exists($noPrefixKey, $properties);
151 | $hasKey and $properties[$key] = $properties[$noPrefixKey];
152 | }
153 |
154 | $field = $hasKey ? $properties[$key] : $value;
155 | $post->{$key} = $field;
156 | $toArray[$key] = $field;
157 | }
158 |
159 | $post->post_content = $content;
160 | $toArray['post_content'] = $content;
161 | $post->post_content_filtered = $contentFiltered;
162 | $toArray['post_content_filtered'] = $contentFiltered;
163 |
164 | if ($post->post_type === 'attachment') {
165 | $mime = $properties['post_mime_type'] ?? $properties['mime_type'] ?? null;
166 | $mime === null and $mime = $this->generator->randomElement(self::MIME_TYPES);
167 | $post->post_mime_type = $mime;
168 | $toArray['post_mime_type'] = $mime;
169 | }
170 |
171 | if (!$post->post_status) {
172 | $dateGmt = \DateTime::createFromFormat('Y-m-d H:i:s', $post->post_date_gmt, $gmt);
173 | $status = $dateGmt > new \DateTimeImmutable('now', $gmt)
174 | ? 'future'
175 | : $this->generator->randomElement(['publish', 'draft']);
176 | $post->post_status = $status;
177 | $toArray['post_status'] = $status;
178 | }
179 |
180 | $post->shouldReceive('to_array')->andReturn($toArray)->byDefault();
181 |
182 | $this->posts[$post->ID] = $toArray;
183 | $this->mockFunctions();
184 |
185 | return $post;
186 | }
187 |
188 | private function mockFunctions(): void
189 | {
190 | if (!$this->canMockFunctions()) {
191 | return;
192 | }
193 |
194 | $this->functionExpectations->mock('get_post')
195 | ->zeroOrMoreTimes()
196 | ->with(\Mockery::any())
197 | ->andReturnUsing(
198 | function ($post) { // phpcs:ignore
199 | $postId = is_object($post) ? $post->ID : $post;
200 | if (!$postId || !is_numeric($postId)) {
201 | return false;
202 | }
203 |
204 | $data = $this->posts[(int)$postId] ?? null;
205 |
206 | return $data ? $this->__invoke($data) : false;
207 | }
208 | );
209 |
210 | $this->functionExpectations->mock('get_post_field')
211 | ->zeroOrMoreTimes()
212 | ->andReturnUsing(
213 | function ($field = null, $post = null) { // phpcs:ignore
214 | $postId = is_object($post) ? $post->ID : $post;
215 | if (!$postId || !is_numeric($postId) || !is_string($field)) {
216 | return '';
217 | }
218 |
219 | return $this->posts[(int)$postId][$field] ?? '';
220 | }
221 | );
222 |
223 | $this->stopMockingFunctions();
224 | }
225 |
226 | /**
227 | * @param array $properties
228 | * @param string $randomZone
229 | * @return array
230 | * @throws \Exception
231 | */
232 | private function setupDateProperties(array $properties, string $randomZone): array
233 | {
234 | $dateKeys = [
235 | 'date' => [false, 'date_gmt'],
236 | 'date_gmt' => [true, 'date'],
237 | 'modified' => [false, 'modified_gmt'],
238 | 'modified_gmt' => [true, 'modified'],
239 | ];
240 |
241 | $original = $properties;
242 | foreach ($dateKeys as $key => [$isGmt, $altKey]) {
243 | $hasDateKey = array_key_exists("post_{$key}", $original);
244 | if (!$hasDateKey && !array_key_exists($key, $original)) {
245 | continue;
246 | }
247 |
248 | $dateRaw = $hasDateKey ? $original["post_{$key}"] : $original[$key];
249 | $date = $this->formatDate($dateRaw, $isGmt ? 'GMT' : $randomZone);
250 |
251 | $properties["post_{$key}"] = $date;
252 |
253 | if (!$hasDateKey) {
254 | unset($properties[$key]);
255 | }
256 |
257 | $hasAltDateKey = array_key_exists("post_{$altKey}", $original);
258 | if ($hasAltDateKey || array_key_exists($altKey, $original)) {
259 | continue;
260 | }
261 |
262 | $targetZone = $isGmt ? new \DateTimeZone($randomZone) : new \DateTimeZone('GMT');
263 |
264 | $altDate = \DateTime::createFromFormat(self::DATE_FORMAT, $date)
265 | ->setTimezone($targetZone)
266 | ->format(self::DATE_FORMAT);
267 |
268 | $properties["post_{$altKey}"] = $altDate;
269 |
270 | if (!$hasAltDateKey) {
271 | unset($properties[$key]);
272 | }
273 | }
274 |
275 | return $properties;
276 | }
277 |
278 | /**
279 | * @param $date
280 | * @param string|null $zone
281 | * @return string
282 | *
283 | * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration
284 | */
285 | private function formatDate($date, ?string $zone = null): string
286 | {
287 | // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration
288 |
289 | if ($date instanceof \DateTimeInterface) {
290 | return $date->format(self::DATE_FORMAT);
291 | }
292 |
293 | if (is_int($date)) {
294 | return (new \DateTime('now', new \DateTimeZone($zone ?? 'UTC')))
295 | ->setTimestamp($date)
296 | ->format(self::DATE_FORMAT);
297 | }
298 |
299 | if (!is_string($date) || strtolower($date) === 'now') {
300 | return (new \DateTime('now', new \DateTimeZone($zone ?? 'UTC')))
301 | ->format(self::DATE_FORMAT);
302 | }
303 |
304 | if (preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/', $date)) {
305 | return $date;
306 | }
307 |
308 | return $this->formatDate((int)(strtotime($date) ?: (int)time()), $zone);
309 | }
310 |
311 | /**
312 | * Faker randomHtml is slow for long text and it generates full-page HTML, not fragment like
313 | * post content is.
314 | *
315 | * @return string
316 | */
317 | private function generateRandomHtml(): string
318 | {
319 | $output = '';
320 | $max = $this->generator->numberBetween(0, 50);
321 | if (!$max) {
322 | return '';
323 | }
324 |
325 | $listItems = $this->generator->numberBetween(0, 10);
326 | $list = '';
327 | if ($listItems) {
328 | $listTag = $this->generator->randomElement(['ul', 'ol']);
329 | $list .= "<{$listTag}>";
330 | for ($listI = 0; $listI < $listItems; $listI++) {
331 | $list .= "\n";
332 | $list .= $this->generator->sentence($this->generator->numberBetween(1, 3));
333 | $list .= "";
334 | }
335 | $list .= "\n{$listTag}>";
336 | }
337 |
338 | for ($i = 0; $i < $max; $i++) {
339 | $tag = $this->generator->randomElement(['p', 'div']);
340 | $output .= "\n<{$tag}>\n";
341 | $image = $this->generator->randomElement([true, false]);
342 | if ($image) {
343 | $output .= sprintf(
344 | "
\n",
345 | $this->generator->sentence(1, 3),
346 | $this->generator->imageUrl()
347 | );
348 | }
349 | $output .= $this->generator->sentences($this->generator->numberBetween(1, 5), true);
350 | $output .= "\n";
351 | $output .= $tag === 'div' ? "{$list}\n{$tag}>" : "{$tag}>\n{$list}";
352 | }
353 |
354 | return trim($output);
355 | }
356 | }
357 |
--------------------------------------------------------------------------------
/src/Provider/Provider.php:
--------------------------------------------------------------------------------
1 | generator = $generator;
35 | $this->uniqueGenerator = $generator->unique(true);
36 | }
37 |
38 | /**
39 | * @return void
40 | */
41 | final public function resetUnique(): void
42 | {
43 | $this->uniqueGenerator = $this->generator->unique(true);
44 | }
45 |
46 | /**
47 | * @return void
48 | */
49 | public function reset(): void
50 | {
51 | $this->resetUnique();
52 | }
53 |
54 | /**
55 | * @param array $args
56 | * @return object
57 | */
58 | abstract public function __invoke(array $args = []);
59 | }
60 |
--------------------------------------------------------------------------------
/src/Provider/Site.php:
--------------------------------------------------------------------------------
1 | term_id === (int)$site->term_id;
29 | };
30 | }
31 |
32 | /**
33 | * @return void
34 | */
35 | public function reset(): void
36 | {
37 | $this->sites = [];
38 | parent::reset();
39 | }
40 |
41 | /**
42 | * @param array $properties
43 | * @return \WP_Site
44 | *
45 | * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
46 | */
47 | public function __invoke(array $properties = []): \WP_Site
48 | {
49 | // phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
50 |
51 | if (function_exists('is_multisite') && !is_multisite()) {
52 | throw new \Error('WP_Site class is only available in multisite installations.');
53 | }
54 |
55 | $hasBlogId = array_key_exists('blog_id', $properties);
56 | $id = $hasBlogId || array_key_exists('id', $properties)
57 | ? ($hasBlogId ? $properties['blog_id'] : $properties['id'])
58 | : $this->uniqueGenerator->numberBetween(1, 99999999);
59 |
60 | $siteId = $properties['site_id']
61 | ?? $properties['network_id']
62 | ?? (rand(1, 100) > 90 ? $this->generator->numberBetween(2, 5) : 1);
63 |
64 | $url = $properties['site_url']
65 | ?? $properties['home']
66 | ?? $properties['url']
67 | ?? null;
68 |
69 | if ($url) {
70 | parse_url($url, PHP_URL_SCHEME) or $url = "http://{$url}";
71 | if (!array_key_exists('path', $properties)) {
72 | $path = parse_url($url, PHP_URL_PATH);
73 | $path and $properties['path'] = '/' . trim($path, '/');
74 | }
75 | }
76 |
77 | $defaults = [
78 | 'domain' => $this->generator->domainName,
79 | 'path' => rand(1, 100) > 50 ? $this->generator->domainWord : '',
80 | 'registered' => $this->generator->dateTimeThisDecade->format('Y-m-d H:i:s'),
81 | 'last_updated' => $this->generator->dateTimeThisMonth->format('Y-m-d H:i:s'),
82 | 'public' => rand(1, 100) > 80 ? '0' : '1',
83 | 'archived' => rand(1, 100) > 80 ? '1' : '0',
84 | 'mature' => rand(1, 100) > 80 ? '1' : '0',
85 | 'spam' => rand(1, 100) > 80 ? '1' : '0',
86 | 'deleted' => rand(1, 100) > 80 ? '1' : '0',
87 | 'lang_id' => rand(1, 100) > 80 ? '1' : '0',
88 | ];
89 |
90 | $site = \Mockery::mock(\WP_Site::class);
91 | $site->blog_id = (string)((int)$id);
92 | $site->site_id = (string)((int)$siteId);
93 | $site->id = $site->blog_id;
94 | $site->network_id = $site->site_id;
95 |
96 | $toArray = ['blog_id' => $site->blog_id, 'site_id' => $site->site_id];
97 | foreach ($defaults as $key => $value) {
98 | $field = array_key_exists($key, $properties) ? $properties[$key] : $value;
99 | is_numeric($field) and $field = (string)((int)$field);
100 | $toArray[$key] = $field;
101 | $site->{$key} = $field;
102 | }
103 |
104 | $details = [
105 | 'blogname' => $this->generator->sentence,
106 | 'siteurl' => $url ?? "http://{$this->generator->domainName}/{$site->path}",
107 | 'home' => $url ?? "http://{$this->generator->domainName}/{$site->path}",
108 | 'post_count' => $this->generator->numberBetween(0, 9999),
109 | ];
110 |
111 | $data = $toArray;
112 |
113 | foreach ($details as $key => $value) {
114 | $field = array_key_exists($key, $properties) ? $properties[$key] : $value;
115 | $site->{$key} = $field;
116 | $data[$key] = $field;
117 | }
118 |
119 | $site->shouldReceive('to_array')->andReturn($toArray)->byDefault();
120 | $this->sites[$site->blog_id] = $data;
121 | $this->mockFunctions();
122 |
123 | return $site;
124 | }
125 |
126 | /**
127 | * @return void
128 | */
129 | private function mockFunctions(): void
130 | {
131 | if (!$this->canMockFunctions()) {
132 | return;
133 | }
134 |
135 | $this->functionExpectations->mock('get_site')
136 | ->zeroOrMoreTimes()
137 | ->andReturnUsing(
138 | function ($site = null) { // phpcs:ignore
139 | $siteId = is_object($site) ? ($site->blog_id ?? null) : $site;
140 |
141 | return $siteId && is_numeric($siteId) && isset($this->sites[(int)$siteId])
142 | ? $this->__invoke($this->sites[(int)$siteId])
143 | : null;
144 | }
145 | );
146 |
147 | $this->stopMockingFunctions();
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/Provider/Taxonomy.php:
--------------------------------------------------------------------------------
1 | [
18 | 'name' => 'category',
19 | 'label' => 'Categories',
20 | 'labels' => [
21 | 'name' => 'Categories',
22 | 'singular_name' => 'Category',
23 | 'search_items' => 'Search Categories',
24 | 'popular_items' => null,
25 | 'all_items' => 'All Categories',
26 | 'parent_item' => 'Parent Category',
27 | 'parent_item_colon' => 'Parent Category:',
28 | 'edit_item' => 'Edit Category',
29 | 'view_item' => 'View Category',
30 | 'update_item' => 'Update Category',
31 | 'add_new_item' => 'Add New Category',
32 | 'new_item_name' => 'New Category Name',
33 | 'separate_items_with_commas' => null,
34 | 'add_or_remove_items' => null,
35 | 'choose_from_most_used' => null,
36 | 'not_found' => 'No categories found.',
37 | 'no_terms' => 'No categories',
38 | 'items_list_navigation' => 'Categories list navigation',
39 | 'items_list' => 'Categories list',
40 | 'most_used' => 'Most Used',
41 | 'back_to_items' => '← Back to Categories',
42 | 'menu_name' => 'Categories',
43 | 'name_admin_bar' => 'category',
44 | ],
45 | 'description' => '',
46 | 'public' => true,
47 | 'publicly_queryable' => true,
48 | 'hierarchical' => true,
49 | 'show_ui' => true,
50 | 'show_in_menu' => true,
51 | 'show_in_nav_menus' => true,
52 | 'show_tagcloud' => true,
53 | 'show_in_quick_edit' => true,
54 | 'show_admin_column' => true,
55 | 'meta_box_cb' => 'post_categories_meta_box',
56 | 'meta_box_sanitize_cb' => 'taxonomy_meta_box_sanitize_cb_checkboxes',
57 | 'object_type' => ['post'],
58 | 'cap' => [
59 | 'manage_terms' => 'manage_categories',
60 | 'edit_terms' => 'edit_categories',
61 | 'delete_terms' => 'delete_categories',
62 | 'assign_terms' => 'assign_categories',
63 | ],
64 | 'rewrite' => [
65 | 'with_front' => true,
66 | 'hierarchical' => true,
67 | 'ep_mask' => 512,
68 | 'slug' => 'category',
69 | ],
70 | 'query_var' => 'category_name',
71 | 'update_count_callback' => '',
72 | 'show_in_rest' => true,
73 | 'rest_base' => 'categories',
74 | 'rest_controller_class' => 'WP_REST_Terms_Controller',
75 | '_builtin' => true,
76 | ],
77 | 'post_tag' => [
78 | 'name' => 'post_tag',
79 | 'label' => 'Tags',
80 | 'labels' => [
81 | 'name' => 'Tags',
82 | 'singular_name' => 'Tag',
83 | 'search_items' => 'Search Tags',
84 | 'popular_items' => 'Popular Tags',
85 | 'all_items' => 'All Tags',
86 | 'parent_item' => null,
87 | 'parent_item_colon' => null,
88 | 'edit_item' => 'Edit Tag',
89 | 'view_item' => 'View Tag',
90 | 'update_item' => 'Update Tag',
91 | 'add_new_item' => 'Add New Tag',
92 | 'new_item_name' => 'New Tag Name',
93 | 'separate_items_with_commas' => 'Separate tags with commas',
94 | 'add_or_remove_items' => 'Add or remove tags',
95 | 'choose_from_most_used' => 'Choose from the most used tags',
96 | 'not_found' => 'No tags found.',
97 | 'no_terms' => 'No tags',
98 | 'items_list_navigation' => 'Tags list navigation',
99 | 'items_list' => 'Tags list',
100 | 'most_used' => 'Most Used',
101 | 'back_to_items' => '← Back to Tags',
102 | 'menu_name' => 'Tags',
103 | 'name_admin_bar' => 'post_tag',
104 | ],
105 | 'description' => '',
106 | 'public' => true,
107 | 'publicly_queryable' => true,
108 | 'hierarchical' => false,
109 | 'show_ui' => true,
110 | 'show_in_menu' => true,
111 | 'show_in_nav_menus' => true,
112 | 'show_tagcloud' => true,
113 | 'show_in_quick_edit' => true,
114 | 'show_admin_column' => true,
115 | 'meta_box_cb' => 'post_tags_meta_box',
116 | 'meta_box_sanitize_cb' => 'taxonomy_meta_box_sanitize_cb_input',
117 | 'object_type' => ['post'],
118 | 'cap' => [
119 | 'manage_terms' => 'manage_post_tags',
120 | 'edit_terms' => 'edit_post_tags',
121 | 'delete_terms' => 'delete_post_tags',
122 | 'assign_terms' => 'assign_post_tags',
123 | ],
124 | 'rewrite' => [
125 | 'with_front' => true,
126 | 'hierarchical' => false,
127 | 'ep_mask' => 1024,
128 | 'slug' => 'tag',
129 | ],
130 | 'query_var' => 'tag',
131 | 'update_count_callback' => '',
132 | 'show_in_rest' => true,
133 | 'rest_base' => 'tags',
134 | 'rest_controller_class' => 'WP_REST_Terms_Controller',
135 | '_builtin' => true,
136 | ],
137 | 'nav_menu' => [
138 | 'name' => 'nav_menu',
139 | 'label' => 'Navigation Menus',
140 | 'labels' => [
141 | 'name' => 'Navigation Menus',
142 | 'singular_name' => 'Navigation Menu',
143 | 'search_items' => 'Search Tags',
144 | 'popular_items' => 'Popular Tags',
145 | 'all_items' => 'Navigation Menus',
146 | 'parent_item' => null,
147 | 'parent_item_colon' => null,
148 | 'edit_item' => 'Edit Tag',
149 | 'view_item' => 'View Tag',
150 | 'update_item' => 'Update Tag',
151 | 'add_new_item' => 'Add New Tag',
152 | 'new_item_name' => 'New Tag Name',
153 | 'separate_items_with_commas' => 'Separate tags with commas',
154 | 'add_or_remove_items' => 'Add or remove tags',
155 | 'choose_from_most_used' => 'Choose from the most used tags',
156 | 'not_found' => 'No tags found.',
157 | 'no_terms' => 'No tags',
158 | 'items_list_navigation' => 'Tags list navigation',
159 | 'items_list' => 'Tags list',
160 | 'most_used' => 'Most Used',
161 | 'back_to_items' => '← Back to Tags',
162 | 'menu_name' => 'Navigation Menus',
163 | 'name_admin_bar' => 'Navigation Menu',
164 | 'archives' => 'Navigation Menus',
165 | ],
166 | 'description' => '',
167 | 'public' => false,
168 | 'publicly_queryable' => false,
169 | 'hierarchical' => false,
170 | 'show_ui' => false,
171 | 'show_in_menu' => false,
172 | 'show_in_nav_menus' => false,
173 | 'show_tagcloud' => false,
174 | 'show_in_quick_edit' => false,
175 | 'show_admin_column' => false,
176 | 'meta_box_cb' => 'post_tags_meta_box',
177 | 'meta_box_sanitize_cb' => 'taxonomy_meta_box_sanitize_cb_input',
178 | 'object_type' => ['nav_menu_item'],
179 | 'cap' => [
180 | 'manage_terms' => 'manage_categories',
181 | 'edit_terms' => 'manage_categories',
182 | 'delete_terms' => 'manage_categories',
183 | 'assign_terms' => 'edit_posts',
184 | ],
185 | 'rewrite' => false,
186 | 'query_var' => false,
187 | 'update_count_callback' => '',
188 | 'show_in_rest' => false,
189 | 'rest_base' => false,
190 | 'rest_controller_class' => false,
191 | '_builtin' => true,
192 | ],
193 | 'link_category' => [
194 | 'name' => 'link_category',
195 | 'label' => 'Link Categories',
196 | 'labels' => [
197 | 'name' => 'Link Categories',
198 | 'singular_name' => 'Link Category',
199 | 'search_items' => 'Search Link Categories',
200 | 'popular_items' => null,
201 | 'all_items' => 'All Link Categories',
202 | 'parent_item' => null,
203 | 'parent_item_colon' => null,
204 | 'edit_item' => 'Edit Link Category',
205 | 'view_item' => 'View Tag',
206 | 'update_item' => 'Update Link Category',
207 | 'add_new_item' => 'Add New Link Category',
208 | 'new_item_name' => 'New Link Category Name',
209 | 'separate_items_with_commas' => null,
210 | 'add_or_remove_items' => null,
211 | 'choose_from_most_used' => null,
212 | 'not_found' => 'No tags found.',
213 | 'no_terms' => 'No tags',
214 | 'items_list_navigation' => 'Tags list navigation',
215 | 'items_list' => 'Tags list',
216 | 'most_used' => 'Most Used',
217 | 'back_to_items' => '← Back to Link Categories',
218 | 'menu_name' => 'Link Categories',
219 | 'name_admin_bar' => 'Link Category',
220 | 'archives' => 'All Link Categories',
221 | ],
222 | 'description' => '',
223 | 'public' => false,
224 | 'publicly_queryable' => false,
225 | 'hierarchical' => false,
226 | 'show_ui' => true,
227 | 'show_in_menu' => true,
228 | 'show_in_nav_menus' => false,
229 | 'show_tagcloud' => true,
230 | 'show_in_quick_edit' => true,
231 | 'show_admin_column' => false,
232 | 'meta_box_cb' => 'post_tags_meta_box',
233 | 'meta_box_sanitize_cb' => 'taxonomy_meta_box_sanitize_cb_input',
234 | 'object_type' => ['link'],
235 | 'cap' => [
236 | 'manage_terms' => 'manage_links',
237 | 'edit_terms' => 'manage_links',
238 | 'delete_terms' => 'manage_links',
239 | 'assign_terms' => 'manage_links',
240 | ],
241 | 'rewrite' => false,
242 | 'query_var' => false,
243 | 'update_count_callback' => '',
244 | 'show_in_rest' => false,
245 | 'rest_base' => false,
246 | 'rest_controller_class' => false,
247 | '_builtin' => true,
248 | ],
249 | 'post_format' => [
250 | 'name' => 'post_format',
251 | 'label' => 'Formats',
252 | 'labels' => [
253 | 'name' => 'Formats',
254 | 'singular_name' => 'Format',
255 | 'search_items' => 'Search Tags',
256 | 'popular_items' => 'Popular Tags',
257 | 'all_items' => 'Formats',
258 | 'parent_item' => null,
259 | 'parent_item_colon' => null,
260 | 'edit_item' => 'Edit Tag',
261 | 'view_item' => 'View Tag',
262 | 'update_item' => 'Update Tag',
263 | 'add_new_item' => 'Add New Tag',
264 | 'new_item_name' => 'New Tag Name',
265 | 'separate_items_with_commas' => 'Separate tags with commas',
266 | 'add_or_remove_items' => 'Add or remove tags',
267 | 'choose_from_most_used' => 'Choose from the most used tags',
268 | 'not_found' => 'No tags found.',
269 | 'no_terms' => 'No tags',
270 | 'items_list_navigation' => 'Tags list navigation',
271 | 'items_list' => 'Tags list',
272 | 'most_used' => 'Most Used',
273 | 'back_to_items' => '← Back to Tags',
274 | 'menu_name' => 'Formats',
275 | 'name_admin_bar' => 'Format',
276 | 'archives' => 'Formats',
277 | ],
278 | 'description' => '',
279 | 'public' => true,
280 | 'publicly_queryable' => true,
281 | 'hierarchical' => false,
282 | 'show_ui' => false,
283 | 'show_in_menu' => false,
284 | 'show_in_nav_menus' => false,
285 | 'show_tagcloud' => false,
286 | 'show_in_quick_edit' => false,
287 | 'show_admin_column' => false,
288 | 'meta_box_cb' => 'post_tags_meta_box',
289 | 'meta_box_sanitize_cb' => 'taxonomy_meta_box_sanitize_cb_input',
290 | 'object_type' => ['post'],
291 | 'cap' => [
292 | 'manage_terms' => 'manage_categories',
293 | 'edit_terms' => 'manage_categories',
294 | 'delete_terms' => 'manage_categories',
295 | 'assign_terms' => 'edit_posts',
296 | ],
297 | 'rewrite' => [
298 | 'with_front' => true,
299 | 'hierarchical' => false,
300 | 'ep_mask' => 0,
301 | 'slug' => 'type',
302 | ],
303 | 'query_var' => 'post_format',
304 | 'update_count_callback' => '',
305 | 'show_in_rest' => false,
306 | 'rest_base' => false,
307 | 'rest_controller_class' => false,
308 | '_builtin' => true,
309 | ],
310 | ];
311 |
312 | /**
313 | * @var array[]
314 | */
315 | private $taxonomies = [];
316 |
317 | /**
318 | * @return void
319 | */
320 | public function reset(): void
321 | {
322 | $this->taxonomies = [];
323 | parent::reset();
324 | }
325 |
326 | /**
327 | * @param array $properties
328 | * @return \WP_Taxonomy|\Mockery\MockInterface
329 | */
330 | public function __invoke(array $properties = []): \WP_Taxonomy
331 | {
332 | $properties = array_change_key_case($properties, CASE_LOWER);
333 | $customName = array_key_exists('name', $properties) ? $properties['name'] : null;
334 | $name = $customName;
335 |
336 | if ($name === null) {
337 | $buildInKeys = array_keys(self::BUILT_IN);
338 | $notDoneBuildIn = array_diff($buildInKeys, array_keys($this->taxonomies));
339 | $name = $this->generator->randomElement($notDoneBuildIn ?: $buildInKeys);
340 | }
341 |
342 | $public = array_key_exists('public', $properties)
343 | ? (bool)filter_var($properties['public'], FILTER_VALIDATE_BOOLEAN)
344 | : null;
345 |
346 | /** @var string $name */
347 |
348 | $loadedProperties = $this->maybeLoadProperties($name, $properties);
349 | if (is_array($loadedProperties)) {
350 | return $this->createTaxonomy($loadedProperties, [], $name);
351 | }
352 |
353 | $builtIn = array_key_exists($name, self::BUILT_IN);
354 | $baseName = $builtIn ? $name : array_rand(self::BUILT_IN);
355 |
356 | if (!$builtIn && ($customName || (is_bool($public) && $public))) {
357 | $hierarchical = !empty($properties['hierarchical']);
358 | $baseName = $hierarchical ? 'category' : 'post_tag';
359 | }
360 |
361 | $defaults = $builtIn ? self::BUILT_IN[$name] : self::BUILT_IN[$baseName];
362 | $properties['_builtin'] = $builtIn;
363 |
364 | $taxonomy = $this->createTaxonomy($defaults, $properties, $name, $public);
365 | $this->mockFunctions();
366 |
367 | return $taxonomy;
368 | }
369 |
370 | /**
371 | * @param string $name
372 | * @param array $properties
373 | * @return array|null
374 | */
375 | private function maybeLoadProperties(string $name, array $properties): ?array
376 | {
377 | if (!isset($this->taxonomies[$name])) {
378 | return null;
379 | }
380 |
381 | $diffKeys = ['labels' => '', 'cap' => '', 'rewrite' => '', 'name' => ''];
382 |
383 | $savedProperties = $this->taxonomies[$name];
384 | $savedScalars = array_diff_key($savedProperties, $diffKeys);
385 | $savedLabels = $savedProperties['labels'] ?? [];
386 | $savedCaps = $savedProperties['cap'] ?? [];
387 | $savedRewrite = $savedProperties['rewrite'] ?? false;
388 | $savedRewrite and $savedRewrite = (array)$savedRewrite;
389 |
390 | $newScalars = $properties ? array_diff_key($properties, $diffKeys) : [];
391 | $newLabels = (array)($properties['labels'] ?? []);
392 | $newCaps = (array)($properties['cap'] ?? []);
393 | $newRewrite = $properties['rewrite'] ?? false;
394 | $newRewrite and $newRewrite = (array)$newRewrite;
395 |
396 | $savedScalars and ksort($savedScalars);
397 | $savedLabels and ksort($savedLabels);
398 | $savedCaps and ksort($savedCaps);
399 | $savedRewrite and ksort($savedRewrite);
400 |
401 | $newScalars and ksort($newScalars);
402 | $newLabels and ksort($newLabels);
403 | $newCaps and ksort($newCaps);
404 | $newRewrite and ksort($newRewrite);
405 |
406 | if (($newScalars && $newScalars !== $savedScalars)
407 | || ($newLabels && $newLabels !== $savedLabels)
408 | || ($newCaps && $newCaps !== $savedCaps)
409 | || ($newRewrite && $newRewrite !== $savedRewrite)
410 | ) {
411 | throw new \Error("Taxonomy {$name} was already faked with different properties.");
412 | }
413 |
414 | return $savedProperties;
415 | }
416 |
417 | /**
418 | * @param array $defaults
419 | * @param array $properties
420 | * @param string $name
421 | * @param bool|null $public
422 | * @return \WP_Taxonomy
423 | */
424 | private function createTaxonomy(
425 | array $defaults,
426 | array $properties,
427 | string $name,
428 | ?bool $public = null
429 | ): \WP_Taxonomy {
430 |
431 | $showUi = $properties['show_ui'] ?? $public;
432 |
433 | $publicKeys = [
434 | 'publicly_queryable',
435 | 'show_in_rest',
436 | ];
437 |
438 | $uiKeys = [
439 | 'show_ui',
440 | 'show_in_menu',
441 | 'show_in_nav_menus',
442 | 'show_tagcloud',
443 | 'show_in_quick_edit',
444 | 'show_in_rest',
445 | ];
446 |
447 | $reloading = isset($this->taxonomies[$name]);
448 | $data = [];
449 |
450 | $taxonomy = \Mockery::mock(\WP_Taxonomy::class);
451 |
452 | foreach ($defaults as $key => $value) {
453 | $custom = array_key_exists($key, $properties);
454 | $field = $custom ? $properties[$key] : $value;
455 | if (!$custom && is_bool($public) && in_array($key, $publicKeys, true)) {
456 | $field = $public;
457 | }
458 |
459 | if (!$custom && is_bool($showUi) && in_array($key, $uiKeys, true)) {
460 | $field = $showUi;
461 | }
462 |
463 | if (!in_array($key, ['labels', 'cap'], true)) {
464 | $taxonomy->{$key} = $field;
465 | $reloading or $data[$key] = $field;
466 | }
467 | }
468 |
469 | $labels = (array)($properties['labels'] ?? $defaults['labels'] ?? []);
470 | $caps = (array)($properties['cap'] ?? $defaults['cap'] ?? []);
471 | $buildIn = array_key_exists($name, self::BUILT_IN);
472 |
473 | $baseType = $taxonomy->hierarchical ? 'category' : 'post_tag';
474 | $baseData = $buildIn ? self::BUILT_IN[$name] : self::BUILT_IN[$baseType];
475 |
476 | $data['labels'] = array_merge($baseData['labels'], $labels);
477 | $taxonomy->labels = (object)$data['labels'];
478 |
479 | $data['cap'] = array_merge($baseData['cap'], $caps);
480 | $taxonomy->cap = (object)$data['cap'];
481 |
482 | if (empty($properties['label']) && !empty($properties['labels']['name'])) {
483 | $taxonomy->label = $taxonomy->labels->name;
484 | $reloading or $data['label'] = $taxonomy->labels->name;
485 | }
486 |
487 | if (empty($properties['labels']['name']) && !empty($properties['label'])) {
488 | $taxonomy->labels->name = $taxonomy->label;
489 | $reloading or $data['labels']['name'] = $taxonomy->label;
490 | }
491 |
492 | $reloading or $this->taxonomies[$name] = $data;
493 |
494 | return $taxonomy;
495 | }
496 |
497 | /**
498 | * @return void
499 | */
500 | private function mockFunctions(): void
501 | {
502 | if (!$this->canMockFunctions()) {
503 | return;
504 | }
505 |
506 | $this->functionExpectations->mock('get_taxonomy')
507 | ->zeroOrMoreTimes()
508 | ->andReturnUsing(
509 | function ($name) { // phpcs:ignore
510 | if (!is_scalar($name) || !isset($this->taxonomies[$name])) {
511 | return null;
512 | }
513 |
514 | return $this->__invoke($this->taxonomies[$name]);
515 | }
516 | );
517 |
518 | $this->functionExpectations->mock('taxonomy_exists')
519 | ->zeroOrMoreTimes()
520 | ->zeroOrMoreTimes()
521 | ->andReturnUsing(
522 | function ($name) { // phpcs:ignore
523 | return is_scalar($name) && array_key_exists($name, $this->taxonomies);
524 | }
525 | );
526 |
527 | $this->stopMockingFunctions();
528 | }
529 | }
530 |
--------------------------------------------------------------------------------
/src/Provider/Term.php:
--------------------------------------------------------------------------------
1 | term_id === (int)$term->term_id;
29 | };
30 | }
31 |
32 | /**
33 | * @return void
34 | */
35 | public function reset(): void
36 | {
37 | $this->terms = [];
38 | parent::reset();
39 | }
40 |
41 | /**
42 | * @param array $properties
43 | * @return \WP_Term
44 | */
45 | public function __invoke(array $properties = []): \WP_Term
46 | {
47 | $id = $properties['term_id'] ?? $properties['id'] ?? null;
48 | $ttId = $properties['term_taxonomy_id'] ?? $properties['tt_id'] ?? null;
49 | ($id && !$ttId) and $ttId = $id;
50 | ($ttId && !$id) and $id = $ttId;
51 |
52 | $id or $id = $this->uniqueGenerator->numberBetween(1, 99999999);
53 | $ttId or $ttId = $id;
54 |
55 | $slug = strtolower($this->uniqueGenerator->slug($this->generator->numberBetween(1, 2)));
56 |
57 | $defaults = [
58 | 'name' => ucwords(str_replace('-', ' ', $slug)),
59 | 'slug' => $slug,
60 | 'term_group' => '',
61 | 'taxonomy' => array_rand(Taxonomy::BUILT_IN),
62 | 'description' => $this->generator->sentence,
63 | 'parent' => $this->generator->numberBetween(0, 99999),
64 | 'count' => $this->generator->numberBetween(0, 99999),
65 | 'filter' => $this->generator->randomElement(['raw', null]),
66 | ];
67 |
68 | $term = \Mockery::mock(\WP_Term::class);
69 | $term->term_id = (int)$id;
70 | $term->term_taxonomy_id = (int)$ttId;
71 |
72 | $toArray = ['term_id' => (int)$id, 'term_taxonomy_id' => (int)$ttId];
73 | foreach ($defaults as $key => $value) {
74 | $field = array_key_exists($key, $properties) ? $properties[$key] : $value;
75 | $toArray[$key] = $field;
76 | $term->{$key} = $field;
77 | }
78 |
79 | /** @var \Mockery\MockInterface $term */
80 | $term->data = (object)$toArray;
81 | $term->shouldReceive('to_array')->andReturn($toArray)->byDefault();
82 |
83 | $this->terms[$term->term_id] = $toArray;
84 | $this->mockFunctions();
85 |
86 | return $term;
87 | }
88 |
89 | /**
90 | * @return void
91 | */
92 | private function mockFunctions(): void
93 | {
94 | if (!$this->canMockFunctions()) {
95 | return;
96 | }
97 |
98 | $this->functionExpectations->mock('get_term')
99 | ->zeroOrMoreTimes()
100 | ->andReturnUsing(
101 | function (...$args) { //phpcs:ignore
102 | return $this->mockedGetTerm(...$args);
103 | }
104 | );
105 |
106 | $this->functionExpectations->mock('get_term_by')
107 | ->zeroOrMoreTimes()
108 | ->andReturnUsing(
109 | function (...$args) { //phpcs:ignore
110 | return $this->mockedGetTermBy(...$args);
111 | }
112 | );
113 |
114 | $this->stopMockingFunctions();
115 | }
116 |
117 | /**
118 | * @param $term
119 | * @param string $taxonomy
120 | * @param string $output
121 | * @return array|\WP_Term|null
122 | *
123 | * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration
124 | * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration
125 | */
126 | private function mockedGetTerm($term, $taxonomy = '', $output = 'OBJECT')
127 | {
128 | // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration
129 | // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration
130 |
131 | $termId = is_object($term) ? $term->term_id ?? null : $term;
132 | if (!$termId || !is_numeric($termId)) {
133 | return null;
134 | }
135 |
136 | $data = $this->terms[(int)$termId] ?? null;
137 | if (!$data || ($taxonomy && $taxonomy !== $data['taxonomy'])) {
138 | return null;
139 | }
140 |
141 | $termObj = $this->__invoke($data);
142 |
143 | if ($output === 'ARRAY_A') {
144 | return $termObj->to_array();
145 | } elseif ($output === 'ARRAY_N') {
146 | return array_values($termObj->to_array());
147 | }
148 |
149 | return $termObj;
150 | }
151 |
152 | /**
153 | * @param $field
154 | * @param $value
155 | * @param string $taxonomy
156 | * @param string $output
157 | * @return array|\WP_Term|bool
158 | *
159 | * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration
160 | * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration
161 | */
162 | private function mockedGetTermBy($field, $value, $taxonomy = '', $output = 'OBJECT')
163 | {
164 | // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration
165 | // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration
166 |
167 | if (!in_array($field, ['id', 'term_taxonomy_id', 'slug', 'name'], true)) {
168 | return false;
169 | }
170 |
171 | $id = $field === 'id' ? $value : null;
172 | if ($id === null) {
173 | $isTtId = $field === 'term_taxonomy_id';
174 | if (($isTtId && !is_numeric($value))
175 | || (!$isTtId && (!is_string($value) || !$taxonomy))
176 | ) {
177 | return false;
178 | }
179 |
180 | $isTtId and $value = (int)$value;
181 | if ($field === 'slug') {
182 | $value = preg_replace('/[^a-z0-9_-]/i', '-', strtolower($value));
183 | }
184 |
185 | $values = array_column($this->terms, $field, 'term_id');
186 | $id = array_search($value, $values, true);
187 | }
188 |
189 | return $id && is_numeric($id)
190 | ? ($this->mockedGetTerm($id, $taxonomy, $output) ?: false)
191 | : false;
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/src/Provider/User.php:
--------------------------------------------------------------------------------
1 | [
21 | 'switch_themes',
22 | 'edit_themes',
23 | 'activate_plugins',
24 | 'edit_plugins',
25 | 'edit_users',
26 | 'edit_files',
27 | 'manage_options',
28 | 'moderate_comments',
29 | 'manage_categories',
30 | 'manage_links',
31 | 'upload_files',
32 | 'import',
33 | 'unfiltered_html',
34 | 'edit_posts',
35 | 'edit_others_posts',
36 | 'edit_published_posts',
37 | 'publish_posts',
38 | 'edit_pages',
39 | 'read',
40 | 'level_10',
41 | 'level_9',
42 | 'level_8',
43 | 'level_7',
44 | 'level_6',
45 | 'level_5',
46 | 'level_4',
47 | 'level_3',
48 | 'level_2',
49 | 'level_1',
50 | 'level_0',
51 | 'edit_others_pages',
52 | 'edit_published_pages',
53 | 'publish_pages',
54 | 'delete_pages',
55 | 'delete_others_pages',
56 | 'delete_published_pages',
57 | 'delete_posts',
58 | 'delete_others_posts',
59 | 'delete_published_posts',
60 | 'delete_private_posts',
61 | 'edit_private_posts',
62 | 'read_private_posts',
63 | 'delete_private_pages',
64 | 'edit_private_pages',
65 | 'read_private_pages',
66 | 'delete_users',
67 | 'create_users',
68 | 'unfiltered_upload',
69 | 'edit_dashboard',
70 | 'update_plugins',
71 | 'delete_plugins',
72 | 'install_plugins',
73 | 'update_themes',
74 | 'install_themes',
75 | 'update_core',
76 | 'list_users',
77 | 'remove_users',
78 | 'promote_users',
79 | 'edit_theme_options',
80 | 'delete_themes',
81 | 'export',
82 | 'manage_woocommerce',
83 | 'view_woocommerce_reports',
84 | 'edit_product',
85 | 'read_product',
86 | 'delete_product',
87 | 'edit_products',
88 | 'edit_others_products',
89 | 'publish_products',
90 | 'read_private_products',
91 | 'delete_products',
92 | 'delete_private_products',
93 | 'delete_published_products',
94 | 'delete_others_products',
95 | 'edit_private_products',
96 | 'edit_published_products',
97 | 'manage_product_terms',
98 | 'edit_product_terms',
99 | 'delete_product_terms',
100 | 'assign_product_terms',
101 | 'edit_shop_order',
102 | 'read_shop_order',
103 | 'delete_shop_order',
104 | 'edit_shop_orders',
105 | 'edit_others_shop_orders',
106 | 'publish_shop_orders',
107 | 'read_private_shop_orders',
108 | 'delete_shop_orders',
109 | 'delete_private_shop_orders',
110 | 'delete_published_shop_orders',
111 | 'delete_others_shop_orders',
112 | 'edit_private_shop_orders',
113 | 'edit_published_shop_orders',
114 | 'manage_shop_order_terms',
115 | 'edit_shop_order_terms',
116 | 'delete_shop_order_terms',
117 | 'assign_shop_order_terms',
118 | 'edit_shop_coupon',
119 | 'read_shop_coupon',
120 | 'delete_shop_coupon',
121 | 'edit_shop_coupons',
122 | 'edit_others_shop_coupons',
123 | 'publish_shop_coupons',
124 | 'read_private_shop_coupons',
125 | 'delete_shop_coupons',
126 | 'delete_private_shop_coupons',
127 | 'delete_published_shop_coupons',
128 | 'delete_others_shop_coupons',
129 | 'edit_private_shop_coupons',
130 | 'edit_published_shop_coupons',
131 | 'manage_shop_coupon_terms',
132 | 'edit_shop_coupon_terms',
133 | 'delete_shop_coupon_terms',
134 | 'assign_shop_coupon_terms',
135 | ],
136 | 'editor' => [
137 | 'moderate_comments',
138 | 'manage_categories',
139 | 'manage_links',
140 | 'upload_files',
141 | 'unfiltered_html',
142 | 'edit_posts',
143 | 'edit_others_posts',
144 | 'edit_published_posts',
145 | 'publish_posts',
146 | 'edit_pages',
147 | 'read',
148 | 'level_7',
149 | 'level_6',
150 | 'level_5',
151 | 'level_4',
152 | 'level_3',
153 | 'level_2',
154 | 'level_1',
155 | 'level_0',
156 | 'edit_others_pages',
157 | 'edit_published_pages',
158 | 'publish_pages',
159 | 'delete_pages',
160 | 'delete_others_pages',
161 | 'delete_published_pages',
162 | 'delete_posts',
163 | 'delete_others_posts',
164 | 'delete_published_posts',
165 | 'delete_private_posts',
166 | 'edit_private_posts',
167 | 'read_private_posts',
168 | 'delete_private_pages',
169 | 'edit_private_pages',
170 | 'read_private_pages',
171 | ],
172 | 'author' => [
173 | 'upload_files',
174 | 'edit_posts',
175 | 'edit_published_posts',
176 | 'publish_posts',
177 | 'read',
178 | 'level_2',
179 | 'level_1',
180 | 'level_0',
181 | 'delete_posts',
182 | 'delete_published_posts',
183 | ],
184 | 'contributor' => [
185 | 'edit_posts',
186 | 'read',
187 | 'level_1',
188 | 'level_0',
189 | 'delete_posts',
190 | ],
191 | 'subscriber' => [
192 | 'read',
193 | 'level_0',
194 | ],
195 | ];
196 |
197 | const LEVELS = [
198 | 'administrator' => 10,
199 | 'editor' => 7,
200 | 'author' => 2,
201 | 'contributor' => 1,
202 | 'subscriber' => 0,
203 | ];
204 |
205 | /**
206 | * @var array[]
207 | */
208 | private $users = [];
209 |
210 | /**
211 | * @var bool
212 | */
213 | private $currentUserSet = false;
214 |
215 | /**
216 | * @param \WP_User $user
217 | * @return callable
218 | */
219 | public static function withSame(\WP_User $user): callable
220 | {
221 | return function (\WP_User $theUser) use ($user): bool {
222 | return (int)$theUser->ID === (int)$user->ID;
223 | };
224 | }
225 |
226 | /**
227 | * @return void
228 | */
229 | public function reset(): void
230 | {
231 | $this->users = [];
232 | $this->currentUserSet = false;
233 | parent::reset();
234 | }
235 |
236 | /**
237 | * @param array $properties
238 | * @return \WP_User|MonkeyWpUser
239 | *
240 | * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
241 | */
242 | public function __invoke(array $properties = []): \WP_User
243 | {
244 | // phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
245 |
246 | $properties = array_change_key_case($properties, CASE_LOWER);
247 |
248 | $user = $this->createBaseUser($properties);
249 |
250 | $noPrefixKeys = [
251 | 'user_firstname' => 'first_name',
252 | 'user_lastname' => 'last_name',
253 | 'user_description' => 'description',
254 | ];
255 |
256 | $login = $this->uniqueGenerator->userName;
257 |
258 | $defaults = [
259 | 'user_login' => $login,
260 | 'user_pass' => $this->generator->password,
261 | 'user_nicename' => preg_replace('/[^a-z0-9-]/', '-', strtolower($login)),
262 | 'user_email' => $this->uniqueGenerator->email,
263 | 'user_url' => 'https://' . $this->generator->domainName,
264 | 'user_registered' => $this->generator->date('Y-m-d H:i:s'),
265 | 'user_activation_key' => rand(1, 100) > 80 ? $this->generator->password(32) : '',
266 | 'user_status' => '0',
267 | 'display_name' => $this->generator->name,
268 | 'user_description' => $this->generator->sentence,
269 | 'user_firstname' => $this->generator->firstName,
270 | 'user_lastname' => $this->generator->lastName,
271 | 'nickname' => $login,
272 | 'spam' => '',
273 | 'deleted' => '',
274 | 'locale' => $this->generator->locale,
275 | 'rich_editing' => $this->generator->randomElement(['true', 'false']),
276 | 'syntax_highlighting' => $this->generator->randomElement(['true', 'false']),
277 | 'cap_key' => 'wp_capabilities',
278 | 'filter' => $this->generator->randomElement(['raw', null]),
279 | ];
280 |
281 | foreach ($defaults as $key => $value) {
282 | $hasKey = array_key_exists($key, $properties);
283 | $noPrefixKey = '';
284 | if (strpos($key, 'user_') === 0) {
285 | $noPrefixKey = $noPrefixKeys[$key] ?? substr($key, 5);
286 | }
287 |
288 | if (!$hasKey && $noPrefixKey) {
289 | $hasKey = array_key_exists($noPrefixKey, $properties);
290 | $hasKey and $properties[$key] = $properties[$noPrefixKey];
291 | }
292 |
293 | if (!$hasKey && $key === 'user_pass' && !empty($properties['password'])) {
294 | $properties[$key] = $properties['password'];
295 | $hasKey = true;
296 | }
297 |
298 | $field = $hasKey ? $properties[$key] : $value;
299 | $user->{$key} = $field;
300 | $get[$key] = $field;
301 |
302 | if ($noPrefixKey && in_array($noPrefixKey, $noPrefixKeys, true)) {
303 | $user->{$noPrefixKey} = $field;
304 | }
305 | }
306 |
307 | $toArray = [
308 | 'ID' => $user->ID,
309 | 'user_login' => $user->user_login,
310 | 'user_pass' => $user->user_pass,
311 | 'user_nicename' => $user->user_nicename,
312 | 'user_email' => $user->user_email,
313 | 'user_url' => $user->user_url,
314 | 'user_registered' => $user->user_registered,
315 | 'user_activation_key' => $user->user_activation_key,
316 | 'user_status' => $user->user_status,
317 | 'display_name' => $user->display_name,
318 | ];
319 |
320 | $user->data = (object)$toArray;
321 |
322 | $user->shouldReceive('to_array')->andReturn($toArray)->byDefault();
323 |
324 | $getKeys = [
325 | 'user_description',
326 | 'description',
327 | 'user_firstname',
328 | 'first_name',
329 | 'user_lastname',
330 | 'last_name',
331 | 'user_level',
332 | 'nickname',
333 | 'spam',
334 | 'deleted',
335 | 'locale',
336 | 'rich_editing',
337 | 'syntax_highlighting',
338 | ];
339 |
340 | $get = $toArray;
341 | foreach ($getKeys as $key) {
342 | $get[$key] = $user->{$key};
343 | }
344 |
345 | $user->shouldReceive('get')
346 | ->andReturnUsing(
347 | function ($key) use ($get) { //phpcs:ignore
348 | if (strtoupper($key) === 'ID' && $key !== 'ID') {
349 | throw new \Error('Please use `WP_User::ID` instead of `WP_User::id`.');
350 | }
351 |
352 | return array_key_exists($key, $get) ? (string)$get[$key] : false;
353 | }
354 | )
355 | ->byDefault();
356 |
357 | $siteId = $properties['site_id']
358 | ?? $properties['blog_id']
359 | ?? (rand(1, 100) > 80 ? $this->generator->numberBetween(1, 10) : 1);
360 |
361 | $user->shouldReceive('get_site_id')->andReturn($siteId)->byDefault();
362 |
363 | $this->saveUser($get, (int)$siteId, $user);
364 | $this->mockFunctions();
365 |
366 | $user->shouldReceive('__monkeyMakeCurrent')
367 | ->withNoArgs()
368 | ->andReturnUsing(
369 | function () use (&$user) { //phpcs:ignore
370 | $this->makeCurrent($user);
371 |
372 | return $user;
373 | }
374 | );
375 |
376 | return $user;
377 | }
378 |
379 | /**
380 | * @param array $properties
381 | * @return \Mockery\MockInterface|\WP_User
382 | */
383 | private function createBaseUser(array $properties): \Mockery\MockInterface
384 | {
385 | [$userRoles, $allCaps, $userCaps, $level] = $this->extractRolesAndCapabilities($properties);
386 |
387 | $id = array_key_exists('id', $properties)
388 | ? $properties['id']
389 | : $this->uniqueGenerator->numberBetween(1, 99999999);
390 |
391 | $user = \Mockery::mock(\WP_User::class);
392 | $user->ID = (int)$id;
393 | $user->roles = $userRoles;
394 | $user->caps = $userCaps;
395 | $user->allcaps = $allCaps;
396 | $user->user_level = is_int($level) ? $level : '';
397 |
398 | $user->shouldReceive('exists')->andReturn($id > 0)->byDefault();
399 |
400 | $user->shouldReceive('has_cap')
401 | ->with(\Mockery::type('string'))
402 | ->andReturnUsing(
403 | function ($cap) use ($allCaps) { //phpcs:ignore
404 | return !empty($allCaps[$cap]);
405 | }
406 | )
407 | ->byDefault();
408 |
409 | return $user;
410 | }
411 |
412 | /**
413 | * @param array $properties
414 | * @param int $siteId
415 | * @param \WP_User $user
416 | */
417 | private function saveUser(array $properties, int $siteId, \WP_User $user)
418 | {
419 | $updatedProps = $properties;
420 | $updatedProps['site_id'] = $siteId;
421 | $updatedProps['allcaps'] = $user->allcaps;
422 | $updatedProps['roles'] = $user->roles;
423 | $updatedProps['user_level'] = $user->user_level;
424 |
425 | $this->users[$user->ID] = $updatedProps;
426 | }
427 |
428 | /**
429 | * @return void
430 | *
431 | * phpcs:disable Inpsyde.CodeQuality.FunctionLength.TooLong
432 | * phpcs:disable Generic.Metrics.NestingLevel
433 | */
434 | private function mockFunctions(): void
435 | {
436 | // phpcs:enable Inpsyde.CodeQuality.FunctionLength.TooLong
437 | // phpcs:enable Generic.Metrics.NestingLevel
438 |
439 | if (!$this->canMockFunctions()) {
440 | return;
441 | }
442 |
443 | $this->functionExpectations->mock('get_userdata')
444 | ->zeroOrMoreTimes()
445 | ->andReturnUsing(
446 | function ($userId = null) { //phpcs:ignore
447 | if (!is_numeric($userId) || !array_key_exists((int)$userId, $this->users)) {
448 | return false;
449 | }
450 |
451 | return $this->__invoke($this->users[(int)$userId]);
452 | }
453 | );
454 |
455 | $this->functionExpectations->mock('get_user_by')
456 | ->zeroOrMoreTimes()
457 | ->with(\Mockery::any(), \Mockery::any())
458 | ->andReturnUsing(
459 | function ($field, $value) { //phpcs:ignore
460 | if (!in_array($field, ['id', 'ID', 'slug', 'email', 'login'], true)) {
461 | return false;
462 | }
463 |
464 | $byId = $field === 'id' || $field === 'ID';
465 | $id = $byId ? $value : null;
466 | if (!$byId) {
467 | if (!is_string($value)) {
468 | return false;
469 | }
470 |
471 | $fieldName = $field === 'slug' ? 'nicename' : $field;
472 | $fields = array_column($this->users, "user_{$fieldName}", 'ID');
473 | $id = array_search($value, $fields, true);
474 | }
475 |
476 | if (!is_numeric($id) || !array_key_exists((int)$id, $this->users)) {
477 | return false;
478 | }
479 |
480 | return $this->__invoke($this->users[(int)$id]);
481 | }
482 | );
483 |
484 | $this->functionExpectations->mock('user_can')
485 | ->zeroOrMoreTimes()
486 | ->with(\Mockery::any(), \Mockery::any())
487 | ->andReturnUsing(
488 | function ($user = null, $cap = null) { // phpcs:ignore
489 | $userId = is_object($user) ? $user->ID : $user;
490 | if (!is_numeric($userId)
491 | || !is_scalar($cap)
492 | || !array_key_exists((int)$userId, $this->users)
493 | ) {
494 | return false;
495 | }
496 |
497 | $caps = $this->users[(int)$userId]['allcaps'];
498 |
499 | return !empty($caps[$cap]);
500 | }
501 | );
502 |
503 | $this->stopMockingFunctions();
504 | }
505 |
506 | /**
507 | * @param \WP_User $user
508 | * @return void
509 | */
510 | private function makeCurrent(\WP_User $user): void
511 | {
512 | if ($this->currentUserSet) {
513 | throw new \Error('Only one user can be made the current one.');
514 | }
515 |
516 | $this->currentUserSet = true;
517 |
518 | Monkey\Functions\when('get_current_user_id')->justReturn($user->ID);
519 | Monkey\Functions\when('wp_get_current_user')->justReturn($user);
520 | Monkey\Functions\when('current_user_can')->alias([$user, 'has_cap']);
521 | }
522 |
523 | /**
524 | * @param array $properties
525 | * @return array
526 | */
527 | private function extractRolesAndCapabilities(array $properties): array
528 | {
529 | $role = $properties['role'] ?? null;
530 | $roles = $properties['roles'] ?? null;
531 | $level = $properties['user_level'] ?? $properties['level'] ?? null;
532 | $allCaps = $properties['allcaps']
533 | ?? $properties['caps']
534 | ?? $properties['capabilities']
535 | ?? null;
536 |
537 | $rawRoles = is_array($roles) ? $roles : [];
538 | ($role && is_string($role)) and $rawRoles[] = $role;
539 | $userRoles = array_values(array_filter($rawRoles, 'is_string'));
540 | is_numeric($level) and $level = (int)$level;
541 |
542 | if (is_int($level) && !$userRoles) {
543 | $foundLevels = [];
544 | $level = min(max((int)$level, 0), 10);
545 | foreach (self::LEVELS as $levelRole => $roleLevel) {
546 | ($level >= $roleLevel) and $foundLevels[$roleLevel] = $levelRole;
547 | }
548 | if ($foundLevels) {
549 | ksort($foundLevels, SORT_NUMERIC);
550 | $userRoles[] = end($foundLevels);
551 | }
552 | }
553 |
554 | if (!$userRoles && $roles !== []) {
555 | $userRoles = $this->generator->randomElements(array_keys(self::CAPS), 3);
556 | }
557 |
558 | $hasCaps = is_array($allCaps);
559 | [$allCaps, $userCaps] = $this->prepareCapabilities(
560 | $userRoles,
561 | $hasCaps ? $allCaps : [],
562 | $hasCaps
563 | );
564 |
565 | if (!is_int($level)) {
566 | $level = null;
567 | foreach ($userRoles as $role) {
568 | $level = $level === null
569 | ? (int)(self::LEVELS[$role] ?? 0)
570 | : (int)max($level, self::LEVELS[$role] ?? 0);
571 | }
572 |
573 | if ($level === null && $roles !== []) {
574 | $level = $this->generator->numberBetween(0, 10);
575 | }
576 | }
577 |
578 | if (is_int($level)) {
579 | $level = min(max((int)$level, 0), 10);
580 | for ($i = 0; $i <= $level; $i++) {
581 | array_key_exists("level_{$i}", $allCaps) or $allCaps["level_{$i}"] = true;
582 | }
583 | }
584 |
585 | return [array_unique(array_filter($userRoles)), $allCaps, $userCaps, $level];
586 | }
587 |
588 | /**
589 | * @param array $roles
590 | * @param array $allcaps
591 | * @param bool $hasCaps
592 | * @return array
593 | */
594 | private function prepareCapabilities(
595 | array $roles,
596 | array $allcaps,
597 | bool $hasCaps
598 | ): array {
599 |
600 | $userCaps = [];
601 |
602 | foreach ($roles as $role) {
603 | $userCaps[$role] = true;
604 | if (!$hasCaps && array_key_exists($role, self::CAPS)) {
605 | $roleCaps = array_fill_keys(self::CAPS[$role], true);
606 | $allcaps = array_merge($allcaps, $roleCaps);
607 | }
608 | }
609 |
610 | return [$hasCaps ? $allcaps : array_merge($allcaps, $userCaps), $userCaps];
611 | }
612 | }
613 |
--------------------------------------------------------------------------------
/src/Providers.php:
--------------------------------------------------------------------------------
1 | >
226 | */
227 | private $methods = [
228 | self::ONE => [],
229 | self::MANY => [],
230 | ];
231 |
232 | /**
233 | * @var array
234 | */
235 | private $providers = [];
236 |
237 | /**
238 | * @var FunctionExpectations
239 | */
240 | private $functionExpectations;
241 |
242 | /**
243 | * @param Generator $generator
244 | */
245 | public function __construct(Generator $generator)
246 | {
247 | $this->generator = $generator;
248 | $this->functionExpectations = new FunctionExpectations();
249 | }
250 |
251 | /**
252 | * @param string $method
253 | * @param array $args
254 | * @return object|object[]
255 | *
256 | * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration
257 | */
258 | public function __call(string $method, array $args = [])
259 | {
260 | //phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration
261 |
262 | $this->bailWhenNotInitialized(sprintf('$faker->wp()->%s', $method));
263 |
264 | /**
265 | * @var bool $forceMany
266 | * @var string $method
267 | * @var bool|null $atLeast
268 | * @var bool|null $atMost
269 | */
270 | [$forceMany, $method, $atLeast, $atMost] = $this->extractAtLeastArMost($method);
271 |
272 | /**
273 | * @var callable $object
274 | * @var bool $isMany
275 | */
276 | [$object, $isMany] = $this->factoryProvider($method);
277 |
278 | if (!$isMany && !$forceMany) {
279 | return $object(...$args);
280 | }
281 |
282 | $min = $atLeast ?? 0;
283 | $max = $atMost ?? ($min + $this->generator->numberBetween(1, 10));
284 |
285 | $num = null;
286 | if ($atLeast === null && $atMost === null) {
287 | $num = $args ? array_shift($args) : $this->generator->numberBetween(0, 10);
288 | is_numeric($num) or $this->bailForCallManyWithNoNumber($method);
289 | }
290 |
291 | $params = $args ? reset($args) : [];
292 | if (!is_array($params)) {
293 | $this->bailForCallManyWithBadParams($method);
294 | }
295 |
296 | if ($num === null) {
297 | $num = $min === $max ? $min : $this->generator->numberBetween($min, $max);
298 | }
299 |
300 | $objects = [];
301 | for ($i = 0; $i < $num; $i++) {
302 | $objects[] = $object(...$args);
303 | }
304 |
305 | return $objects;
306 | }
307 |
308 | /**
309 | * @param string $method
310 | * @return mixed
311 | *
312 | * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration
313 | */
314 | public function __get(string $method)
315 | {
316 | // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration
317 |
318 | return $this->__call($method);
319 | }
320 |
321 | /**
322 | * @param string $providerClass
323 | * @param string $methodOne
324 | * @param string $methodMany
325 | * @return Providers
326 | */
327 | public function __addProviderClass( // phpcs:ignore
328 | string $providerClass,
329 | string $methodOne,
330 | string $methodMany
331 | ): Providers {
332 |
333 | $reflection = null;
334 |
335 | if (!is_subclass_of($providerClass, Provider::class)) {
336 | $this->bailForInvalidClass($providerClass);
337 | }
338 |
339 | try {
340 | $reflection = new \ReflectionClass($providerClass);
341 | } catch (\Throwable $throwable) {
342 | $this->bailForInvalidClass($providerClass, $throwable);
343 | }
344 |
345 | /** \ReflectionClass $reflection */
346 | if (!$reflection->isInstantiable()) {
347 | $this->bailForInvalidClass($providerClass);
348 | }
349 |
350 | if ($methodOne === 'wp' || substr($methodOne, 0, 2) === '__') {
351 | $this->bailForReservedMethod($methodOne);
352 | }
353 |
354 | if ($methodMany === 'wp' || substr($methodMany, 0, 2) === '__') {
355 | $this->bailForReservedMethod($methodOne);
356 | }
357 |
358 | $this->methods[self::ONE][$methodOne] = $providerClass;
359 | $this->methods[self::MANY][$methodMany] = $providerClass;
360 | unset($this->providers[$providerClass]);
361 |
362 | return $this;
363 | }
364 |
365 | /**
366 | * @return Providers
367 | */
368 | public function __resetUnique(): Providers // phpcs:ignore
369 | {
370 | /** @var Provider $provider */
371 | foreach ($this->providers as $provider) {
372 | $provider->resetUnique();
373 | }
374 |
375 | return $this;
376 | }
377 |
378 | /**
379 | * @param string $function
380 | * @return Expectation
381 | */
382 | public function __monkeyFunction(string $function): Expectation // phpcs:ignore
383 | {
384 | return $this->functionExpectations->replace($function);
385 | }
386 |
387 | /**
388 | * @return Providers
389 | */
390 | public function __reset(): Providers // phpcs:ignore
391 | {
392 | $this->functionExpectations->reset();
393 |
394 | /** @var Provider $provider */
395 | foreach ($this->providers as $provider) {
396 | $provider->reset();
397 | }
398 |
399 | return $this;
400 | }
401 |
402 | /**
403 | * @return Providers
404 | */
405 | public function wp(): Providers
406 | {
407 | $this->bailWhenNotInitialized(__METHOD__);
408 |
409 | return $this;
410 | }
411 |
412 | /**
413 | * @param string $method
414 | * @return array
415 | */
416 | private function extractAtLeastArMost(string $method): array
417 | {
418 | $numWords = [
419 | 'One' => 1,
420 | 'Two' => 2,
421 | 'Three' => 3,
422 | 'Four' => 4,
423 | 'Five' => 5,
424 | ];
425 |
426 | $prefixExp = 'atLeast|atMost|between';
427 | $numExp = '(?:[0-9]+)|(?:' . implode('|', array_keys($numWords)) . ')';
428 | $dynamicMethod = preg_match(
429 | "/^(?P{$prefixExp})(?{$numExp})(?:And(?P{$numExp}))?(?P.+)\$/",
430 | $method,
431 | $matches
432 | );
433 |
434 | if (!$dynamicMethod) {
435 | return [false, $method, null, null];
436 | }
437 |
438 | $minOrMax = $matches['prefix'] !== 'between' && empty($matches['n2']);
439 | $between = $matches['prefix'] === 'between' && !empty($matches['n2']);
440 |
441 | if (!$minOrMax && !$between) {
442 | return [false, $method, null, null];
443 | }
444 |
445 | if ($minOrMax) {
446 | $isNum = is_numeric($matches['n1']);
447 | $atNum = $isNum ? (int)$matches['n1'] : $numWords[$matches['n1']];
448 | $maybeMethod = lcfirst($matches['method']);
449 | if (($atNum === 1 && array_key_exists($maybeMethod, $this->methods[self::ONE]))
450 | || array_key_exists($maybeMethod, $this->methods[self::MANY])
451 | ) {
452 | $atLeast = $matches['prefix'] === 'atLeast' ? $atNum : null;
453 | $atMost = $matches['prefix'] === 'atLeast' ? null : $atNum;
454 |
455 | return [true, $maybeMethod, $atLeast, $atMost];
456 | }
457 |
458 | return [false, $method, null, null];
459 | }
460 |
461 | $isNumMin = is_numeric($matches['n1']);
462 | $isNumMax = is_numeric($matches['n2']);
463 | $maybeMethod = lcfirst($matches['method']);
464 |
465 | if (array_key_exists($maybeMethod, $this->methods[self::MANY])) {
466 | $min = $isNumMin ? (int)$matches['n1'] : $numWords[$matches['n1']];
467 | $max = $isNumMax ? (int)$matches['n2'] : $numWords[$matches['n2']];
468 | $atLeast = min($min, $max);
469 | $atMost = max($min, $max);
470 |
471 | return [true, $maybeMethod, $atLeast, $atMost];
472 | }
473 |
474 | return [false, $method, null, null];
475 | }
476 |
477 | /**
478 | * @param string $method
479 | * @return array
480 | */
481 | private function factoryProvider(string $method): array
482 | {
483 | $isOne = array_key_exists($method, $this->methods[self::ONE]);
484 | $isMany = array_key_exists($method, $this->methods[self::MANY]);
485 |
486 | if (!$isOne && !$isMany) {
487 | $this->bailForInvalidMethod($method);
488 | }
489 |
490 | if ($isOne && $isMany) {
491 | $this->bailForNotUniquelyIdentifiedClass($method);
492 | }
493 |
494 | $class = $isMany ? $this->methods[self::MANY][$method] : $this->methods[self::ONE][$method];
495 |
496 | if (empty($this->providers[$class])) {
497 | $isFunctionMocker = is_subclass_of($class, FunctionMockerProvider::class, true);
498 | /** @var Provider|FunctionMockerProvider $provider */
499 | $provider = $isFunctionMocker
500 | ? new $class($this->generator, $this->functionExpectations)
501 | : new $class($this->generator);
502 |
503 | $this->providers[$class] = $provider;
504 | }
505 |
506 | return [$this->providers[$class], $isMany];
507 | }
508 |
509 | /**
510 | * @param string $method
511 | */
512 | private function bailWhenNotInitialized(string $method): void
513 | {
514 | if (!empty($this->methods[self::ONE])) {
515 | return;
516 | }
517 |
518 | throw new \Error(
519 | sprintf(
520 | "Can't call '%s()' before %s has been initialized.",
521 | $method,
522 | __CLASS__
523 | )
524 | );
525 | }
526 |
527 | /**
528 | * @param string $class
529 | * @param \Throwable|null $previous
530 | */
531 | private function bailForInvalidClass(string $class, \Throwable $previous = null): void
532 | {
533 | throw new \Error("{$class} is not a valid provider class.", 0, $previous);
534 | }
535 |
536 | /**
537 | * @param string $method
538 | */
539 | private function bailForInvalidMethod(string $method): void
540 | {
541 | throw new \Error(sprintf('Call to undefined method %s::%s()', __CLASS__, $method));
542 | }
543 |
544 | /**
545 | * @param string $method
546 | */
547 | private function bailForNotUniquelyIdentifiedClass(string $method): void
548 | {
549 | throw new \Error(
550 | "Impossible to uniquely identify provider class for \$faker->wp()->{$method}()."
551 | );
552 | }
553 |
554 | /**
555 | * @param string $method
556 | */
557 | private function bailForReservedMethod(string $method): void
558 | {
559 | throw new \Error(
560 | "'{$method}' is a reserved method name, can't be used for \$faker->wp()->{$method}()."
561 | );
562 | }
563 |
564 | /**
565 | * @param string $method
566 | */
567 | private function bailForCallManyWithNoNumber(string $method): void
568 | {
569 | throw new \Error("\$faker->wp()->{$method}() first argument must be a number.");
570 | }
571 |
572 | /**
573 | * @param string $method
574 | */
575 | private function bailForCallManyWithBadParams(string $method): void
576 | {
577 | throw new \Error("\$faker->wp()->{$method}() requires options provided as array.");
578 | }
579 | }
580 |
--------------------------------------------------------------------------------
/tests/cases/functional/BrainFakerTest.php:
--------------------------------------------------------------------------------
1 | wpFaker->post(['id' => 123, 'author' => 456]);
25 | $this->wpFaker->user(['id' => 456, 'role' => 'editor'])->__monkeyMakeCurrent();
26 |
27 | static::assertSame('It works!', $this->productionCode(123));
28 | }
29 |
30 | public function testPostAndUserNoRole()
31 | {
32 | $this->wpFaker->post(['id' => 123, 'author' => 456]);
33 | $this->wpFaker->user(['id' => 456, 'role' => 'subscriber'])->__monkeyMakeCurrent();
34 |
35 | static::assertSame('Can\'t edit pages', $this->productionCode(123));
36 | }
37 |
38 | public function testPostAndUserNoPost()
39 | {
40 | $this->wpFaker->post(['id' => 123, 'author' => 456]);
41 | $this->wpFaker->user(['id' => 456, 'role' => 'subscriber'])->__monkeyMakeCurrent();
42 |
43 | static::assertSame('No post', $this->productionCode(124));
44 | }
45 |
46 | public function testPostAndUserNoCurrentUser()
47 | {
48 | $this->wpFaker->post(['id' => 123, 'author' => 457]);
49 | $this->wpFaker->user(['id' => 456, 'role' => 'subscriber'])->__monkeyMakeCurrent();
50 |
51 | static::assertSame('No user ID', $this->productionCode(123));
52 | }
53 |
54 | public function testPostAndUserNotExists()
55 | {
56 | $this->wpFaker->post(['id' => 123, 'author' => 456]);
57 |
58 | $user = $this->wpFaker->user(['id' => 456, 'role' => 'subscriber'])
59 | ->__monkeyMakeCurrent();
60 |
61 | $this->wpFaker->__monkeyFunction('get_userdata')
62 | ->once()
63 | ->with($user->ID)
64 | ->andReturn($user);
65 |
66 | $user->shouldReceive('exists')
67 | ->once()
68 | ->andReturn(false);
69 |
70 | static::assertSame('Bad user', $this->productionCode(123));
71 | }
72 |
73 | public function testWithoutBrainFaker()
74 | {
75 | $post = \Mockery::mock(\WP_Post::class);
76 | $post->post_author = 456;
77 |
78 | $user = \Mockery::mock(\WP_User::class);
79 | $user->shouldReceive('exists')->andReturn(true);
80 | $user->shouldReceive('has_cap')->with('edit_others_pages')->andReturn(true);
81 | $user->ID = 456;
82 | $user->user_email = 'me@example.com';
83 | $user->user_url = 'http://example.com';
84 |
85 | Monkey\Functions\expect('get_post')->with(123)->andReturn($post);
86 | Monkey\Functions\expect('user_can')->with($user, 'upload_files')->andReturn(true);
87 | Monkey\Functions\expect('get_current_user_id')->andReturn(456);
88 | Monkey\Functions\expect('get_userdata')->with(456)->andReturn($user);
89 | Monkey\Functions\expect('wp_get_current_user')->andReturn($user);
90 |
91 | static::assertSame('It works!', $this->productionCode(123));
92 | }
93 |
94 | /**
95 | * @param int $postId
96 | * @return string
97 | */
98 | private function productionCode(int $postId): string
99 | {
100 | $post = get_post($postId);
101 |
102 | if (!$post instanceof \WP_Post) {
103 | return 'No post';
104 | }
105 |
106 | $callback = static function (\WP_User $user) { // phpcs:ignore
107 | if (wp_get_current_user()->ID !== $user->ID) {
108 | return "No current user";
109 | }
110 |
111 | if (!user_can($user, 'upload_files')) {
112 | return "Can't upload";
113 | }
114 |
115 | if (filter_var($user->user_email, FILTER_VALIDATE_EMAIL)
116 | && filter_var($user->user_url, FILTER_VALIDATE_URL)
117 | ) {
118 | return 'It works!';
119 | }
120 |
121 | return 'Bad email or URL';
122 | };
123 |
124 | $authorId = (int)$post->post_author;
125 |
126 | if ($authorId === get_current_user_id()) {
127 | $user = get_userdata($authorId);
128 | if (!$user || !$user->exists()) {
129 | return 'Bad user';
130 | }
131 |
132 | if ($user->has_cap('edit_others_pages')) {
133 | return $callback($user);
134 | }
135 |
136 | return "Can't edit pages";
137 | }
138 |
139 | return 'No user ID';
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/tests/cases/unit/GeneratorsTest.php:
--------------------------------------------------------------------------------
1 | wp());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/cases/unit/Provider/CommentTest.php:
--------------------------------------------------------------------------------
1 | factoryProvider(Provider\Comment::class);
22 | $comment = $factory();
23 |
24 | static::assertInstanceOf(\WP_Comment::class, $comment);
25 |
26 | static::assertIsInt($comment->comment_ID);
27 | static::assertGreaterThanOrEqual(1, $comment->comment_ID);
28 | static::assertIsInt($comment->comment_post_ID);
29 | static::assertGreaterThanOrEqual(1, $comment->comment_post_ID);
30 | static::assertIsString($comment->comment_author);
31 | static::assertTrue((bool)filter_var($comment->comment_author_email, FILTER_VALIDATE_EMAIL));
32 | static::assertIsString($comment->comment_author_url);
33 | static::assertIsString($comment->comment_author_url);
34 | static::assertIsString($comment->comment_author_IP);
35 | static::assertTrue((bool)filter_var($comment->comment_author_IP, FILTER_VALIDATE_IP));
36 | static::assertInstanceOf(\DateTime::class, $this->dateByMySql($comment->comment_date));
37 | static::assertInstanceOf(\DateTime::class, $this->dateByMySql($comment->comment_date_gmt));
38 | static::assertIsString($comment->comment_content);
39 | static::assertSame(0, $comment->comment_karma);
40 | static::assertContains($comment->comment_approved, Provider\Comment::STATUSES);
41 | static::assertIsString($comment->comment_agent);
42 | static::assertIsString($comment->comment_type);
43 | static::assertIsInt($comment->comment_parent);
44 | static::assertGreaterThanOrEqual(0, $comment->comment_parent);
45 | static::assertIsInt($comment->user_id);
46 | static::assertGreaterThanOrEqual(0, $comment->user_id);
47 |
48 | $expectedArray = [
49 | 'comment_ID' => $comment->comment_ID,
50 | 'comment_post_ID' => $comment->comment_post_ID,
51 | 'comment_author' => $comment->comment_author,
52 | 'comment_author_email' => $comment->comment_author_email,
53 | 'comment_author_url' => $comment->comment_author_url,
54 | 'comment_author_IP' => $comment->comment_author_IP,
55 | 'comment_date' => $comment->comment_date,
56 | 'comment_date_gmt' => $comment->comment_date_gmt,
57 | 'comment_content' => $comment->comment_content,
58 | 'comment_karma' => $comment->comment_karma,
59 | 'comment_approved' => $comment->comment_approved,
60 | 'comment_agent' => $comment->comment_agent,
61 | 'comment_type' => $comment->comment_type,
62 | 'comment_parent' => $comment->comment_parent,
63 | 'user_id' => $comment->user_id,
64 | ];
65 |
66 | $actualArray = $comment->to_array();
67 |
68 | ksort($expectedArray);
69 | ksort($actualArray);
70 |
71 | static::assertSame($expectedArray, $actualArray);
72 | }
73 |
74 | public function testCreateWithFixedId()
75 | {
76 | $factory = $this->factoryProvider(Provider\Comment::class);
77 | $comment = $factory(['id' => 123]);
78 |
79 | static::assertInstanceOf(\WP_Comment::class, $comment);
80 | static::assertSame(123, $comment->comment_ID);
81 | }
82 |
83 | public function testCreateWithFixedType()
84 | {
85 | $factory = $factory = $this->factoryProvider(Provider\Comment::class);
86 | $comment = $factory(['type' => 'pingback']);
87 |
88 | static::assertInstanceOf(\WP_Comment::class, $comment);
89 | static::assertSame('pingback', $comment->comment_type);
90 | }
91 |
92 | public function testIdUniqueness()
93 | {
94 | $factory = $this->factoryProvider(Provider\Comment::class);
95 |
96 | $ids = [];
97 | for ($i = 0; $i < 200; $i++) {
98 | $ids[] = $factory()->comment_ID;
99 | }
100 |
101 | static::assertSame($ids, array_unique($ids));
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/tests/cases/unit/Provider/ErrorTest.php:
--------------------------------------------------------------------------------
1 | factoryProvider(Provider\Error::class);
22 | $error = $factory();
23 |
24 | static::assertInstanceOf(\WP_Error::class, $error);
25 | static::assertTrue(is_wp_error($error));
26 | static::assertSame([], $error->errors);
27 | static::assertSame([], $error->error_data);
28 | static::assertFalse($error->has_errors());
29 | static::assertSame('', $error->get_error_code());
30 | static::assertSame([], $error->get_error_codes());
31 | static::assertNull($error->get_error_data());
32 | static::assertSame('', $error->get_error_message());
33 | static::assertSame([], $error->get_error_messages());
34 | }
35 |
36 | public function testWithError()
37 | {
38 | $factory = $this->factoryProvider(Provider\Error::class);
39 | $error = $factory(['error' => 'Ahi!']);
40 |
41 | $code = $error->get_error_code();
42 |
43 | static::assertInstanceOf(\WP_Error::class, $error);
44 |
45 | static::assertIsString($code);
46 | static::assertSame('Ahi!', $error->get_error_message());
47 | static::assertSame('Ahi!', $error->get_error_message($code));
48 | static::assertSame(['Ahi!'], $error->get_error_messages());
49 | static::assertSame(['Ahi!'], $error->get_error_messages($code));
50 | static::assertTrue($error->has_errors());
51 | }
52 |
53 | public function testWithErrorAndCode()
54 | {
55 | $factory = $this->factoryProvider(Provider\Error::class);
56 | $error = $factory(['error' => 'Ahi!', 'code' => 'foo']);
57 |
58 | static::assertInstanceOf(\WP_Error::class, $error);
59 |
60 | static::assertSame('foo', $error->get_error_code());
61 | static::assertSame('Ahi!', $error->get_error_message());
62 | static::assertSame('Ahi!', $error->get_error_message('foo'));
63 | static::assertSame(['Ahi!'], $error->get_error_messages());
64 | static::assertSame(['Ahi!'], $error->get_error_messages('foo'));
65 | static::assertTrue($error->has_errors());
66 | }
67 |
68 | public function testAddError()
69 | {
70 | $factory = $this->factoryProvider(Provider\Error::class);
71 | $error = $factory();
72 |
73 | static::assertInstanceOf(\WP_Error::class, $error);
74 |
75 | static::assertFalse($error->has_errors());
76 |
77 | $error->add('foo', 'One');
78 | $error->add('foo', 'Two');
79 | $error->add('bar', 'Three', 'some data');
80 |
81 | static::assertSame('foo', $error->get_error_code());
82 | static::assertSame(['foo', 'bar'], $error->get_error_codes());
83 | static::assertSame('One', $error->get_error_message());
84 | static::assertSame('One', $error->get_error_message('foo'));
85 | static::assertSame('Three', $error->get_error_message('bar'));
86 | static::assertSame(['One', 'Two', 'Three'], $error->get_error_messages());
87 | static::assertSame(['One', 'Two'], $error->get_error_messages('foo'));
88 | static::assertSame(['Three'], $error->get_error_messages('bar'));
89 | static::assertNull($error->get_error_data('foo'));
90 | static::assertNull($error->get_error_data());
91 | static::assertSame('some data', $error->get_error_data('bar'));
92 |
93 | static::assertTrue($error->has_errors());
94 | }
95 |
96 | public function testAddErrorData()
97 | {
98 | /** @var Provider\Error $factory */
99 | $factory = $this->factoryProvider(Provider\Error::class);
100 | $error = $factory();
101 |
102 | $error->add_data('Data before');
103 |
104 | static::assertSame('Data before', $error->get_error_data());
105 | static::assertSame('Data before', $error->get_error_data(''));
106 |
107 | $error->add('x', 'One');
108 |
109 | $error->add_data('Data after');
110 | $error->add_data('Data foo', 'foo');
111 |
112 | static::assertSame('Data after', $error->get_error_data());
113 | static::assertSame('Data after', $error->get_error_data(''));
114 | static::assertSame('Data after', $error->get_error_data('x'));
115 | static::assertSame('Data foo', $error->get_error_data('foo'));
116 | }
117 |
118 | public function testRemove()
119 | {
120 | /** @var Provider\Error $factory */
121 | $factory = $this->factoryProvider(Provider\Error::class);
122 | $error = $factory();
123 |
124 | $error->add('code', 'msg', 'data');
125 |
126 | static::assertSame('code', $error->get_error_code());
127 | static::assertSame('msg', $error->get_error_message());
128 | static::assertSame('data', $error->get_error_data());
129 |
130 | $error->remove('code');
131 |
132 | static::assertSame('', $error->get_error_code());
133 | static::assertSame('', $error->get_error_message());
134 | static::assertNull($error->get_error_data());
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/tests/cases/unit/Provider/PostTest.php:
--------------------------------------------------------------------------------
1 | factoryProvider(Provider\Post::class);
25 | $post = $factory();
26 |
27 | static::assertInstanceOf(\WP_Post::class, $post);
28 |
29 | static::assertIsInt($post->ID);
30 | static::assertGreaterThanOrEqual(1, $post->ID);
31 | static::assertIsNumeric($post->post_author);
32 | static::assertGreaterThanOrEqual(1, (int)$post->post_author);
33 | static::assertInstanceOf(\DateTime::class, $this->dateByMySql($post->post_date));
34 | static::assertInstanceOf(\DateTime::class, $this->dateByMySql($post->post_date_gmt));
35 | static::assertIsString($post->post_content);
36 | static::assertIsString($post->post_title);
37 | static::assertIsString($post->post_excerpt);
38 | static::assertContains($post->post_status, ['publish', 'draft', 'future']);
39 | static::assertContains($post->comment_status, ['open', 'closed']);
40 | static::assertContains($post->ping_status, ['open', 'closed']);
41 | static::assertIsString($post->post_password);
42 | static::assertIsString($post->post_name);
43 | static::assertSame('', $post->to_ping);
44 | static::assertSame('', $post->pinged);
45 | static::assertInstanceOf(\DateTime::class, $this->dateByMySql($post->post_modified));
46 | static::assertInstanceOf(\DateTime::class, $this->dateByMySql($post->post_modified_gmt));
47 | static::assertIsString($post->post_content_filtered);
48 | static::assertSame($post->post_content_filtered, trim(strip_tags($post->post_content)));
49 | static::assertIsInt($post->post_parent);
50 | static::assertGreaterThanOrEqual(0, $post->post_parent);
51 | static::assertTrue((bool)filter_var($post->guid, FILTER_VALIDATE_URL));
52 | static::assertIsInt($post->menu_order);
53 | static::assertGreaterThanOrEqual(0, $post->menu_order);
54 | static::assertContains($post->post_type, ['post', 'page']);
55 | static::assertSame('', $post->post_mime_type);
56 | static::assertSame('0', $post->comment_count);
57 | static::assertContains($post->filter, ['raw', null]);
58 | static::assertSame([], $post->ancestors);
59 | static::assertSame('', $post->page_template);
60 | static::assertSame([], $post->post_category);
61 | static::assertSame([], $post->tags_input);
62 |
63 | $expectedArray = [
64 | 'ID' => $post->ID,
65 | 'post_author' => $post->post_author,
66 | 'post_date' => $post->post_date,
67 | 'post_date_gmt' => $post->post_date_gmt,
68 | 'post_content' => $post->post_content,
69 | 'post_title' => $post->post_title,
70 | 'post_excerpt' => $post->post_excerpt,
71 | 'post_status' => $post->post_status,
72 | 'comment_status' => $post->comment_status,
73 | 'ping_status' => $post->ping_status,
74 | 'post_password' => $post->post_password,
75 | 'post_name' => $post->post_name,
76 | 'to_ping' => $post->to_ping,
77 | 'pinged' => $post->pinged,
78 | 'post_modified' => $post->post_modified,
79 | 'post_modified_gmt' => $post->post_modified_gmt,
80 | 'post_content_filtered' => $post->post_content_filtered,
81 | 'post_parent' => $post->post_parent,
82 | 'guid' => $post->guid,
83 | 'menu_order' => $post->menu_order,
84 | 'post_type' => $post->post_type,
85 | 'post_mime_type' => $post->post_mime_type,
86 | 'comment_count' => $post->comment_count,
87 | 'filter' => $post->filter,
88 | 'ancestors' => $post->ancestors,
89 | 'page_template' => $post->page_template,
90 | 'post_category' => $post->post_category,
91 | 'tags_input' => $post->tags_input,
92 | ];
93 |
94 | $actualArray = $post->to_array();
95 |
96 | ksort($expectedArray);
97 | ksort($actualArray);
98 |
99 | static::assertSame($expectedArray, $actualArray);
100 |
101 | static::assertSame($post->to_array(), get_post($post->ID)->to_array());
102 | static::assertSame($post->to_array(), get_post((string)$post->ID)->to_array());
103 | static::assertSame($post->to_array(), get_post($post)->to_array());
104 |
105 | foreach ($expectedArray as $key => $value) {
106 | static::assertSame($value ?? '', get_post_field($key, $post->ID));
107 | static::assertSame($value ?? '', get_post_field($key, $post));
108 | }
109 | }
110 |
111 | public function testCreateWithId()
112 | {
113 | $factory = $this->factoryProvider(Provider\Post::class);
114 | $post = $factory(['id' => 123]);
115 |
116 | static::assertSame(123, $post->ID);
117 | }
118 |
119 | public function testCreateWithAttachmentType()
120 | {
121 | $factory = $this->factoryProvider(Provider\Post::class);
122 | $post = $factory(['type' => 'attachment']);
123 |
124 | static::assertSame('attachment', $post->post_type);
125 | static::assertTrue(in_array($post->post_mime_type, Provider\Post::MIME_TYPES, true));
126 | }
127 |
128 | public function testFuturePost()
129 | {
130 | $factory = $this->factoryProvider(Provider\Post::class);
131 | $post = $factory(['date' => '+1 year']);
132 |
133 | $gmt = new \DateTimeZone('GMT');
134 | $postDateGmt = \DateTime::createFromFormat('Y-m-d H:i:s', $post->post_date_gmt, $gmt);
135 |
136 | $compare = (new \DateTime('now', $gmt))->modify('+1 year')->modify('-1 day');
137 |
138 | static::assertSame('future', $post->post_status);
139 | static::assertGreaterThan($compare->getTimestamp(), $postDateGmt->getTimestamp());
140 | }
141 |
142 | public function testWithFixedDateTime()
143 | {
144 | $factory = $this->factoryProvider(Provider\Post::class);
145 |
146 | $gmt = new \DateTimeZone('GMT');
147 | $now = new \DateTime('now', $gmt);
148 |
149 | $post = $factory(['date_gmt' => $now]);
150 |
151 | $postDateGmt = \DateTime::createFromFormat('Y-m-d H:i:s', $post->post_date_gmt, $gmt);
152 |
153 | static::assertSame($now->getTimestamp(), $postDateGmt->getTimestamp());
154 | }
155 |
156 | public function testTrashedPost()
157 | {
158 | $factory = $this->factoryProvider(Provider\Post::class);
159 |
160 | $post = $factory(['status' => 'trash']);
161 |
162 | static::assertSame('trash', $post->post_status);
163 | }
164 |
165 | public function testFunctionWithMultipleObjects()
166 | {
167 | /** @var Provider\Post $factory */
168 | $factory = $this->factoryProvider(Provider\Post::class);
169 |
170 | $posts = [];
171 | for ($i = 0; $i < 100; $i++) {
172 | $posts[] = $factory();
173 | }
174 |
175 | /** @var \WP_Post $post */
176 | foreach ($posts as $post) {
177 | /** @var \WP_Post $compare */
178 | $compare = get_post($post->ID);
179 | static::assertSame($post->to_array(), $compare->to_array());
180 | }
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/tests/cases/unit/Provider/PostTypeTest.php:
--------------------------------------------------------------------------------
1 | factoryProvider(Provider\PostType::class);
23 | $type = $factory();
24 |
25 | static::assertInstanceOf(\WP_Post_Type::class, $type);
26 |
27 | static::assertArrayHasKey($type->name, Provider\PostType::BUILT_IN);
28 | static::assertIsString($type->label);
29 | static::assertTrue((bool)$type->label);
30 | static::assertInstanceOf(\stdClass::class, $type->labels);
31 | static::assertIsString($type->labels->name);
32 | static::assertIsString($type->description);
33 | static::assertIsBool($type->public);
34 | static::assertIsBool($type->hierarchical);
35 | static::assertIsBool($type->exclude_from_search);
36 | static::assertIsBool($type->publicly_queryable);
37 | static::assertIsBool($type->show_ui);
38 | static::assertIsBool($type->show_in_menu);
39 | static::assertIsBool($type->show_in_nav_menus);
40 | static::assertIsBool($type->show_in_admin_bar);
41 | static::assertTrue(is_int($type->menu_position) || is_null($type->menu_position));
42 | static::assertNull($type->menu_icon);
43 | static::assertIsString($type->capability_type);
44 | static::assertIsBool($type->map_meta_cap);
45 | static::assertNull($type->register_meta_box_cb);
46 | static::assertIsArray($type->taxonomies);
47 | static::assertIsBool($type->has_archive);
48 | static::assertTrue(is_bool($type->query_var) || is_string($type->query_var));
49 | static::assertIsBool($type->can_export);
50 | static::assertTrue(is_bool($type->delete_with_user) || is_null($type->delete_with_user));
51 | static::assertIsString($type->_edit_link);
52 | static::assertInstanceOf(\stdClass::class, $type->cap);
53 | static::assertTrue(is_array($type->rewrite) || ($type->rewrite === false));
54 | static::assertIsBool($type->show_in_rest);
55 | static::assertTrue(is_string($type->rest_base) || is_bool($type->rest_base));
56 | static::assertTrue(
57 | is_string($type->rest_controller_class)
58 | || is_bool($type->rest_controller_class)
59 | );
60 |
61 | static::assertTrue($type->_builtin);
62 |
63 | static::assertInstanceOf(\WP_Post_Type::class, get_post_type_object($type->name));
64 | static::assertSame($type->name, get_post_type_object($type->name)->name);
65 | static::assertEquals($type->labels, get_post_type_object($type->name)->labels);
66 | static::assertEquals($type->cap, get_post_type_object($type->name)->cap);
67 |
68 | static::assertTrue(post_type_exists($type->name));
69 | }
70 |
71 | public function testWithBuiltInType()
72 | {
73 | $factory = $this->factoryProvider(Provider\PostType::class);
74 | $type = $factory(['name' => 'page']);
75 |
76 | static::assertSame('Pages', $type->label);
77 | static::assertSame('Page', $type->labels->singular_name);
78 | static::assertTrue($type->hierarchical);
79 | static::assertTrue($type->_builtin);
80 | }
81 |
82 | public function testWithNameAndHierarchical()
83 | {
84 | $factory = $this->factoryProvider(Provider\PostType::class);
85 | $type = $factory(['name' => 'foo', 'hierarchical' => true, 'labels' => ['name' => 'Foo']]);
86 |
87 | static::assertSame('Foo', $type->label);
88 | static::assertSame('Foo', $type->labels->name);
89 | static::assertSame('Page', $type->labels->singular_name);
90 | static::assertTrue($type->hierarchical);
91 | static::assertFalse($type->_builtin);
92 | }
93 |
94 | public function testWithNameAndLabel()
95 | {
96 | $factory = $this->factoryProvider(Provider\PostType::class);
97 | $type = $factory(['name' => 'bar', 'label' => 'Bar']);
98 |
99 | static::assertSame('Bar', $type->label);
100 | static::assertSame('Bar', $type->labels->name);
101 | static::assertSame('Post', $type->labels->singular_name);
102 | static::assertFalse($type->hierarchical);
103 | static::assertFalse($type->_builtin);
104 | }
105 |
106 | public function testWithNameAndLabelAndCap()
107 | {
108 | $factory = $this->factoryProvider(Provider\PostType::class);
109 | $type = $factory(
110 | [
111 | 'name' => 'product',
112 | 'label' => 'Product',
113 | 'cap' => ['edit_post' => 'edit_product'],
114 | ]
115 | );
116 |
117 | static::assertSame('Product', $type->label);
118 | static::assertSame('Product', $type->labels->name);
119 | static::assertSame('Post', $type->labels->singular_name);
120 | static::assertSame('edit_product', $type->cap->edit_post);
121 | static::assertSame('publish_posts', $type->cap->publish_posts);
122 | static::assertSame('edit_posts', $type->cap->create_posts);
123 | static::assertFalse($type->hierarchical);
124 | static::assertFalse($type->_builtin);
125 | }
126 |
127 | public function testWithPublic()
128 | {
129 | $factory = $this->factoryProvider(Provider\PostType::class);
130 | $type = $factory(['name' => 'product', 'label' => 'Product', 'public' => true]);
131 |
132 | static::assertSame('Product', $type->label);
133 | static::assertSame('Product', $type->labels->name);
134 | static::assertFalse($type->exclude_from_search);
135 | static::assertTrue($type->show_in_admin_bar);
136 | static::assertTrue($type->show_in_menu);
137 | static::assertTrue($type->show_in_nav_menus);
138 | static::assertTrue($type->show_in_rest);
139 | static::assertTrue($type->show_ui);
140 | static::assertFalse($type->_builtin);
141 | }
142 |
143 | public function testFunctionWithMultipleObjects()
144 | {
145 | $factory = $this->factoryProvider(Provider\PostType::class);
146 |
147 | $types = [];
148 | for ($i = 0; $i < 100; $i++) {
149 | $types[] = $factory();
150 | }
151 |
152 | /** @var \WP_Post_Type $type */
153 | foreach ($types as $type) {
154 | /** @var \WP_Post_Type $compare */
155 | $compare = get_post_type_object($type->name);
156 | static::assertInstanceOf(\WP_Post_Type::class, $compare);
157 | static::assertSame($type->name, $compare->name);
158 | static::assertSame($type->label, $compare->label);
159 | static::assertSame($type->query_var, $compare->query_var);
160 | static::assertEquals($type->labels, $compare->labels);
161 | static::assertEquals($type->cap, $compare->cap);
162 | }
163 | }
164 |
165 | public function testUnicityUpToPossible()
166 | {
167 | $factory = $this->factoryProvider(Provider\PostType::class);
168 |
169 | $names = [];
170 | for ($i = 0; $i < count(Provider\PostType::BUILT_IN); $i++) {
171 | $names[] = $factory()->name;
172 | }
173 |
174 | static::assertSame($names, array_unique($names));
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/tests/cases/unit/Provider/SiteTest.php:
--------------------------------------------------------------------------------
1 | factoryProvider(Provider\Site::class);
27 | $site = $factory();
28 |
29 | static::assertInstanceOf(\WP_Site::class, $site);
30 |
31 | static::assertIsString($site->blog_id);
32 | static::assertIsNumeric($site->blog_id);
33 | static::assertGreaterThanOrEqual(1, (int)$site->blog_id);
34 | static::assertIsString($site->domain);
35 | static::assertIsString($site->path);
36 | static::assertIsString($site->site_id);
37 | static::assertIsNumeric($site->site_id);
38 | static::assertGreaterThanOrEqual(1, (int)$site->site_id);
39 | static::assertInstanceOf(\DateTime::class, $this->dateByMySql($site->registered));
40 | static::assertInstanceOf(\DateTime::class, $this->dateByMySql($site->last_updated));
41 | static::assertIsString($site->public);
42 | static::assertIsNumeric($site->public);
43 | static::assertContains($site->public, ['0', '1']);
44 | static::assertIsString($site->archived);
45 | static::assertIsNumeric($site->archived);
46 | static::assertContains($site->archived, ['0', '1']);
47 | static::assertIsString($site->mature);
48 | static::assertIsNumeric($site->mature);
49 | static::assertContains($site->mature, ['0', '1']);
50 | static::assertIsString($site->spam);
51 | static::assertIsNumeric($site->spam);
52 | static::assertContains($site->spam, ['0', '1']);
53 | static::assertIsString($site->deleted);
54 | static::assertIsNumeric($site->deleted);
55 | static::assertContains($site->deleted, ['0', '1']);
56 | static::assertIsString($site->lang_id);
57 | static::assertIsNumeric($site->lang_id);
58 | static::assertContains($site->lang_id, ['0', '1']);
59 |
60 | $expectedArray = [
61 | 'blog_id' => $site->blog_id,
62 | 'domain' => $site->domain,
63 | 'path' => $site->path,
64 | 'site_id' => $site->site_id,
65 | 'registered' => $site->registered,
66 | 'last_updated' => $site->last_updated,
67 | 'public' => $site->public,
68 | 'archived' => $site->archived,
69 | 'mature' => $site->mature,
70 | 'spam' => $site->spam,
71 | 'deleted' => $site->deleted,
72 | 'lang_id' => $site->lang_id,
73 | ];
74 |
75 | $actualArray = $site->to_array();
76 |
77 | ksort($expectedArray);
78 | ksort($actualArray);
79 |
80 | static::assertSame($expectedArray, $actualArray);
81 | static::assertSame($site->blog_id, $site->id);
82 | static::assertSame($site->site_id, $site->network_id);
83 | static::assertIsString($site->blogname);
84 | static::assertTrue((bool)filter_var($site->siteurl, FILTER_VALIDATE_URL));
85 | static::assertTrue((bool)filter_var($site->home, FILTER_VALIDATE_URL));
86 | static::assertIsInt($site->post_count);
87 | static::assertGreaterThan(0, $site->post_count);
88 |
89 | static::assertInstanceOf(\WP_Site::class, get_site($site->blog_id));
90 | static::assertInstanceOf(\WP_Site::class, get_site((int)$site->blog_id));
91 | static::assertSame($site->to_array(), get_site($site->blog_id)->to_array());
92 | static::assertSame($site->to_array(), get_site((int)$site->blog_id)->to_array());
93 | }
94 |
95 | public function testWithGivenId()
96 | {
97 | /** @var Provider\Site $factory */
98 | $factory = $this->factoryProvider(Provider\Site::class);
99 | $site = $factory(['id' => 123]);
100 |
101 | static::assertSame('123', $site->blog_id);
102 | static::assertSame('123', $site->id);
103 | }
104 |
105 | public function testWithGivenUrl()
106 | {
107 | /** @var Provider\Site $factory */
108 | $factory = $this->factoryProvider(Provider\Site::class);
109 | $site = $factory(['url' => 'example.com/blog/']);
110 |
111 | static::assertSame('http://example.com/blog/', $site->home);
112 | static::assertSame('http://example.com/blog/', $site->siteurl);
113 | static::assertSame('/blog', $site->path);
114 | }
115 |
116 | public function testFunctionsWithMultipleObjects()
117 | {
118 | /** @var Provider\Site $factory */
119 | $factory = $this->factoryProvider(Provider\Site::class);
120 |
121 | $sites = [];
122 | for ($i = 0; $i < 100; $i++) {
123 | $sites[] = $factory();
124 | }
125 |
126 | /** @var \WP_Site $site */
127 | foreach ($sites as $site) {
128 | static::assertInstanceOf(\WP_Site::class, get_site($site->blog_id));
129 | static::assertSame($site->to_array(), get_site($site->blog_id)->to_array());
130 | }
131 | }
132 |
133 | /**
134 | * @runInSeparateProcess
135 | */
136 | public function testDoesNotCreateOnSingleSite()
137 | {
138 | Monkey\Functions\when('is_multisite')->justReturn(false);
139 |
140 | $this->expectExceptionMessageRegExp('/multisite/');
141 | $this->factoryProvider(Provider\Site::class)();
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/tests/cases/unit/Provider/TaxonomyTest.php:
--------------------------------------------------------------------------------
1 | factoryProvider(Provider\Taxonomy::class);
23 | $taxonomy = $factory();
24 |
25 | static::assertInstanceOf(\WP_Taxonomy::class, $taxonomy);
26 |
27 | static::assertArrayHasKey($taxonomy->name, Provider\Taxonomy::BUILT_IN);
28 | static::assertIsString($taxonomy->label);
29 | static::assertInstanceOf(\stdClass::class, $taxonomy->labels);
30 | static::assertIsString($taxonomy->labels->name);
31 | static::assertIsString($taxonomy->description);
32 | static::assertIsBool($taxonomy->public);
33 | static::assertIsBool($taxonomy->publicly_queryable);
34 | static::assertIsBool($taxonomy->hierarchical);
35 | static::assertIsBool($taxonomy->show_ui);
36 | static::assertIsBool($taxonomy->show_in_menu);
37 | static::assertIsBool($taxonomy->show_in_nav_menus);
38 | static::assertIsBool($taxonomy->show_tagcloud);
39 | static::assertIsBool($taxonomy->show_in_quick_edit);
40 | static::assertIsBool($taxonomy->show_in_quick_edit);
41 | static::assertIsBool($taxonomy->show_admin_column);
42 | static::assertIsBool($taxonomy->show_in_rest);
43 | static::assertIsArray($taxonomy->object_type);
44 | static::assertInstanceOf(\stdClass::class, $taxonomy->cap);
45 | static::assertIsString($taxonomy->cap->manage_terms);
46 | static::assertTrue(is_array($taxonomy->rewrite) || $taxonomy->rewrite === false);
47 | static::assertTrue(is_string($taxonomy->query_var) || $taxonomy->query_var === false);
48 | static::assertTrue(is_string($taxonomy->rest_base) || is_bool($taxonomy->rest_base));
49 |
50 | $controller = $taxonomy->rest_controller_class;
51 | static::assertTrue(is_string($controller) || is_bool($controller));
52 |
53 | // phpcs:disable Inpsyde.CodeQuality.VariablesName.SnakeCaseVar
54 | $boxCb = $taxonomy->meta_box_cb;
55 | $cb_esc = $taxonomy->meta_box_sanitize_cb;
56 | $cb_upd = $taxonomy->update_count_callback;
57 | static::assertTrue(is_null($boxCb) || is_bool($boxCb) || is_callable($boxCb, true));
58 | static::assertTrue(is_null($cb_esc) || is_callable($cb_esc, true));
59 | static::assertTrue(is_null($cb_upd) || is_callable($cb_upd, true));
60 | // phpcs:enable Inpsyde.CodeQuality.VariablesName.SnakeCaseVar
61 |
62 | static::assertTrue($taxonomy->_builtin);
63 | static::assertInstanceOf(\WP_Taxonomy::class, get_taxonomy($taxonomy->name));
64 | static::assertSame($taxonomy->name, get_taxonomy($taxonomy->name)->name);
65 | static::assertEquals($taxonomy->labels, get_taxonomy($taxonomy->name)->labels);
66 | static::assertEquals($taxonomy->cap, get_taxonomy($taxonomy->name)->cap);
67 | static::assertSame($taxonomy->rewrite, get_taxonomy($taxonomy->name)->rewrite);
68 | static::assertTrue(taxonomy_exists($taxonomy->name));
69 | }
70 |
71 | public function testWithBuiltInType()
72 | {
73 | $factory = $this->factoryProvider(Provider\Taxonomy::class);
74 | $type = $factory(['name' => 'category']);
75 |
76 | static::assertSame('Categories', $type->label);
77 | static::assertSame('Category', $type->labels->singular_name);
78 | static::assertTrue($type->hierarchical);
79 | static::assertTrue($type->_builtin);
80 | }
81 |
82 | public function testWithNameAndHierarchical()
83 | {
84 | $factory = $this->factoryProvider(Provider\Taxonomy::class);
85 | $tax = $factory(['name' => 'foo', 'hierarchical' => true, 'labels' => ['name' => 'Foo']]);
86 |
87 | static::assertSame('Foo', $tax->label);
88 | static::assertSame('Foo', $tax->labels->name);
89 | static::assertSame('Category', $tax->labels->singular_name);
90 | static::assertTrue($tax->hierarchical);
91 | static::assertFalse($tax->_builtin);
92 | }
93 |
94 | public function testWithNameAndLabel()
95 | {
96 | $factory = $this->factoryProvider(Provider\Taxonomy::class);
97 | $type = $factory(['name' => 'bar', 'label' => 'Bar']);
98 |
99 | static::assertSame('Bar', $type->label);
100 | static::assertSame('Bar', $type->labels->name);
101 | static::assertSame('Tag', $type->labels->singular_name);
102 | static::assertFalse($type->hierarchical);
103 | static::assertFalse($type->_builtin);
104 | }
105 |
106 | public function testWithNameAndLabelAndCap()
107 | {
108 | $factory = $this->factoryProvider(Provider\Taxonomy::class);
109 | $type = $factory(
110 | [
111 | 'name' => 'product',
112 | 'label' => 'Product',
113 | 'cap' => ['manage_terms' => 'manage_products'],
114 | ]
115 | );
116 |
117 | static::assertSame('Product', $type->label);
118 | static::assertSame('Product', $type->labels->name);
119 | static::assertSame('Tag', $type->labels->singular_name);
120 | static::assertSame('manage_products', $type->cap->manage_terms);
121 | static::assertSame('assign_post_tags', $type->cap->assign_terms);
122 | static::assertFalse($type->hierarchical);
123 | static::assertFalse($type->_builtin);
124 | }
125 |
126 | public function testWithPublic()
127 | {
128 | /** @var Provider\Taxonomy $factory */
129 | $factory = $this->factoryProvider(Provider\Taxonomy::class);
130 | $tax = $factory(['name' => 'product', 'label' => 'Product', 'public' => true]);
131 |
132 | static::assertSame('Product', $tax->label);
133 | static::assertSame('Product', $tax->labels->name);
134 | static::assertTrue($tax->public);
135 | static::assertTrue($tax->publicly_queryable);
136 | static::assertTrue($tax->show_in_menu);
137 | static::assertTrue($tax->show_in_nav_menus);
138 | static::assertTrue($tax->show_in_rest);
139 | static::assertTrue($tax->show_ui);
140 | static::assertFalse($tax->_builtin);
141 | }
142 |
143 | public function testFunctionWithMultipleObjects()
144 | {
145 | /** @var Provider\Taxonomy $factory */
146 | $factory = $this->factoryProvider(Provider\Taxonomy::class);
147 |
148 | $taxonomies = [];
149 | for ($i = 0; $i < 50; $i++) {
150 | $taxonomies[] = $factory();
151 | }
152 |
153 | /** @var \WP_Taxonomy $taxonomy */
154 | foreach ($taxonomies as $taxonomy) {
155 | /** @var \WP_Taxonomy $compare */
156 | $compare = get_taxonomy($taxonomy->name);
157 | static::assertInstanceOf(\WP_Taxonomy::class, $compare);
158 | static::assertSame($taxonomy->name, $compare->name);
159 | static::assertSame($taxonomy->label, $compare->label);
160 | static::assertSame($taxonomy->rewrite, $compare->rewrite);
161 | static::assertSame($taxonomy->description, $compare->description);
162 | static::assertEquals($taxonomy->labels, $compare->labels);
163 | static::assertEquals($taxonomy->cap, $compare->cap);
164 | }
165 | }
166 |
167 | public function testUnicityUpToPossible()
168 | {
169 | /** @var Provider\Taxonomy $factory */
170 | $factory = $this->factoryProvider(Provider\Taxonomy::class);
171 |
172 | $names = [];
173 | for ($i = 0; $i < count(Provider\Taxonomy::BUILT_IN); $i++) {
174 | $names[] = $factory()->name;
175 | }
176 |
177 | static::assertSame($names, array_unique($names));
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/tests/cases/unit/Provider/TermTest.php:
--------------------------------------------------------------------------------
1 | factoryProvider(Provider\Term::class);
26 | $term = $factory();
27 |
28 | static::assertInstanceOf(\WP_Term::class, $term);
29 |
30 | static::assertIsInt($term->term_id);
31 | static::assertGreaterThanOrEqual(1, $term->term_id);
32 | static::assertIsInt($term->term_taxonomy_id);
33 | static::assertGreaterThanOrEqual(1, $term->term_taxonomy_id);
34 | static::assertIsString($term->name);
35 | static::assertIsString($term->slug);
36 | static::assertSame('', $term->term_group);
37 | static::assertArrayHasKey($term->taxonomy, Provider\Taxonomy::BUILT_IN);
38 | static::assertIsString($term->description);
39 | static::assertIsInt($term->parent);
40 | static::assertGreaterThanOrEqual(0, $term->parent);
41 | static::assertIsInt($term->count);
42 | static::assertGreaterThanOrEqual(0, $term->count);
43 | static::assertContains($term->filter, ['raw', null]);
44 | static::assertInstanceOf(\stdClass::class, $term->data);
45 | static::assertSame($term->term_id, $term->data->term_id);
46 |
47 | $expectedArray = [
48 | 'term_id' => $term->term_id,
49 | 'term_taxonomy_id' => $term->term_taxonomy_id,
50 | 'name' => $term->name,
51 | 'slug' => $term->slug,
52 | 'term_group' => $term->term_group,
53 | 'taxonomy' => $term->taxonomy,
54 | 'description' => $term->description,
55 | 'parent' => $term->parent,
56 | 'count' => $term->count,
57 | 'filter' => $term->filter,
58 | ];
59 |
60 | $actualArray = $term->to_array();
61 | $arr = $actualArray;
62 |
63 | ksort($expectedArray);
64 | ksort($actualArray);
65 |
66 | static::assertSame($expectedArray, $actualArray);
67 |
68 | $id = $term->term_id;
69 | $ttId = $term->term_taxonomy_id;
70 | $tax = $term->taxonomy;
71 |
72 | static::assertSame($arr, get_term($id, $tax)->to_array());
73 | static::assertSame($arr, get_term((string)$id, $tax)->to_array());
74 | static::assertSame($arr, get_term_by('slug', $term->slug, $tax)->to_array());
75 | static::assertSame($arr, get_term_by('slug', $term->name, $tax)->to_array());
76 | static::assertSame($arr, get_term_by('name', $term->name, $tax)->to_array());
77 | static::assertSame($arr, get_term_by('id', $id, $tax)->to_array());
78 | static::assertSame($arr, get_term_by('term_taxonomy_id', $ttId, $tax)->to_array());
79 | static::assertSame($arr, get_term_by('term_taxonomy_id', (string)$ttId, $tax)->to_array());
80 | static::assertSame($arr, get_term_by('term_taxonomy_id', $ttId)->to_array());
81 | static::assertSame($arr, get_term_by('term_taxonomy_id', (string)$ttId)->to_array());
82 | static::assertFalse(get_term_by('slug', $term->slug));
83 | static::assertFalse(get_term_by('name', $term->name));
84 | static::assertFalse(get_term_by('name', $term->slug, $tax));
85 | }
86 |
87 | public function testCreateWithFixedId()
88 | {
89 | /** @var Provider\Term $factory */
90 | $factory = $this->factoryProvider(Provider\Term::class);
91 | $term = $factory(['id' => 123]);
92 |
93 | static::assertInstanceOf(\WP_Term::class, $term);
94 | static::assertSame(123, $term->term_id);
95 | static::assertSame(123, $term->term_taxonomy_id);
96 | }
97 |
98 | public function testCreateWithFixedIdAndTermTaxId()
99 | {
100 | /** @var Provider\Term $factory */
101 | $factory = $this->factoryProvider(Provider\Term::class);
102 | $term = $factory(['id' => 123, 'tt_id' => 456]);
103 |
104 | static::assertInstanceOf(\WP_Term::class, $term);
105 | static::assertSame(123, $term->term_id);
106 | static::assertSame(456, $term->term_taxonomy_id);
107 | }
108 |
109 | public function testCreateWithFixedTaxonomy()
110 | {
111 | /** @var Provider\Term $factory */
112 | $factory = $this->factoryProvider(Provider\Term::class);
113 | $term = $factory(['taxonomy' => 'category']);
114 |
115 | static::assertSame('category', $term->taxonomy);
116 | }
117 |
118 | public function testIdUniqueness()
119 | {
120 | /** @var Provider\Term $factory */
121 | $factory = $this->factoryProvider(Provider\Term::class);
122 |
123 | $ids = [];
124 | for ($i = 0; $i < 200; $i++) {
125 | $ids[] = $factory()->term_id;
126 | }
127 |
128 | static::assertSame($ids, array_unique($ids));
129 | }
130 |
131 | public function testFunctionsForManyTerms()
132 | {
133 | /** @var Provider\Term $factory */
134 | $factory = $this->factoryProvider(Provider\Term::class);
135 |
136 | $terms = [];
137 | for ($i = 0; $i < 1000; $i++) {
138 | $terms[] = $factory();
139 | }
140 |
141 | $ids = [];
142 | /** @var \WP_Term $term */
143 | foreach ($terms as $term) {
144 | $ids[] = $term->term_id;
145 | $arr = $term->to_array();
146 | $tax = $term->taxonomy;
147 | $ttId = $term->term_taxonomy_id;
148 |
149 | static::assertSame($arr, get_term($term->term_id, $tax)->to_array());
150 | static::assertSame($arr, get_term_by('slug', $term->slug, $tax)->to_array());
151 | static::assertSame($arr, get_term_by('name', $term->name, $tax)->to_array());
152 | static::assertSame($arr, get_term_by('id', $term->term_id, $tax)->to_array());
153 | static::assertSame($arr, get_term_by('term_taxonomy_id', $ttId, $tax)->to_array());
154 | static::assertSame($arr, get_term_by('term_taxonomy_id', $ttId)->to_array());
155 | }
156 |
157 | $badId = (int)(max($ids) + 1);
158 | static::assertNull(get_term($badId));
159 | static::assertFalse(get_term_by('id', $badId));
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/tests/cases/unit/Provider/UserTest.php:
--------------------------------------------------------------------------------
1 | factoryProvider(Provider\User::class);
27 | $user = $factory();
28 |
29 | static::assertInstanceOf(\WP_User::class, $user);
30 |
31 | static::assertIsInt($user->ID);
32 | static::assertGreaterThan(1, $user->ID);
33 | static::assertInstanceOf(\stdClass::class, $user->data);
34 | static::assertSame($user->ID, $user->data->ID);
35 | static::assertIsArray($user->caps);
36 | static::assertIsString($user->cap_key);
37 | static::assertIsArray($user->roles);
38 | static::assertIsArray($user->allcaps);
39 | static::assertContains($user->filter, ['raw', null]);
40 |
41 | static::assertIsString($user->user_login);
42 | static::assertIsString($user->user_pass);
43 | static::assertIsString($user->user_nicename);
44 | static::assertTrue((bool)filter_var($user->user_email, FILTER_VALIDATE_EMAIL));
45 | static::assertTrue((bool)filter_var($user->user_url, FILTER_VALIDATE_URL));
46 | static::assertInstanceOf(\DateTime::class, $this->dateByMySql($user->user_registered));
47 | static::assertIsString($user->user_activation_key);
48 | static::assertIsString($user->user_status);
49 | static::assertIsNumeric($user->user_status);
50 | static::assertIsString($user->display_name);
51 |
52 | static::assertIsString($user->user_description);
53 | static::assertSame($user->user_description, $user->description);
54 | static::assertIsString($user->user_firstname);
55 | static::assertSame($user->user_firstname, $user->first_name);
56 | static::assertIsString($user->user_lastname);
57 | static::assertSame($user->user_lastname, $user->last_name);
58 | static::assertIsInt($user->user_level);
59 | static::assertIsString($user->nickname);
60 | static::assertIsString($user->spam);
61 | static::assertIsString($user->deleted);
62 | static::assertIsString($user->locale);
63 | static::assertContains($user->rich_editing, ['true', 'false']);
64 | static::assertContains($user->syntax_highlighting, ['true', 'false']);
65 |
66 | $expectedArray = [
67 | 'ID' => $user->ID,
68 | 'user_login' => $user->user_login,
69 | 'user_pass' => $user->user_pass,
70 | 'user_nicename' => $user->user_nicename,
71 | 'user_email' => $user->user_email,
72 | 'user_url' => $user->user_url,
73 | 'user_registered' => $user->user_registered,
74 | 'user_activation_key' => $user->user_activation_key,
75 | 'user_status' => $user->user_status,
76 | 'display_name' => $user->display_name,
77 | ];
78 |
79 | $actualArray = $user->to_array();
80 |
81 | ksort($expectedArray);
82 | ksort($actualArray);
83 |
84 | static::assertSame($expectedArray, $actualArray);
85 |
86 | static::assertIsInt($user->get_site_id());
87 | static::assertGreaterThanOrEqual(1, $user->get_site_id());
88 | }
89 |
90 | public function testGet()
91 | {
92 | $keys = [
93 | 'ID',
94 | 'user_login',
95 | 'user_pass',
96 | 'user_nicename',
97 | 'user_email',
98 | 'user_url',
99 | 'user_registered',
100 | 'user_activation_key',
101 | 'user_status',
102 | 'user_description',
103 | 'description',
104 | 'user_firstname',
105 | 'first_name',
106 | 'user_lastname',
107 | 'last_name',
108 | 'user_level',
109 | 'nickname',
110 | 'spam',
111 | 'deleted',
112 | 'locale',
113 | 'rich_editing',
114 | 'syntax_highlighting',
115 | ];
116 |
117 | /** @var Provider\User $factory */
118 | $factory = $this->factoryProvider(Provider\User::class);
119 | $user = $factory();
120 |
121 | foreach ($keys as $key) {
122 | $value = $user->get($key);
123 | static::assertSame((string)$user->{$key}, $value);
124 | }
125 | }
126 |
127 | public function testFunctions()
128 | {
129 | /** @var Provider\User $factory */
130 | $factory = $this->factoryProvider(Provider\User::class);
131 | $user = $factory();
132 |
133 | $this->compareUser($user, get_userdata($user->ID));
134 | $this->compareUser($user, get_user_by('ID', $user->ID));
135 | $this->compareUser($user, get_user_by('id', $user->ID));
136 | $this->compareUser($user, get_user_by('ID', (string)$user->ID));
137 | $this->compareUser($user, get_user_by('id', (string)$user->ID));
138 | $this->compareUser($user, get_user_by('slug', $user->user_nicename));
139 | $this->compareUser($user, get_user_by('email', $user->user_email));
140 | $this->compareUser($user, get_user_by('login', $user->user_login));
141 |
142 | static::assertFalse(get_userdata($user->ID + 1));
143 | static::assertFalse(get_user_by('id', $user->ID + 1));
144 | static::assertFalse(get_user_by('slug', 'x' . $user->user_nicename));
145 | static::assertFalse(get_user_by('email', $user->user_email . 'x'));
146 | static::assertFalse(get_user_by('login', 'x' . $user->user_login));
147 | static::assertFalse(get_user_by('login ', $user->user_login));
148 | }
149 |
150 | public function testFunctionsForManyUsers()
151 | {
152 | /** @var Provider\User $factory */
153 | $factory = $this->factoryProvider(Provider\User::class);
154 |
155 | $users = [];
156 | for ($i = 0; $i < 1000; $i++) {
157 | $users[] = $factory();
158 | }
159 |
160 | $ids = [];
161 | /** @var \WP_User $user */
162 | foreach ($users as $user) {
163 | $ids[] = $user->ID;
164 | $this->compareUser($user, get_userdata($user->ID));
165 | $this->compareUser($user, get_user_by('slug', $user->user_nicename));
166 | }
167 |
168 | $badId = (int)(max($ids) + 1);
169 | static::assertFalse(get_userdata($badId));
170 | }
171 |
172 | public function testFixedData()
173 | {
174 | /** @var Provider\User $factory */
175 | $factory = $this->factoryProvider(Provider\User::class);
176 | $user = $factory(
177 | [
178 | 'id' => 123,
179 | 'login' => 'itsme',
180 | 'email' => 'me@example.com',
181 | 'password' => 's3cr3t',
182 | ]
183 | );
184 |
185 | static::assertSame(123, $user->ID);
186 | static::assertSame('itsme', $user->user_login);
187 | static::assertSame('me@example.com', $user->user_email);
188 | static::assertSame('s3cr3t', $user->user_pass);
189 | }
190 |
191 | public function testFixedRole()
192 | {
193 | /** @var Provider\User $factory */
194 | $factory = $this->factoryProvider(Provider\User::class);
195 | $user = $factory(['role' => 'editor']);
196 |
197 | static::assertSame(['editor'], $user->roles);
198 | static::assertTrue($user->caps['editor']);
199 | static::assertSame(7, $user->user_level);
200 | static::assertTrue($user->allcaps['level_7']);
201 | static::assertTrue($user->allcaps['level_6']);
202 | static::assertTrue($user->allcaps['level_5']);
203 | static::assertTrue($user->allcaps['level_4']);
204 | static::assertTrue($user->allcaps['level_3']);
205 | static::assertTrue($user->allcaps['level_2']);
206 | static::assertTrue($user->allcaps['level_1']);
207 | static::assertTrue($user->allcaps['level_0']);
208 | static::assertTrue($user->allcaps['manage_categories']);
209 |
210 | static::assertTrue($user->has_cap('editor'));
211 | static::assertTrue($user->has_cap('level_7'));
212 | static::assertTrue($user->has_cap('level_6'));
213 | static::assertTrue($user->has_cap('level_5'));
214 | static::assertTrue($user->has_cap('level_4'));
215 | static::assertTrue($user->has_cap('level_3'));
216 | static::assertTrue($user->has_cap('level_2'));
217 | static::assertTrue($user->has_cap('level_1'));
218 | static::assertTrue($user->has_cap('level_0'));
219 | static::assertTrue($user->has_cap('manage_categories'));
220 | static::assertFalse($user->has_cap('level_8'));
221 | static::assertFalse($user->has_cap('level_9'));
222 | static::assertFalse($user->has_cap('level_10'));
223 | static::assertFalse($user->has_cap('administrator'));
224 | static::assertFalse($user->has_cap('switch_themes'));
225 |
226 | static::assertTrue(user_can($user, 'manage_categories'));
227 | static::assertTrue(user_can($user->ID, 'editor'));
228 | static::assertFalse(user_can($user, 'administrator'));
229 | static::assertFalse(user_can($user->ID, 'switch_themes'));
230 | }
231 |
232 | public function testRoleByLevel()
233 | {
234 | /** @var Provider\User $factory */
235 | $factory = $this->factoryProvider(Provider\User::class);
236 | $user = $factory(['level' => 5]);
237 |
238 | static::assertSame(['author'], $user->roles);
239 | static::assertTrue($user->caps['author']);
240 | static::assertSame(5, $user->user_level);
241 | static::assertTrue($user->allcaps['level_5']);
242 | static::assertTrue($user->allcaps['level_4']);
243 | static::assertTrue($user->allcaps['level_3']);
244 | static::assertTrue($user->allcaps['level_2']);
245 | static::assertTrue($user->allcaps['level_1']);
246 | static::assertTrue($user->allcaps['level_0']);
247 | static::assertTrue($user->allcaps['upload_files']);
248 |
249 | static::assertTrue($user->has_cap('author'));
250 | static::assertTrue($user->has_cap('level_5'));
251 | static::assertTrue($user->has_cap('level_4'));
252 | static::assertTrue($user->has_cap('level_3'));
253 | static::assertTrue($user->has_cap('level_2'));
254 | static::assertTrue($user->has_cap('level_1'));
255 | static::assertTrue($user->has_cap('level_0'));
256 | static::assertTrue($user->has_cap('upload_files'));
257 | static::assertFalse($user->has_cap('level_6'));
258 | static::assertFalse($user->has_cap('level_7'));
259 | static::assertFalse($user->has_cap('level_8'));
260 | static::assertFalse($user->has_cap('level_9'));
261 | static::assertFalse($user->has_cap('level_10'));
262 | static::assertFalse($user->has_cap('editor'));
263 | static::assertFalse($user->has_cap('manage_categories'));
264 |
265 | static::assertTrue(user_can($user, 'upload_files'));
266 | static::assertTrue(user_can($user->ID, 'author'));
267 | static::assertTrue(user_can((string)$user->ID, 'level_5'));
268 | static::assertFalse(user_can($user, 'editor'));
269 | static::assertFalse(user_can($user->ID, 'manage_categories'));
270 | }
271 |
272 | public function testGetFailWithLowercaseId()
273 | {
274 | /** @var Provider\User $factory */
275 | $factory = $this->factoryProvider(Provider\User::class);
276 | $user = $factory();
277 |
278 | $this->expectExceptionMessageRegExp('/WP_User::ID/');
279 |
280 | $user->get('id');
281 | }
282 |
283 | public function testMakeUserCurrent()
284 | {
285 | Monkey\Functions\expect('wp_safe_redirect')->once();
286 |
287 | /** @var Provider\User $factory */
288 | $factory = $this->factoryProvider(Provider\User::class);
289 | $factory(['id' => 123, 'first_name' => 'Jane', 'role' => 'author'])->__monkeyMakeCurrent();
290 |
291 | $this->expectOutputString('Jane rocks!');
292 |
293 | $rocks = static function (\WP_User $user): \WP_User {
294 | if (array_intersect(['editor', 'author'], $user->roles)) {
295 | print "{$user->user_firstname} rocks!"; // phpcs:ignore
296 | }
297 |
298 | return $user;
299 | };
300 |
301 | if (get_current_user_id() === 123 && current_user_can('edit_published_posts')) {
302 | $user = $rocks(wp_get_current_user());
303 | if (filter_var($user->user_url, FILTER_VALIDATE_URL)) {
304 | wp_safe_redirect($user->user_url);
305 | }
306 | }
307 | }
308 |
309 | /**
310 | * @param \WP_User $left
311 | * @param \WP_User $right
312 | */
313 | private function compareUser(\WP_User $left, \WP_User $right): void
314 | {
315 | static::assertSame($left->to_array(), $right->to_array());
316 | static::assertSame($left->allcaps, $right->allcaps);
317 | static::assertSame($left->caps, $right->caps);
318 | static::assertSame($left->roles, $right->roles);
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/tests/cases/unit/ProvidersInitTest.php:
--------------------------------------------------------------------------------
1 | expectExceptionMessageRegExp('/initialized/');
24 |
25 | $provider = new Providers(Factory::create());
26 | $provider->wp();
27 | }
28 |
29 | public function testCallMethodRequiresInitialization()
30 | {
31 | $this->expectExceptionMessageRegExp('/initialized/');
32 |
33 | $provider = new Providers(Factory::create());
34 | /** @noinspection PhpUndefinedMethodInspection */
35 | $provider->test();
36 | }
37 |
38 | /**
39 | * @runInSeparateProcess
40 | */
41 | public function testResetUniqueness()
42 | {
43 | $provider = new Providers(Factory::create());
44 |
45 | $php = <<<'PHP'
46 | namespace Brain\Faker\Tests\Unit;
47 |
48 | class ExampleClass extends \Brain\Faker\Provider\Provider {
49 | public function __invoke(array $args = []) {
50 | return (object)['digit' => $this->uniqueGenerator->randomDigitNotNull];
51 | }
52 | }
53 | PHP;
54 | eval($php); // phpcs:ignore
55 |
56 | /** @noinspection PhpUndefinedClassInspection */
57 | $provider->__addProviderClass(ExampleClass::class, 'thing', 'things');
58 |
59 | $exceptionHappened = false;
60 |
61 | try {
62 | /** @noinspection PhpUndefinedMethodInspection */
63 | $provider->wp()->things(10);
64 | } catch (\OverflowException $exception) {
65 | $exceptionHappened = true;
66 | }
67 |
68 | static::assertTrue($exceptionHappened);
69 |
70 | $provider->wp()->__resetUnique();
71 |
72 | static::assertIsInt($provider->wp()->thing->digit);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/tests/cases/unit/ProvidersTest.php:
--------------------------------------------------------------------------------
1 | expectException(\Error::class);
26 | $this->expectExceptionMessageMatches('/class/');
27 |
28 | $provider = new Providers(Factory::create());
29 | $provider->__addProviderClass(__CLASS__, 'bar', 'baz');
30 | }
31 |
32 | public function testAddProviderClassFailsForNotExistentClass()
33 | {
34 | $this->expectException(\Error::class);
35 | $this->expectExceptionMessageMatches('/class/');
36 |
37 | $provider = new Providers(Factory::create());
38 | $provider->__addProviderClass('Meh', 'bar', 'baz');
39 | }
40 |
41 | public function testAddProviderClassFailsForNotInstantiableClass()
42 | {
43 | $this->expectException(\Error::class);
44 | $this->expectExceptionMessageMatches('/not a valid provider class/');
45 |
46 | $class = $this->declarePhpClass(null, null, null, 'abstract');
47 |
48 | $provider = new Providers(Factory::create());
49 | /** @noinspection PhpUndefinedClassInspection */
50 | $provider->__addProviderClass($class, 'foo', 'bar');
51 | }
52 |
53 | public function testAddProviderClassFailsForReservedMethodOne()
54 | {
55 | $this->expectExceptionMessageMatches('/reserved method/');
56 |
57 | $class = $this->declarePhpClass();
58 |
59 | $provider = new Providers(Factory::create());
60 | $provider->__addProviderClass($class, 'wp', 'bar');
61 | }
62 |
63 | public function testAddProviderClassFailsForReservedMethodMany()
64 | {
65 | $this->expectExceptionMessageMatches('/reserved method/');
66 |
67 | $class = $this->declarePhpClass();
68 |
69 | $provider = new Providers(Factory::create());
70 | $provider->__addProviderClass($class, 'foo', '__call');
71 | }
72 |
73 | public function testAddProviderClassFailsForNotUniqueClass()
74 | {
75 | $this->expectExceptionMessageMatches('/uniquely identify/');
76 |
77 | $class1 = $this->declarePhpClass('ClassOne');
78 | $class2 = $this->declarePhpClass('ClassTwo');
79 |
80 | $provider = new Providers(Factory::create());
81 | $provider->__addProviderClass($class1, 'foo', 'notUnique');
82 | $provider->__addProviderClass($class2, 'notUnique', 'baz');
83 |
84 | /** @noinspection PhpUndefinedMethodInspection */
85 | $provider->wp()->notUnique();
86 | }
87 |
88 | public function testAddProviderClassSuccessfully()
89 | {
90 | $class = $this->declarePhpClass();
91 |
92 | $provider = new Providers(Factory::create());
93 |
94 | static::assertSame($provider, $provider->__addProviderClass($class, 'one', 'many'));
95 | }
96 |
97 | public function testCallNotRegisteredMethod()
98 | {
99 | $this->expectExceptionMessageMatches('/undefined method/');
100 |
101 | $class = $this->declarePhpClass();
102 |
103 | $provider = new Providers(Factory::create());
104 |
105 | $provider->__addProviderClass($class, 'one', 'many');
106 |
107 | /** @noinspection PhpUndefinedMethodInspection */
108 | $provider->wp()->foo();
109 | }
110 |
111 | public function testCallOne()
112 | {
113 | $class = $this->declarePhpClass(null, 'return (object)["name" => "one"];');
114 |
115 | $provider = new Providers(Factory::create());
116 |
117 | $provider->__addProviderClass($class, 'one', 'many');
118 | /** @noinspection PhpUndefinedMethodInspection */
119 | $result = $provider->wp()->one();
120 |
121 | static::assertInstanceOf(\stdClass::class, $result);
122 | static::assertSame('one', $result->name);
123 | }
124 |
125 | public function testCallManyFailsIfNoNumber()
126 | {
127 | $this->expectExceptionMessageMatches('/number/');
128 |
129 | $class = $this->declarePhpClass();
130 |
131 | $provider = new Providers(Factory::create());
132 |
133 | $provider->__addProviderClass($class, 'one', 'many');
134 | /** @noinspection PhpUndefinedMethodInspection */
135 | $provider->wp()->many('meh');
136 | }
137 |
138 | public function testCallManyFailsIfNoArray()
139 | {
140 | $this->expectExceptionMessageMatches('/array/');
141 |
142 | $class = $this->declarePhpClass();
143 |
144 | $provider = new Providers(Factory::create());
145 |
146 | $provider->__addProviderClass($class, 'one', 'many');
147 | /** @noinspection PhpUndefinedMethodInspection */
148 | $provider->wp()->many(1, 'meh');
149 | }
150 |
151 | public function testCallMany()
152 | {
153 | $invoke = <<<'PHP'
154 | $args['str'] = $this->uniqueGenerator->word();
155 | $args['num'] = $this->generator->randomNumber();
156 | return (object)$args;
157 | PHP;
158 |
159 | $class = $this->declarePhpClass(null, $invoke);
160 |
161 | $provider = new Providers(Factory::create());
162 |
163 | $provider->__addProviderClass($class, 'one', 'many');
164 |
165 | /** @noinspection PhpUndefinedMethodInspection */
166 | $result = $provider->wp()->many(7);
167 |
168 | static::assertIsArray($result);
169 | static::assertCount(7, $result);
170 |
171 | $last = null;
172 | foreach ($result as $element) {
173 | static::assertNotSame($last, $element);
174 | static::assertInstanceOf(\stdClass::class, $element);
175 | static::assertIsString($element->str);
176 | static::assertIsInt($element->num);
177 | $last = $element;
178 | }
179 | }
180 |
181 | public function testCallManyWithDefaults()
182 | {
183 | $class = $this->declarePhpClass();
184 |
185 | $provider = new Providers(Factory::create());
186 |
187 | $provider->__addProviderClass($class, 'one', 'many');
188 | /** @noinspection PhpUndefinedMethodInspection */
189 | $result = $provider->wp()->many();
190 |
191 | static::assertIsArray($result);
192 |
193 | foreach ($result as $element) {
194 | static::assertInstanceOf(\stdClass::class, $element);
195 | }
196 | }
197 |
198 | public function testCallManyReturnEmptyArrayIfRequiringZeroItems()
199 | {
200 | $class = $this->declarePhpClass();
201 |
202 | $provider = new Providers(Factory::create());
203 |
204 | $provider->__addProviderClass($class, 'one', 'many');
205 |
206 | /** @noinspection PhpUndefinedMethodInspection */
207 | static::assertSame([], $provider->wp()->many(0));
208 | }
209 |
210 | public function testCallOneWithArgs()
211 | {
212 | $class = $this->declarePhpClass();
213 |
214 | $provider = new Providers(Factory::create());
215 |
216 | $provider->__addProviderClass($class, 'one', 'many');
217 |
218 | /** @noinspection PhpUndefinedMethodInspection */
219 | $result = $provider->wp()->one(['hello' => 'world']);
220 |
221 | static::assertInstanceOf(\stdClass::class, $result);
222 | static::assertSame('world', $result->hello);
223 | }
224 |
225 | public function testCallOneViaProperty()
226 | {
227 | $class = $this->declarePhpClass();
228 |
229 | $provider = new Providers(Factory::create());
230 |
231 | $provider->__addProviderClass($class, 'one', 'many');
232 |
233 | static::assertInstanceOf(\stdClass::class, $provider->wp()->one);
234 | }
235 |
236 | public function testCallManyViaProperty()
237 | {
238 | $class = $this->declarePhpClass();
239 |
240 | $provider = new Providers(Factory::create());
241 |
242 | $provider->__addProviderClass($class, 'one', 'many');
243 |
244 | static::assertIsArray($provider->wp()->many);
245 | }
246 |
247 | public function testAtLeast()
248 | {
249 | $class = $this->declarePhpClass();
250 |
251 | $provider = new Providers(Factory::create());
252 |
253 | $provider->__addProviderClass($class, 'item', 'items');
254 | /** @noinspection PhpUndefinedMethodInspection */
255 | $result = $provider->wp()->atLeast3items();
256 |
257 | static::assertIsArray($result);
258 | static::assertGreaterThanOrEqual(3, count($result));
259 | }
260 |
261 | public function testAtMost()
262 | {
263 | $class1 = $this->declarePhpClass('ExampleOne');
264 | $class2 = $this->declarePhpClass('ExampleTwo');
265 |
266 | $provider = new Providers(Factory::create());
267 |
268 | $provider->__addProviderClass($class1, 'post', 'posts');
269 | $provider->__addProviderClass($class2, 'user', 'users');
270 |
271 | /** @noinspection PhpUndefinedMethodInspection */
272 | $atMost2posts = $provider->wp()->atMost2posts();
273 | /** @noinspection PhpUndefinedMethodInspection */
274 | $atMost3users = $provider->wp()->atMost3users();
275 | /** @noinspection PhpUndefinedMethodInspection */
276 | $atMost1users = $provider->wp()->atMost1users();
277 | /** @noinspection PhpUndefinedMethodInspection */
278 | $atMost0posts = $provider->wp()->atMost0posts();
279 |
280 | static::assertIsArray($atMost2posts);
281 | static::assertIsArray($atMost3users);
282 | static::assertIsArray($atMost1users);
283 | static::assertSame([], $atMost0posts);
284 | static::assertContains(count($atMost2posts), [0, 1, 2]);
285 | static::assertContains(count($atMost3users), [0, 1, 2, 3]);
286 | static::assertContains(count($atMost1users), [0, 1]);
287 | }
288 |
289 | public function testAtLeastAndAtMostDynamic()
290 | {
291 | $class = $this->declarePhpClass();
292 |
293 | $provider = new Providers(Factory::create());
294 |
295 | $provider->__addProviderClass($class, 'thing', 'things');
296 |
297 | /** @noinspection PhpUndefinedMethodInspection */
298 | $atLeastOneThing = $provider->wp()->atLeastOneThing();
299 | /** @noinspection PhpUndefinedMethodInspection */
300 | $atLeastTwoThings = $provider->wp()->atLeastTwoThings();
301 | /** @noinspection PhpUndefinedMethodInspection */
302 | $atLeastThreeThings = $provider->wp()->atLeastThreeThings();
303 | /** @noinspection PhpUndefinedMethodInspection */
304 | $atLeastFourThings = $provider->wp()->atLeastFourThings();
305 | /** @noinspection PhpUndefinedMethodInspection */
306 | $atLeastFiveThings = $provider->wp()->atLeastFiveThings();
307 |
308 | /** @noinspection PhpUndefinedMethodInspection */
309 | $atMostOneThing = $provider->wp()->atMostOneThing();
310 | /** @noinspection PhpUndefinedMethodInspection */
311 | $atMostTwoThings = $provider->wp()->atMostTwoThings();
312 | /** @noinspection PhpUndefinedMethodInspection */
313 | $atMostThreeThings = $provider->wp()->atMostThreeThings();
314 | /** @noinspection PhpUndefinedMethodInspection */
315 | $atMostFourThings = $provider->wp()->atMostFourThings();
316 | /** @noinspection PhpUndefinedMethodInspection */
317 | $atMostFiveThings = $provider->wp()->atMostFiveThings();
318 |
319 | static::assertIsArray($atLeastOneThing);
320 | static::assertIsArray($atLeastTwoThings);
321 | static::assertIsArray($atLeastThreeThings);
322 | static::assertIsArray($atLeastFourThings);
323 | static::assertIsArray($atLeastFiveThings);
324 | static::assertIsArray($atMostOneThing);
325 | static::assertIsArray($atMostTwoThings);
326 | static::assertIsArray($atMostThreeThings);
327 | static::assertIsArray($atMostFourThings);
328 | static::assertIsArray($atMostFiveThings);
329 |
330 | static::assertGreaterThanOrEqual(1, count($atLeastOneThing));
331 | static::assertGreaterThanOrEqual(2, count($atLeastTwoThings));
332 | static::assertGreaterThanOrEqual(3, count($atLeastThreeThings));
333 | static::assertGreaterThanOrEqual(4, count($atLeastFourThings));
334 | static::assertGreaterThanOrEqual(5, count($atLeastFiveThings));
335 |
336 | static::assertLessThanOrEqual(1, count($atMostOneThing));
337 | static::assertLessThanOrEqual(2, count($atMostTwoThings));
338 | static::assertLessThanOrEqual(3, count($atMostThreeThings));
339 | static::assertLessThanOrEqual(4, count($atMostFourThings));
340 | static::assertLessThanOrEqual(5, count($atMostFiveThings));
341 | }
342 |
343 | public function testBetweenDynamic()
344 | {
345 | $class = $this->declarePhpClass();
346 |
347 | $provider = new Providers(Factory::create());
348 |
349 | $provider->__addProviderClass($class, 'thing', 'things');
350 |
351 | $allTheThings = [
352 | ['betweenOneAndThreeThings', 1, 3],
353 | ['betweenFiveAndTwoThings', 2, 5],
354 | ['betweenFourAndFourThings', 4, 4],
355 | ['between1AndThreeThings', 1, 3],
356 | ['between5AndTwoThings', 2, 5],
357 | ['between4AndFourThings', 4, 4],
358 | ['betweenOneAnd3Things', 1, 3],
359 | ['betweenFiveAnd2Things', 2, 5],
360 | ['betweenFourAnd4Things', 4, 4],
361 | ['between1And3Things', 1, 3],
362 | ['between5And2Things', 2, 5],
363 | ['between4And4Things', 4, 4],
364 | ];
365 |
366 | foreach ($allTheThings as [$method, $min, $max]) {
367 | $things = $provider->wp()->{$method}(['x' => 'X']);
368 |
369 | static::assertIsArray($things);
370 |
371 | foreach ($things as $thing) {
372 | static::assertInstanceOf(\stdClass::class, $thing);
373 | static::assertSame('X', $thing->x);
374 | }
375 |
376 | $count = count($things);
377 |
378 | if ($min === $max) {
379 | static::assertSame($min, $count);
380 | continue;
381 | }
382 |
383 | static::assertGreaterThanOrEqual($min, $count);
384 | static::assertLessThanOrEqual($max, $count);
385 | }
386 | }
387 |
388 | public function testBetweenDynamicWrongEdgeCases()
389 | {
390 | $class = $this->declarePhpClass();
391 |
392 | $provider = new Providers(Factory::create());
393 |
394 | $provider->__addProviderClass($class, 'thing', 'things');
395 |
396 | $methods = [
397 | 'atLeastOneAndThreeThings',
398 | 'atMost1And3Things',
399 | 'atMostOneMeh',
400 | 'between2Things',
401 | 'between2And3Stuff',
402 | ];
403 |
404 | $expected = count($methods);
405 | $exceptionsCount = 0;
406 |
407 | try {
408 | execute: {
409 | $method = array_shift($methods);
410 | $provider->wp()->{$method}();
411 | }
412 | } catch (\Error $error) {
413 | static::assertRegExp('/undefined method/', $error->getMessage());
414 | $exceptionsCount++;
415 | if ($methods) {
416 | goto execute;
417 | }
418 | }
419 |
420 | static::assertSame($expected, $exceptionsCount);
421 | }
422 |
423 | /**
424 | * @param string $name
425 | * @param string|null $invokeBody
426 | * @param string $invokeVisibility
427 | * @param string|null $classModifier
428 | * @return string
429 | */
430 | private function declarePhpClass(
431 | ?string $name = null,
432 | ?string $invokeBody = null,
433 | ?string $invokeVisibility = null,
434 | ?string $classModifier = null
435 | ): string {
436 |
437 | isset($name) or $name = 'ExampleClass';
438 | isset($invokeBody) or $invokeBody = 'return (object)$args;';
439 | isset($invokeVisibility) or $invokeVisibility = 'public';
440 | isset($classModifier) or $classModifier = '';
441 |
442 | $php = <<faker = Brain\faker();
37 |
38 | /** @noinspection PhpUndefinedMethodInspection */
39 | $this->wpFaker = $this->faker->wp();
40 | }
41 |
42 | /**
43 | * @return void
44 | */
45 | protected function tearDown(): void
46 | {
47 | Brain\fakerReset();
48 | parent::tearDown();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/src/ProviderTestCase.php:
--------------------------------------------------------------------------------
1 | functions = new FunctionExpectations();
34 | }
35 |
36 | protected function tearDown(): void
37 | {
38 | $this->functions->reset();
39 | $this->functions = null;
40 |
41 | /** @var Provider$provider */
42 | foreach ($this->providers as $provider) {
43 | $provider->reset();
44 | }
45 |
46 | parent::tearDown();
47 | }
48 |
49 | /**
50 | * @param string $class
51 | * @return Provider
52 | */
53 | protected function factoryProvider(string $class): Provider
54 | {
55 | /** @var Provider $provider */
56 | $provider = new $class(Factory::create(), $this->functions);
57 | $this->providers[] = $provider;
58 |
59 | return $provider;
60 | }
61 |
62 | /**
63 | * @param string $formatString
64 | * @return \DateTime|null
65 | */
66 | protected function dateByMySql(string $formatString): ?\DateTime
67 | {
68 | return \DateTime::createFromFormat('Y-m-d H:i:s', $formatString) ?: null;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/tests/src/TestCase.php:
--------------------------------------------------------------------------------
1 |