├── .github
└── workflows
│ ├── packagist-deploy.yml
│ └── tests.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── composer.json
├── docker-compose.yml
├── phpunit.xml
├── src
├── Calculators
│ ├── Iban.php
│ └── Luhn.php
├── Container
│ ├── Container.php
│ └── Traits
│ │ ├── HasExtensions.php
│ │ ├── HasLocale.php
│ │ ├── HasModifiers.php
│ │ └── HasStrategies.php
├── Exceptions
│ ├── BadParameterException.php
│ ├── MaximumTriesReached.php
│ └── NoExtensionLocaleFound.php
├── Extensions
│ ├── ArrayExtension.php
│ ├── BooleanExtension.php
│ ├── ColorsExtension.php
│ ├── DateTimeExtension.php
│ ├── Extension.php
│ ├── FinancialExtension.php
│ ├── HashExtension.php
│ ├── InternetExtension.php
│ ├── NumbersExtension.php
│ ├── PersonExtension.php
│ ├── StringsExtension.php
│ ├── TextExtension.php
│ └── Traits
│ │ └── HasLocale.php
├── Faker.php
├── FakerServiceProvider.php
├── Manifests
│ ├── ContainerMixinManifest.php
│ └── PackageManifest.php
├── Modifiers
│ ├── LowercaseModifier.php
│ ├── Modifier.php
│ ├── NullableModifier.php
│ └── UppercaseModifier.php
├── Providers
│ ├── Provider.php
│ └── ProviderRepository.php
├── Seeds
│ └── HasSeeds.php
└── Strategies
│ ├── RegexStrategy.php
│ ├── Strategy.php
│ └── UniqueStrategy.php
└── tests
├── Support
├── Extensions
│ ├── EnEnExtensionTest.php
│ ├── EnUsExtensionTest.php
│ ├── FrFrExtensionTest.php
│ ├── MixinTestExtension.php
│ ├── NullLocaleExtensionTest.php
│ ├── NumberTestExtension.php
│ └── StringTestExtension.php
├── TestServiceProvider.php
└── vendor
│ └── composer
│ └── installed.json
└── Unit
├── Calculators
├── IbanTest.php
└── LuhnTest.php
├── ContainerMixinManifestTest.php
├── ContainerTest.php
├── ExtensionTest.php
├── Extensions
├── ArraysExtensionTest.php
├── BooleanExtensionTest.php
├── ColorsExtensionTest.php
├── DatetimeExtensionTest.php
├── FinancialExtensionTest.php
├── HashExtensionTest.php
├── InternetExtensionTest.php
├── NumbersExtensionTest.php
├── PersonExtensionTest.php
├── StringsExtensionTest.php
├── TestCase.php
└── TextExtensionTest.php
├── LocaleTest.php
├── Modifiers
├── LowercaseModifierTest.php
├── OptionalModifierTest.php
└── UppercaseModifierTest.php
├── PackageManifestTest.php
├── ProviderRepositoryTest.php
├── Strategies
├── RegexStrategyTest.php
└── UniqueStrategyTest.php
└── TestCase.php
/.github/workflows/packagist-deploy.yml:
--------------------------------------------------------------------------------
1 | name: Packagist Deploy
2 |
3 | on:
4 | release:
5 | types: [created]
6 |
7 | jobs:
8 | build:
9 |
10 | runs-on: ubuntu-latest
11 | permissions:
12 | contents: read
13 | packages: write
14 |
15 | steps:
16 | - uses: actions/checkout@v4
17 | - uses: mnavarrocarter/packagist-update@v1.0.0
18 | with:
19 | username: "GautierDele"
20 | api_token: ${{ secrets.PACKAGIST_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: tests
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | strategy:
15 | fail-fast: false
16 | matrix:
17 | php-version: [ '8.3', '8.4' ]
18 |
19 | name: Tests on PHP ${{ matrix.php-version }}
20 |
21 | steps:
22 | - name: Checkout
23 | uses: actions/checkout@v4
24 |
25 | - name: Setup PHP
26 | uses: shivammathur/setup-php@v2
27 | with:
28 | php-version: ${{ matrix.php-version }}
29 | coverage: none
30 |
31 | - name: Validate composer.json and composer.lock
32 | run: composer validate
33 |
34 | - name: Cache Composer packages
35 | id: composer-cache
36 | uses: actions/cache@v4
37 | with:
38 | path: vendor
39 | key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}
40 | restore-keys: |
41 | ${{ runner.os }}-php-${{ matrix.php-version }}-
42 |
43 | - name: Install dependencies
44 | if: steps.composer-cache.outputs.cache-hit != 'true'
45 | run: composer i --prefer-dist --no-progress
46 |
47 | - name: Run test suite
48 | run: vendor/bin/phpunit
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.lock
3 | .phpunit*
4 | .idea
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:latest
2 |
3 | RUN apt update
4 | RUN apt install unzip curl -y
5 |
6 | RUN curl -sS https://getcomposer.org/installer -o /usr/local/composer-setup.php
7 |
8 | RUN php /usr/local/composer-setup.php --install-dir=/usr/local/bin --filename=composer
9 |
10 | RUN rm /usr/local/composer-setup.php
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Faker PHP
4 |
5 | Faker PHP allows you to easily generate mock data for your tests, providing a quick and flexible way to simulate realistic data effortlessly—perfect for creating robust development and testing environments.
6 |
7 | ## Requirements
8 |
9 | PHP 8.3+
10 |
11 | ## Documentation, Installation, and Usage Instructions
12 |
13 | See the [documentation](https://faker-php.xefi.com) for detailed installation and usage instructions.
14 |
15 | ## What It Does
16 |
17 | You'll be able to generate fake data for your applications, making your test environment more flexible.
18 |
19 | Here is a quick look at what you can do:
20 |
21 | ```php
22 | $faker = new Xefi\Faker\Faker();
23 |
24 | $faker->name() // John Doe
25 | $faker->name() // Charles Brown
26 |
27 | $faker->sentence() // equus canis populus servus aquaeductus fidelitas
28 |
29 | $faker->iban() // PX41711762752955497163783543
30 | ```
31 |
32 | ## Support us
33 |
34 |
35 |
36 | Since 1997, XEFI is a leader in IT performance support for small and medium-sized businesses through its nearly 200 local agencies based in France, Belgium, Switzerland and Spain.
37 | A one-stop shop for IT, office automation, software, [digitalization](https://www.xefi.com/solutions-software/), print and cloud needs.
38 | [Want to work with us ?](https://carriere.xefi.fr/metiers-software)
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xefi/faker-php",
3 | "type": "library",
4 | "description": "Faker allows you to generate realistic fake data for your php applications",
5 | "keywords": [
6 | "faker",
7 | "data",
8 | "seeding",
9 | "fixtures"
10 | ],
11 | "license": "MIT",
12 | "authors": [
13 | {
14 | "name": "Gautier Deleglise"
15 | },
16 | {
17 | "name": "Martin Soenen"
18 | }
19 | ],
20 | "require": {
21 | "php": "^8.3",
22 | "phpdocumentor/reflection-docblock": "^5.6",
23 | "psr/container": "^2.0"
24 | },
25 | "require-dev": {
26 | "phpunit/phpunit": "^11"
27 | },
28 | "autoload": {
29 | "psr-4": {
30 | "Xefi\\Faker\\": "src/"
31 | }
32 | },
33 | "autoload-dev": {
34 | "psr-4": {
35 | "Xefi\\Faker\\Tests\\": "tests/"
36 | }
37 | },
38 | "config": {
39 | "sort-packages": true
40 | },
41 | "extra": {
42 | "faker": {
43 | "providers": [
44 | "Xefi\\Faker\\FakerServiceProvider"
45 | ]
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | php:
3 | build: .
4 | image: php:latest
5 | volumes:
6 | - ./:/var/www/html
7 | working_dir: /var/www/html
8 | tty: true
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 | tests/Unit
13 |
14 |
15 |
16 |
17 | src
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/Calculators/Iban.php:
--------------------------------------------------------------------------------
1 | = 0; $i--) {
20 | $factor = $parity ? 2 : 1;
21 | $parity = $parity ? 0 : 1;
22 | $sum += array_sum(str_split($number[$i] * $factor));
23 | }
24 |
25 | return $sum;
26 | }
27 |
28 | /**
29 | * Compute check digit.
30 | *
31 | * @param int $number Number to compute.
32 | *
33 | * @return int
34 | */
35 | public static function checksum(int $number): int
36 | {
37 | return (self::algorithm($number) * 9) % 10;
38 | }
39 |
40 | /**
41 | * Validate number containing check digit.
42 | *
43 | * @param int $number Number to validate.
44 | *
45 | * @return bool
46 | */
47 | public static function isValid(int $number): bool
48 | {
49 | return (self::algorithm($number.'0') % 10) === 0;
50 | }
51 |
52 | /**
53 | * Add check digit to number.
54 | *
55 | * @param int $number Number to checksum.
56 | * @param bool $soft Do not add check digit if number already validates.
57 | *
58 | * @return int
59 | */
60 | public static function create(int $number, bool $soft = false): int
61 | {
62 | return !self::isValid($number) || !$soft
63 | ? $number.self::checksum($number)
64 | : $number;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Container/Container.php:
--------------------------------------------------------------------------------
1 | areExtensionsInitialized()) {
58 | $this->registerConfiguredProviders();
59 |
60 | $this->bootstrap();
61 | }
62 |
63 | if ($shouldBuildContainerMixin) {
64 | $this->buildContainerMixinManifest();
65 | }
66 | }
67 |
68 | /**
69 | * Set the package manifest path.
70 | *
71 | * @param string $manifestPath
72 | *
73 | * @return void
74 | */
75 | public static function packageManifestPath(string $manifestPath)
76 | {
77 | static::$packageManifestPath = $manifestPath;
78 | }
79 |
80 | /**
81 | * Set the container mixin manifest path.
82 | *
83 | * @param string $manifestPath
84 | *
85 | * @return void
86 | */
87 | public static function containerMixinManifestPath(string $containerMixinManifestPath)
88 | {
89 | static::$containerMixinManifestPath = $containerMixinManifestPath;
90 | }
91 |
92 | /**
93 | * Set the base path.
94 | *
95 | * @param string $basePath
96 | *
97 | * @return void
98 | */
99 | public static function basePath(string $basePath)
100 | {
101 | static::$basePath = $basePath;
102 | }
103 |
104 | /**
105 | * Build container mixin manifest.
106 | */
107 | protected function buildContainerMixinManifest()
108 | {
109 | $containerMixinManifest = new ContainerMixinManifest(static::$basePath, static::$containerMixinManifestPath);
110 | $containerMixinManifest->buildIfShould($this->getExtensionMethods(), $this->getExtensions());
111 | }
112 |
113 | /**
114 | * Register all of the configured providers.
115 | *
116 | * @return void
117 | */
118 | protected function registerConfiguredProviders()
119 | {
120 | $packageManifest = new PackageManifest(static::$basePath, static::$packageManifestPath);
121 |
122 | $providers = $packageManifest->providers();
123 |
124 | $collapsedProviders = [];
125 | foreach ($providers as $values) {
126 | $collapsedProviders[] = $values;
127 | }
128 |
129 | (new ProviderRepository())
130 | ->load(array_merge([], ...$collapsedProviders));
131 | }
132 |
133 | /**
134 | * Register a console "starting" bootstrapper.
135 | *
136 | * @param Closure $callback
137 | *
138 | * @return void
139 | */
140 | public static function starting(Closure $callback): void
141 | {
142 | static::$bootstrappers[] = $callback;
143 | }
144 |
145 | /**
146 | * Bootstrap the console application.
147 | *
148 | * @return void
149 | */
150 | protected function bootstrap()
151 | {
152 | foreach (static::$bootstrappers as $bootstrapper) {
153 | $bootstrapper($this);
154 | }
155 | }
156 |
157 | /**
158 | * Reset the bootstrappers.
159 | *
160 | * @return void
161 | */
162 | public function forgetBootstrappers(): void
163 | {
164 | static::$bootstrappers = [];
165 | }
166 |
167 | /**
168 | * @param $method
169 | *
170 | * @return mixed
171 | */
172 | public function run($method, $parameters)
173 | {
174 | $tries = 0;
175 | do {
176 | $generatedValue = $this->callExtensionMethod($method, $parameters);
177 |
178 | // Apply modifiers
179 | $generatedValue = $this->applyModifiers($generatedValue);
180 |
181 | if (++$tries > 20000) {
182 | throw new MaximumTriesReached(sprintf('Maximum tries of %d reached without finding a value', 20000));
183 | }
184 | } while (!$this->passStrategies($generatedValue));
185 |
186 | // Here we assume the container has done his job and reset the strategies
187 | // in case the user wants to run the method again on another extension
188 | $this->forgetStrategies();
189 |
190 | return $generatedValue;
191 | }
192 |
193 | /**
194 | * Dynamically call the extension.
195 | *
196 | * @param string $method
197 | * @param array $parameters
198 | *
199 | * @return mixed
200 | */
201 | public function __call($method, $parameters)
202 | {
203 | return $this->run($method, $parameters);
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/src/Container/Traits/HasExtensions.php:
--------------------------------------------------------------------------------
1 | resolve($extension);
37 | }
38 |
39 | return $this;
40 | }
41 |
42 | /**
43 | * Add an extension, resolving through the application.
44 | *
45 | * @param Extension|string $extension
46 | *
47 | * @return Container
48 | */
49 | protected function resolve(\Xefi\Faker\Extensions\Extension|string $extension): Container
50 | {
51 | $instance = $extension instanceof Extension ? $extension : new $extension(new Randomizer());
52 |
53 | // If the extension supports locale variations
54 | if (method_exists($instance, 'getLocale')) {
55 | return $this->addLocaleExtension($instance);
56 | }
57 |
58 | return $this->addExtension($instance);
59 | }
60 |
61 | /**
62 | * Add an extension to the container.
63 | *
64 | * @param \Xefi\Faker\Extensions\Extension $extension
65 | *
66 | * @return \Xefi\Faker\Extensions\Extension
67 | */
68 | protected function addExtension(Extension $extension): Container
69 | {
70 | if (isset(static::$extensions[$extension->getName()])) {
71 | trigger_error(sprintf('[XEFI FAKER] The \'%s\' extension is already registered', $extension->getName()), E_USER_WARNING);
72 | }
73 |
74 | static::$extensions[$extension->getName()] = $extension;
75 |
76 | // Here we register all the extensions methods in order to have a quick access after
77 | foreach (get_class_methods($extension) as $method) {
78 | // If the method is common
79 | if (in_array($method, ['getName', '__construct'])) {
80 | continue;
81 | }
82 |
83 | if (isset(static::$extensionsMethods[$method])) {
84 | trigger_error(sprintf('[XEFI FAKER] The \'%s\' method from \'%s\' is already registered', $method, $extension->getName()), E_USER_WARNING);
85 | }
86 |
87 | static::$extensionsMethods[$method] = $extension->getName();
88 | }
89 |
90 | return $this;
91 | }
92 |
93 | /**
94 | * Add an extension to the container.
95 | *
96 | * @param \Xefi\Faker\Extensions\Extension $extension
97 | *
98 | * @return \Xefi\Faker\Extensions\Extension
99 | */
100 | protected function addLocaleExtension(Extension $extension): Container
101 | {
102 | if (!isset(static::$extensions[$extension->getName()])) {
103 | static::$extensions[$extension->getName()] = [
104 | 'locales' => [],
105 | ];
106 | }
107 |
108 | if (isset(static::$extensions[$extension->getName()]['locales'][$extension->getLocale()])) {
109 | trigger_error(sprintf('[XEFI FAKER] The \'%s\' extension in locale \'%s\' is already registered', $extension->getName(), $extension->getLocale()), E_USER_WARNING);
110 | }
111 |
112 | static::$extensions[$extension->getName()]['locales'][$extension->getLocale()] = $extension;
113 |
114 | // Here we register all the extensions methods in order to have a quick access after
115 | foreach (get_class_methods($extension) as $method) {
116 | // If the method is common
117 | if (in_array($method, ['getName', '__construct'])) {
118 | continue;
119 | }
120 |
121 | // The method for another locale has been set
122 | if (isset(static::$extensionsMethods[$method])) {
123 | continue;
124 | }
125 |
126 | static::$extensionsMethods[$method] = $extension->getName();
127 | }
128 |
129 | return $this;
130 | }
131 |
132 | /**
133 | * Get the container extensions.
134 | *
135 | * @return array
136 | */
137 | public function getExtensions(): array
138 | {
139 | return static::$extensions;
140 | }
141 |
142 | /**
143 | * Get the container extensions methods.
144 | *
145 | * @return array
146 | */
147 | public function getExtensionMethods(): array
148 | {
149 | return static::$extensionsMethods;
150 | }
151 |
152 | /**
153 | * See if the extensions has already been set.
154 | *
155 | * @return bool
156 | */
157 | public function areExtensionsInitialized(): bool
158 | {
159 | return !empty(static::$extensions);
160 | }
161 |
162 | /**
163 | * Reset the container extensions.
164 | *
165 | * @return void
166 | */
167 | public function forgetExtensions(): void
168 | {
169 | static::$extensions = [];
170 | static::$extensionsMethods = [];
171 | }
172 |
173 | /**
174 | * Resolve the method called to extensions.
175 | *
176 | * @param string $method
177 | * @param array $parameters
178 | *
179 | * @return mixed
180 | */
181 | public function callExtensionMethod(string $method, array $parameters = [])
182 | {
183 | if (!isset(static::$extensionsMethods[$method])) {
184 | throw new \BadMethodCallException(sprintf('The %s method does not exist', $method));
185 | }
186 |
187 | $extension = static::$extensions[static::$extensionsMethods[$method]];
188 |
189 | // We assume we here have multiple extensions declined by locale, we will try
190 | // to get the extension with the current locale, defaulting to first element
191 | if (is_array($extension) && isset($extension['locales'])) {
192 | if (!isset($extension['locales'][$this->getLocale()]) && !isset($extension['locales'][null])) {
193 | throw new NoExtensionLocaleFound(sprintf('Locale \'%s\' and \'null\' for method \'%s\' was not found', $this->getLocale(), $method));
194 | }
195 | $extension = $extension['locales'][$this->getLocale()] ?? $extension['locales'][null];
196 | }
197 |
198 | return $extension->$method(...$parameters);
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/src/Container/Traits/HasLocale.php:
--------------------------------------------------------------------------------
1 | locale ?? null;
22 | }
23 |
24 | /**
25 | * Change the locale.
26 | *
27 | * @param ?string $locale
28 | *
29 | * @return self
30 | */
31 | public function locale(?string $locale): self
32 | {
33 | $this->locale = $locale;
34 |
35 | return $this;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Container/Traits/HasModifiers.php:
--------------------------------------------------------------------------------
1 | modifiers[] = new NullableModifier(new Randomizer(), $weight);
30 |
31 | return $this;
32 | }
33 |
34 | /**
35 | * Add a uppercase modifier.
36 | **
37 | * @return $this
38 | */
39 | public function uppercase(): self
40 | {
41 | $this->modifiers[] = new UppercaseModifier();
42 |
43 | return $this;
44 | }
45 |
46 | /**
47 | * Add a lowercase modifier.
48 | **
49 | * @return $this
50 | */
51 | public function lowercase(): self
52 | {
53 | $this->modifiers[] = new LowercaseModifier();
54 |
55 | return $this;
56 | }
57 |
58 | /**
59 | * Determine if a generated value passes the strategies.
60 | *
61 | * @param $generatedValue
62 | *
63 | * @return mixed
64 | */
65 | public function applyModifiers($generatedValue): mixed
66 | {
67 | foreach ($this->getModifiers() as $modifier) {
68 | $generatedValue = $modifier->apply($generatedValue);
69 | }
70 |
71 | return $generatedValue;
72 | }
73 |
74 | /**
75 | * Reset the registered modifiers.
76 | *
77 | * @return void
78 | */
79 | public function forgetModifiers(): void
80 | {
81 | $this->modifiers = [];
82 | }
83 |
84 | /**
85 | * Returns the current modifiers for the container.
86 | *
87 | * @return array
88 | */
89 | public function getModifiers(): array
90 | {
91 | return $this->modifiers;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Container/Traits/HasStrategies.php:
--------------------------------------------------------------------------------
1 | strategies[] = UniqueStrategy::forSeed($seed);
28 |
29 | return $this;
30 | }
31 |
32 | /**
33 | * Add a regex strategy.
34 | *
35 | * @param string $regex
36 | *
37 | * @return $this
38 | */
39 | public function regex(string $regex): self
40 | {
41 | $this->strategies[] = new RegexStrategy($regex);
42 |
43 | return $this;
44 | }
45 |
46 | /**
47 | * Determine if a generated value passes the strategies.
48 | *
49 | * @param $generatedValue
50 | *
51 | * @return bool
52 | */
53 | public function passStrategies($generatedValue): bool
54 | {
55 | foreach ($this->getStrategies() as $strategy) {
56 | if (!$strategy->pass($generatedValue)) {
57 | return false;
58 | }
59 | }
60 |
61 | return true;
62 | }
63 |
64 | /**
65 | * Reset the registered strategies.
66 | *
67 | * @return void
68 | */
69 | public function forgetStrategies(): void
70 | {
71 | $this->strategies = [];
72 | }
73 |
74 | /**
75 | * Returns the current strategies for the container.
76 | *
77 | * @return array
78 | */
79 | public function getStrategies(): array
80 | {
81 | return $this->strategies;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Exceptions/BadParameterException.php:
--------------------------------------------------------------------------------
1 | pickArrayRandomElement($array);
14 | }
15 |
16 | public function randomKey(array $array): mixed
17 | {
18 | return $this->pickArrayRandomKey($array);
19 | }
20 |
21 | public function randomKeyNumber(array $array): mixed
22 | {
23 | return $this->pickArrayRandomKeyNumber($array);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Extensions/BooleanExtension.php:
--------------------------------------------------------------------------------
1 | 100) {
15 | throw new BadParameterException('Percentage must be between 0 and 100');
16 | }
17 |
18 | $randomValue = $this->randomizer->getInt(1, 100);
19 |
20 | return $randomValue <= $percentage;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Extensions/ColorsExtension.php:
--------------------------------------------------------------------------------
1 | pickArrayRandomElement($this->safeColorNames);
34 | }
35 |
36 | public function colorName(): string
37 | {
38 | return $this->pickArrayRandomElement($this->colorNames);
39 | }
40 |
41 | public function safeHexColor(): string
42 | {
43 | $rand = '';
44 | for ($i = 0; $i < 3; $i++) {
45 | $rand .= str_repeat(dechex($this->randomizer->getInt(0, 15)), 2);
46 | }
47 |
48 | return '#'.$rand;
49 | }
50 |
51 | public function hexColor(): string
52 | {
53 | return '#'.bin2hex($this->randomizer->getBytes(3));
54 | }
55 |
56 | public function rgbColorAsArray(): array
57 | {
58 | $colors = [];
59 | for ($i = 0; $i < 3; $i++) {
60 | $colors[] = $this->randomizer->getInt(0, 255);
61 | }
62 |
63 | return $colors;
64 | }
65 |
66 | public function rgbColor(): string
67 | {
68 | return implode(',', $this->rgbColorAsArray());
69 | }
70 |
71 | public function rgbCssColor(): string
72 | {
73 | return 'rgb('.$this->rgbColor().')';
74 | }
75 |
76 | public function rgbaColorAsArray(): array
77 | {
78 | $colors = [];
79 | for ($i = 0; $i < 3; $i++) {
80 | $colors[] = $this->randomizer->getInt(0, 255);
81 | }
82 |
83 | $colors[] = round($this->randomizer->getFloat(0, 1), 2);
84 |
85 | return $colors;
86 | }
87 |
88 | public function rgbaColor(): string
89 | {
90 | return implode(',', $this->rgbaColorAsArray());
91 | }
92 |
93 | public function rgbaCssColor(): string
94 | {
95 | return 'rgba('.$this->rgbaColor().')';
96 | }
97 |
98 | public function hslColorAsArray(): array
99 | {
100 | $colors = [];
101 |
102 | $colors[] = $this->randomizer->getInt(0, 360); // Hue
103 | $colors[] = $this->randomizer->getInt(0, 100); // Saturation
104 | $colors[] = $this->randomizer->getInt(0, 100); // Lightness
105 |
106 | return $colors;
107 | }
108 |
109 | public function hslColor(): string
110 | {
111 | return implode(',', $this->hslColorAsArray());
112 | }
113 |
114 | public function hslCssColor(): string
115 | {
116 | return 'hsl('.$this->hslColor().')';
117 | }
118 |
119 | public function hslaColorAsArray(): array
120 | {
121 | $colors = [];
122 |
123 | $colors[] = $this->randomizer->getInt(0, 360); // Hue
124 | $colors[] = $this->randomizer->getInt(0, 100); // Saturation
125 | $colors[] = $this->randomizer->getInt(0, 100); // Lightness
126 | $colors[] = round($this->randomizer->getFloat(0, 1), 2); // Alpha
127 |
128 | return $colors;
129 | }
130 |
131 | public function hslaColor(): string
132 | {
133 | return implode(',', $this->hslaColorAsArray());
134 | }
135 |
136 | public function hslaCssColor(): string
137 | {
138 | return 'hsla('.$this->hslaColor().')';
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/Extensions/DateTimeExtension.php:
--------------------------------------------------------------------------------
1 | getTimestamp();
17 | }
18 |
19 | return strtotime($timestamp);
20 | }
21 |
22 | public function dateTime(DateTime|int|string $fromTimestamp = '-30 years', DateTime|int|string $toTimestamp = 'now'): DateTime
23 | {
24 | return new DateTime('@'.$this->timestamp($fromTimestamp, $toTimestamp));
25 | }
26 |
27 | public function timestamp(DateTime|int|string $fromTimestamp = '-30 years', DateTime|int|string $toTimestamp = 'now'): int
28 | {
29 | return $this->randomizer->getInt($this->formatTimestamp($fromTimestamp), $this->formatTimestamp($toTimestamp));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Extensions/Extension.php:
--------------------------------------------------------------------------------
1 | randomizer = $randomizer;
15 | }
16 |
17 | /**
18 | * Returns the extension name.
19 | *
20 | * @return string
21 | */
22 | public function getName(): string
23 | {
24 | return
25 | // Here we convert the class name to kebab case
26 | strtolower(
27 | preg_replace(
28 | '/([a-z])([A-Z])/',
29 | '$1-$2',
30 | (
31 | new ReflectionClass($this))->getShortName()
32 | )
33 | );
34 | }
35 |
36 | /**
37 | * Return a given number of random elements from the given array.
38 | *
39 | * @param array $array
40 | * @param int $elements
41 | *
42 | * @return array
43 | */
44 | protected function pickArrayRandomElements(array $array, int $elements = 1): array
45 | {
46 | $keys = $this->randomizer->pickArrayKeys($array, $elements);
47 |
48 | return array_intersect_key($array, array_flip($keys));
49 | }
50 |
51 | /**
52 | * Return a random element from the given array.
53 | *
54 | * @param array $array
55 | *
56 | * @return mixed
57 | */
58 | protected function pickArrayRandomElement(array $array): mixed
59 | {
60 | $elements = $this->pickArrayRandomElements($array);
61 |
62 | return reset($elements);
63 | }
64 |
65 | protected function pickArrayRandomKeys(array $array, int $elements = 1): array
66 | {
67 | return $this->randomizer->pickArrayKeys($array, $elements);
68 | }
69 |
70 | protected function pickArrayRandomKeyNumber(array $array): mixed
71 | {
72 | return $this->pickArrayRandomKeys($array)[0];
73 | }
74 |
75 | protected function pickArrayRandomKey(array $array): mixed
76 | {
77 | return key($array[$this->pickArrayRandomKeys($array)[0]]);
78 | }
79 |
80 | protected function formatString(string $string): string
81 | {
82 | while (($pos = strpos($string, '{a}')) !== false) {
83 | $string = substr_replace($string, $this->pickArrayRandomElement(['{d}', '{l}']), $pos, 3);
84 | }
85 |
86 | while (($pos = strpos($string, '{d}')) !== false) {
87 | $string = substr_replace($string, (string) $this->randomizer->getInt(0, 9), $pos, 3);
88 | }
89 |
90 | while (($pos = strpos($string, '{l}')) !== false) {
91 | $string = substr_replace($string, $this->randomizer->getBytesFromString(implode(range('A', 'Z')), 1), $pos, 3);
92 | }
93 |
94 | return $string;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/Extensions/FinancialExtension.php:
--------------------------------------------------------------------------------
1 | digit, {l} => letter, {a} => any]
15 | *
16 | * @return string
17 | */
18 | public function iban(?string $countryCode = null, ?string $format = null): string
19 | {
20 | if ($format === null) {
21 | $format = str_repeat('{d}', 24);
22 | }
23 |
24 | if ($countryCode === null) {
25 | $countryCode = $this->randomizer->getBytesFromString(implode(range('A', 'Z')), 2);
26 | }
27 |
28 | $format = $this->formatString($format);
29 |
30 | $checksum = Iban::checksum($countryCode.'00'.$format);
31 |
32 | return $countryCode.$checksum.$format;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Extensions/HashExtension.php:
--------------------------------------------------------------------------------
1 | randomizer->getBytes(16));
10 | }
11 |
12 | public function md5(): string
13 | {
14 | return $this->hash('md5');
15 | }
16 |
17 | public function sha1(): string
18 | {
19 | return $this->hash('sha1');
20 | }
21 |
22 | public function sha256(): string
23 | {
24 | return $this->hash('sha256');
25 | }
26 |
27 | public function sha512(): string
28 | {
29 | return $this->hash('sha512');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Extensions/InternetExtension.php:
--------------------------------------------------------------------------------
1 | randomizer->getBytesFromString(
12 | implode(range('a', 'z')),
13 | $this->randomizer->getInt(5, 10)
14 | );
15 | }
16 |
17 | public function tld(): string
18 | {
19 | return $this->pickArrayRandomElement($this->tld);
20 | }
21 |
22 | public function domain(): string
23 | {
24 | return sprintf('%s.%s', $this->sdl(), $this->tld());
25 | }
26 |
27 | public function ipv4(): string
28 | {
29 | return long2ip($this->randomizer->getInt(0, PHP_INT_MAX));
30 | }
31 |
32 | public function ipv6(): string
33 | {
34 | return inet_ntop($this->randomizer->getBytes(16));
35 | }
36 |
37 | public function macAddress()
38 | {
39 | return implode(':', str_split(substr(md5($this->randomizer->getInt(0, 2147483647)), 0, 12), 2));
40 | }
41 |
42 | public function email()
43 | {
44 | $letters = $this->randomizer->getBytesFromString(
45 | implode(range('a', 'z')),
46 | $this->randomizer->getInt(4, 30)
47 | );
48 |
49 | return sprintf('%s@%s', $letters, $this->domain());
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Extensions/NumbersExtension.php:
--------------------------------------------------------------------------------
1 | number(0, 9);
10 | }
11 |
12 | public function number(int $min, int $max): int
13 | {
14 | return $this->randomizer->getInt($min, $max);
15 | }
16 |
17 | public function float(float $min, float $max, int $decimals = 1): float
18 | {
19 | if ($min === $max) {
20 | return (float) number_format($min, $decimals, '.', '');
21 | }
22 |
23 | $factor = pow(10, $decimals);
24 | $randomInt = $this->number((int) floor($min * $factor), (int) ceil($max * $factor));
25 |
26 | return (float) number_format($randomInt / $factor, $decimals, '.', '');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Extensions/PersonExtension.php:
--------------------------------------------------------------------------------
1 | firstName($gender), $this->lastName());
72 | }
73 |
74 | public function firstName(?string $gender = null): string
75 | {
76 | if ($gender === static::GENDER_MALE) {
77 | return $this->pickArrayRandomElement($this->firstNameMale);
78 | }
79 |
80 | if ($gender === static::GENDER_FEMALE) {
81 | return $this->pickArrayRandomElement($this->firstNameFemale);
82 | }
83 |
84 | return $this->pickArrayRandomElement($this->randomizer->getInt(0, 1) === 0 ? $this->firstNameFemale : $this->firstNameMale);
85 | }
86 |
87 | public function lastName(): string
88 | {
89 | return $this->pickArrayRandomElement($this->lastName);
90 | }
91 |
92 | public function title(?string $gender = null)
93 | {
94 | if ($gender === static::GENDER_MALE) {
95 | return $this->pickArrayRandomElement($this->titleMale);
96 | }
97 |
98 | if ($gender === static::GENDER_FEMALE) {
99 | return $this->pickArrayRandomElement($this->titleFemale);
100 | }
101 |
102 | return $this->pickArrayRandomElement($this->randomizer->getInt(0, 1) === 0 ? $this->titleFemale : $this->titleMale);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Extensions/StringsExtension.php:
--------------------------------------------------------------------------------
1 | randomizer->getInt(97, 122));
33 | }
34 |
35 | public function shuffle(array|string $needle): array|string
36 | {
37 | return $this->{'shuffle'.gettype($needle)}($needle);
38 | }
39 |
40 | public function shuffleString(string $needle): string
41 | {
42 | return $this->randomizer->shuffleBytes($needle);
43 | }
44 |
45 | public function shuffleArray(array $needle): array
46 | {
47 | return $this->randomizer->shuffleArray($needle);
48 | }
49 |
50 | public function convertCharacters(string $string): string
51 | {
52 | $patterns = [
53 | '#' => fn () => $this->randomizer->getInt(0, 9),
54 | '?' => fn () => $this->letter(),
55 | ];
56 |
57 | // Here we dynamically define the wildcard to take another option
58 | $patterns['*'] = fn () => $this->pickArrayRandomElement($patterns)();
59 |
60 | for ($i = 0; $i < strlen($string); $i++) {
61 | $string[$i] = isset($patterns[$string[$i]]) ? $patterns[$string[$i]]() : $string[$i];
62 | }
63 |
64 | return $string;
65 | }
66 |
67 | public function semver(): string
68 | {
69 | return sprintf(
70 | '%d.%d.%d',
71 | $this->randomizer->getInt(0, 9),
72 | $this->randomizer->getInt(0, 99),
73 | $this->randomizer->getInt(0, 99)
74 | );
75 | }
76 |
77 | public function emoji(): string
78 | {
79 | return $this->pickArrayRandomElement($this->emojis);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/Extensions/TextExtension.php:
--------------------------------------------------------------------------------
1 | Paragraphs => Sentences => Words.
13 | *
14 | * @var array|array[]
15 | */
16 | protected array $paragraphs = [
17 | [
18 | ['Lorem', 'ipsum', 'dolor', 'sit', 'amet,', 'consectetur', 'adipiscing', 'elit.'],
19 | ['Nullam', 'eu', 'nunc', 'non', 'mi', 'aliquet', 'varius.'],
20 | ['Curabitur', 'et', 'vestibulum', 'nulla.'],
21 | ['Donec', 'placerat', 'tempor', 'arcu,', 'in', 'viverra', 'sapien', 'laoreet', 'eu.'],
22 | ['Sed', 'vitae', 'ligula', 'eget', 'mauris', 'malesuada', 'pretium', 'in', 'at', 'lorem.'],
23 | ['Integer', 'condimentum', 'urna', 'at', 'lacus', 'fermentum,', 'nec', 'sagittis', 'purus', 'venenatis.'],
24 | ],
25 | [
26 | ['Nunc', 'at', 'ligula', 'id', 'nisl', 'varius', 'egestas.'],
27 | ['Suspendisse', 'eget', 'nulla', 'dapibus,', 'efficitur', 'purus', 'a,', 'congue', 'quam.'],
28 | ['Donec', 'sagittis', 'interdum', 'libero', 'non', 'ornare.'],
29 | ['Nam', 'non', 'massa', 'lacus.'],
30 | ['Etiam', 'fermentum', 'neque', 'ut', 'est', 'porttitor,', 'ut', 'tincidunt', 'risus', 'suscipit.'],
31 | ['Nam', 'id', 'nisi', 'eget', 'lorem', 'vehicula', 'eleifend.'],
32 | ],
33 | [
34 | ['Quisque', 'accumsan', 'nisl', 'ut', 'quam', 'pretium,', 'eget', 'lacinia', 'arcu', 'lobortis.'],
35 | ['Nam', 'dapibus', 'justo', 'nec', 'nibh', 'dapibus,', 'ac', 'varius', 'velit', 'varius.'],
36 | ['Nulla', 'facilisi.'],
37 | ['Praesent', 'volutpat', 'suscipit', 'nibh,', 'eget', 'congue', 'ante', 'ornare', 'a.'],
38 | ['Nam', 'aliquet', 'risus', 'eget', 'leo', 'gravida', 'scelerisque.'],
39 | ],
40 | [
41 | ['Aenean', 'accumsan', 'leo', 'at', 'odio', 'vestibulum,', 'non', 'fermentum', 'nisl', 'varius.'],
42 | ['Suspendisse', 'in', 'quam', 'sed', 'ligula', 'convallis', 'sodales.'],
43 | ['Mauris', 'consequat', 'risus', 'sit', 'amet', 'libero', 'iaculis,', 'quis', 'volutpat', 'eros', 'scelerisque.'],
44 | ['Pellentesque', 'habitants', 'morbi', 'tristique', 'senectus', 'et', 'netus', 'et', 'malesuada', 'fames', 'ac', 'turpis', 'egestas.'],
45 | ],
46 | [
47 | ['Donec', 'ultricies', 'euismod', 'libero,', 'vel', 'scelerisque', 'enim', 'condimentum', 'ut.'],
48 | ['Fusce', 'varius', 'urna', 'ac', 'ipsum', 'ultricies,', 'vel', 'elementum', 'turpis', 'dictum.'],
49 | ['Proin', 'nec', 'ante', 'at', 'erat', 'pharetra', 'interdum.'],
50 | ['Etiam', 'nec', 'ligula', 'felis.'],
51 | ['Curabitur', 'sit', 'amet', 'varius', 'nisi,', 'in', 'sagittis', 'turpis.'],
52 | ['Sed', 'eget', 'ex', 'quis', 'risus', 'varius', 'pharetra', 'in', 'a', 'felis.'],
53 | ],
54 | ];
55 |
56 | protected array $flattenedWords;
57 |
58 | protected array $flattenedSentences;
59 |
60 | protected function flattenedWords(): array
61 | {
62 | if (isset($this->flattenedWords)) {
63 | return $this->flattenedWords;
64 | }
65 |
66 | return array_merge(...$this->flattenedSentences());
67 | }
68 |
69 | protected function flattenedSentences(): array
70 | {
71 | if (isset($this->flattenedSentences)) {
72 | return $this->flattenedSentences;
73 | }
74 |
75 | return array_merge(...$this->paragraphs);
76 | }
77 |
78 | public function wordsAsArray(int $words = 3): array
79 | {
80 | return $this->pickArrayRandomElements($this->flattenedWords(), $words);
81 | }
82 |
83 | public function words(int $words = 3): string
84 | {
85 | $words = $this->wordsAsArray($words);
86 |
87 | // Remove any uppercase / comma / dots
88 | return strtolower(preg_replace('/[.,]/', '', implode(' ', $words)));
89 | }
90 |
91 | public function sentencesAsArray(int $sentences = 3): array
92 | {
93 | return $this->pickArrayRandomElements($this->flattenedSentences(), $sentences);
94 | }
95 |
96 | public function sentences(int $sentences = 3): string
97 | {
98 | $sentences = $this->sentencesAsArray($sentences);
99 | $sentences = array_map(function ($sentence) { return implode(' ', $sentence); }, $sentences);
100 |
101 | return implode(' ', $sentences);
102 | }
103 |
104 | public function paragraphsAsArray(int $paragraphs = 3): array
105 | {
106 | return $this->pickArrayRandomElements($this->paragraphs, $paragraphs);
107 | }
108 |
109 | public function paragraphs(int $paragraphs = 3): string
110 | {
111 | $paragraphs = $this->paragraphsAsArray($paragraphs);
112 | $paragraphs = array_map(function ($sentences) { return implode(' ', array_merge(...$sentences)); }, $paragraphs);
113 |
114 | return implode(PHP_EOL, $paragraphs);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/Extensions/Traits/HasLocale.php:
--------------------------------------------------------------------------------
1 | locale = $locale;
22 | }
23 |
24 | public function __call(string $method, array $parameters)
25 | {
26 | // We simply redirect calls to container to create a new container for each faker call
27 | return (new Container())->locale($this->locale)->{$method}(...$parameters);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/FakerServiceProvider.php:
--------------------------------------------------------------------------------
1 | extensions([
23 | TextExtension::class,
24 | NumbersExtension::class,
25 | StringsExtension::class,
26 | HashExtension::class,
27 | DateTimeExtension::class,
28 | InternetExtension::class,
29 | ColorsExtension::class,
30 | PersonExtension::class,
31 | FinancialExtension::class,
32 | BooleanExtension::class,
33 | ArrayExtension::class,
34 | ]);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Manifests/ContainerMixinManifest.php:
--------------------------------------------------------------------------------
1 | basePath = $basePath;
46 | $this->vendorPath = $basePath.'/vendor';
47 | $this->containerMixinPath = $containerMixinPath ?? $basePath.'/_faker_helper.php';
48 | }
49 |
50 | /**
51 | * Build the manifest only if it should.
52 | *
53 | * @param array $extensions
54 | * @param array $extensionMethods
55 | *
56 | * @return void
57 | */
58 | public function buildIfShould(array $extensionMethods, array $extensions)
59 | {
60 | if ($this->shouldRecompile()) {
61 | $this->build($extensionMethods, $extensions);
62 | }
63 | }
64 |
65 | /**
66 | * Build the manifest and write it to disk.
67 | *
68 | * @param array $extensions
69 | * @param array $extensionMethods
70 | *
71 | * @return void
72 | */
73 | public function build(array $extensionMethods, array $extensions)
74 | {
75 | $tags = [];
76 |
77 | foreach ($extensionMethods as $methodName => $extensionName) {
78 | $extension = $extensions[$extensionName];
79 |
80 | // If the extension is localized we look for the first containing the method
81 | if (is_array($extension) && isset($extension['locales'])) {
82 | $extension = current(array_filter($extension['locales'], function ($extensionFiltered) use ($methodName) {
83 | return method_exists($extensionFiltered, $methodName);
84 | }));
85 | }
86 |
87 | $reflectionMethod = new \ReflectionMethod($extension, $methodName);
88 |
89 | $parameters = [];
90 | $typeResolver = new TypeResolver();
91 |
92 | foreach ($reflectionMethod->getParameters() as $parameter) {
93 | $type = new Mixed_();
94 |
95 | if ($parameter->hasType()) {
96 | $type = $parameter->getType();
97 |
98 | if ($type instanceof \ReflectionUnionType) {
99 | $type = new Compound(
100 | array_map(
101 | fn ($type) => $typeResolver->resolve($type),
102 | $type->getTypes()
103 | )
104 | );
105 | } else {
106 | $type = $typeResolver->resolve($type->getName());
107 | }
108 |
109 | if ($parameter->allowsNull()) {
110 | $type = new Nullable($type);
111 | }
112 | }
113 |
114 | $parameters[] = new DocBlock\Tags\MethodParameter(
115 | name: $parameter->getName(),
116 | type: $type,
117 | defaultValue: $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : DocBlock\Tags\MethodParameter::NO_DEFAULT_VALUE
118 | );
119 | }
120 |
121 | $tags[] = new Method(
122 | $methodName,
123 | returnType: $reflectionMethod->hasReturnType() ? (new TypeResolver())->resolve($reflectionMethod->getReturnType()) : new Mixed_(),
124 | parameters: $parameters,
125 | );
126 | }
127 |
128 | $docBlock = new DocBlock(tags: $tags);
129 |
130 | $serializer = new Serializer();
131 |
132 | $this->write(
133 | $serializer->getDocComment($docBlock)
134 | );
135 | }
136 |
137 | /**
138 | * Determine if the manifest should be compiled.
139 | *
140 | * @return bool
141 | */
142 | public function shouldRecompile(): bool
143 | {
144 | return !is_file($this->containerMixinPath) ||
145 | // We check here if the manifest has been generated before changing the installed.json composer file
146 | filemtime($this->containerMixinPath) <= filemtime($this->vendorPath.'/composer/installed.json');
147 | }
148 |
149 | /**
150 | * Write the given manifest docblock to disk.
151 | *
152 | * @param string $docComment
153 | *
154 | * @return void
155 | */
156 | protected function write(string $docComment): void
157 | {
158 | if (!is_writable(dirname($this->containerMixinPath))) {
159 | throw new Exception('The '.dirname($this->containerMixinPath).' directory must be present and writable.');
160 | }
161 |
162 | file_put_contents(
163 | $this->containerMixinPath,
164 | "basePath = $basePath;
48 | $this->vendorPath = $basePath.'/vendor';
49 | $this->manifestPath = $manifestPath;
50 | }
51 |
52 | /**
53 | * Get all of the service provider class names for all packages.
54 | *
55 | * @return array
56 | */
57 | public function providers()
58 | {
59 | return $this->config('providers');
60 | }
61 |
62 | /**
63 | * Get all of the values for all packages for the given configuration name.
64 | *
65 | * @param string $key
66 | *
67 | * @return array
68 | */
69 | public function config($key)
70 | {
71 | return array_filter(
72 | array_map(
73 | function ($configuration) use ($key) {
74 | return (array) ($configuration[$key] ?? []);
75 | },
76 | $this->getManifest()
77 | )
78 | );
79 | }
80 |
81 | /**
82 | * Get the current package manifest.
83 | *
84 | * @return array
85 | */
86 | protected function getManifest()
87 | {
88 | if (!empty($this->manifest)) {
89 | return $this->manifest;
90 | }
91 |
92 | if ($this->shouldRecompile()) {
93 | $this->build();
94 | }
95 |
96 | return $this->manifest = is_file($this->manifestPath) ?
97 | (require $this->manifestPath) : [];
98 | }
99 |
100 | /**
101 | * Build the manifest and write it to disk.
102 | *
103 | * @return void
104 | */
105 | public function build()
106 | {
107 | $packages = [];
108 |
109 | if (is_file($path = $this->vendorPath.'/composer/installed.json')) {
110 | $installed = json_decode(file_get_contents($path), true);
111 |
112 | $packages = $installed['packages'] ?? $installed;
113 | }
114 |
115 | $packagesToProvide = [];
116 |
117 | foreach ($packages as $package) {
118 | if (isset($package['extra']['faker'])) {
119 | $packagesToProvide[$package['name']] = $package['extra']['faker'];
120 | }
121 | }
122 |
123 | $this->write(
124 | $packagesToProvide
125 | );
126 | }
127 |
128 | /**
129 | * Determine if the manifest should be compiled.
130 | *
131 | * @return bool
132 | */
133 | public function shouldRecompile(): bool
134 | {
135 | return !is_file($this->manifestPath) ||
136 | // We check here if the manifest has been generated before changing the installed.json composer file
137 | filemtime($this->manifestPath) <= filemtime($this->vendorPath.'/composer/installed.json');
138 | }
139 |
140 | /**
141 | * Write the given manifest array to disk.
142 | *
143 | * @param array $manifest
144 | *
145 | * @throws \Exception
146 | *
147 | * @return void
148 | */
149 | protected function write(array $manifest): void
150 | {
151 | if (!is_writable($dirname = dirname($this->manifestPath))) {
152 | throw new Exception("The {$dirname} directory must be present and writable.");
153 | }
154 |
155 | file_put_contents(
156 | $this->manifestPath,
157 | ' 60% chance of null).
11 | *
12 | * @var int
13 | */
14 | protected int $weight;
15 |
16 | protected Randomizer $randomizer;
17 |
18 | public function __construct(Randomizer $randomizer, int $weight = 50)
19 | {
20 | $this->randomizer = $randomizer;
21 | $this->weight = $weight;
22 | }
23 |
24 | /**
25 | * Handle the given modifier.
26 | *
27 | * @param mixed $generatedValue
28 | *
29 | * @return mixed
30 | */
31 | public function apply(mixed $generatedValue): mixed
32 | {
33 | if ($this->randomizer->getInt(0, 100) < $this->weight) {
34 | return null;
35 | }
36 |
37 | return $generatedValue;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Modifiers/UppercaseModifier.php:
--------------------------------------------------------------------------------
1 | resolveExtensions($extensions);
20 | });
21 | }
22 |
23 | /**
24 | * Bootstrap any package services.
25 | */
26 | public function boot(): void
27 | {
28 | //
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Providers/ProviderRepository.php:
--------------------------------------------------------------------------------
1 | createProvider($provider);
18 |
19 | $instance->boot();
20 | }
21 | }
22 |
23 | /**
24 | * Create a new provider instance.
25 | *
26 | * @param string $provider
27 | *
28 | * @return \Xefi\Faker\Providers\Provider
29 | */
30 | public function createProvider($provider): Provider
31 | {
32 | if (is_object($provider)) {
33 | return $provider;
34 | }
35 |
36 | return new $provider();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Seeds/HasSeeds.php:
--------------------------------------------------------------------------------
1 | regex = $regex;
12 | }
13 |
14 | /**
15 | * Handle the given strategy.
16 | *
17 | * @param mixed $generatedValue
18 | *
19 | * @return bool
20 | */
21 | public function pass(mixed $generatedValue): bool
22 | {
23 | return (bool) preg_match($this->regex, $generatedValue);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Strategies/Strategy.php:
--------------------------------------------------------------------------------
1 | tried, true)) {
28 | return false;
29 | }
30 |
31 | $this->tried[] = $generatedValue;
32 |
33 | return true;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/Support/Extensions/EnEnExtensionTest.php:
--------------------------------------------------------------------------------
1 | getLocale();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Support/Extensions/EnUsExtensionTest.php:
--------------------------------------------------------------------------------
1 | getLocale();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Support/Extensions/FrFrExtensionTest.php:
--------------------------------------------------------------------------------
1 | getLocale();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Support/Extensions/MixinTestExtension.php:
--------------------------------------------------------------------------------
1 | getLocale();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tests/Support/Extensions/NumberTestExtension.php:
--------------------------------------------------------------------------------
1 | extensions([
14 | NumberTestExtension::class,
15 | StringTestExtension::class,
16 | ]);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tests/Support/vendor/composer/installed.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | {
4 | "name": "autoload-needed",
5 | "extra": {
6 | "faker": {
7 | "providers": [
8 | "Xefi\\Faker\\Tests\\Support\\TestServiceProvider"
9 | ]
10 | }
11 | }
12 | },
13 | {
14 | "name": "common-package",
15 | "extra": {
16 | "branch-alias": {
17 | "dev-master": "2.0.x-dev"
18 | }
19 | }
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/tests/Unit/Calculators/IbanTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($checksum, Iban::checksum($iban), $iban);
88 | }
89 |
90 | public static function validatorProvider()
91 | {
92 | return [
93 | ['AL47212110090000000235698741', true],
94 | ['AD1200012030200359100100', true],
95 | ['AT611904300234573201', true],
96 | ['AZ21NABZ00000000137010001944', true],
97 | ['BH67BMAG00001299123456', true],
98 | ['BE68539007547034', true],
99 | ['BA391290079401028494', true],
100 | ['BR7724891749412660603618210F3', true],
101 | ['BG80BNBG96611020345678', true],
102 | ['CR0515202001026284066', true],
103 | ['HR1210010051863000160', true],
104 | ['CY17002001280000001200527600', true],
105 | ['CZ6508000000192000145399', true],
106 | ['DK5000400440116243', true],
107 | ['DO28BAGR00000001212453611324', true],
108 | ['EE382200221020145685', true],
109 | ['FO6264600001631634', true],
110 | ['FI2112345600000785', true],
111 | ['FR1420041010050500013M02606', true],
112 | ['GE29NB0000000101904917', true],
113 | ['DE89370400440532013000', true],
114 | ['GI75NWBK000000007099453', true],
115 | ['GR1601101250000000012300695', true],
116 | ['GL8964710001000206', true],
117 | ['GT82TRAJ01020000001210029690', true],
118 | ['HU42117730161111101800000000', true],
119 | ['IS140159260076545510730339', true],
120 | ['IE29AIBK93115212345678', true],
121 | ['IL620108000000099999999', true],
122 | ['IT60X0542811101000000123456', true],
123 | ['KZ86125KZT5004100100', true],
124 | ['KW81CBKU0000000000001234560101', true],
125 | ['LV80BANK0000435195001', true],
126 | ['LB62099900000001001901229114', true],
127 | ['LI21088100002324013AA', true],
128 | ['LT121000011101001000', true],
129 | ['LU280019400644750000', true],
130 | ['MK07250120000058984', true],
131 | ['MT84MALT011000012345MTLCAST001S', true],
132 | ['MR1300020001010000123456753', true],
133 | ['MU17BOMM0101101030300200000MUR', true],
134 | ['MD24AG000225100013104168', true],
135 | ['MC5811222000010123456789030', true],
136 | ['ME25505000012345678951', true],
137 | ['NL91ABNA0417164300', true],
138 | ['NO9386011117947', true],
139 | ['PK36SCBL0000001123456702', true],
140 | ['PL61109010140000071219812874', true],
141 | ['PS92PALS000000000400123456702', true],
142 | ['PT50000201231234567890154', true],
143 | ['QA58DOHB00001234567890ABCDEFG', true],
144 | ['RO49AAAA1B31007593840000', true],
145 | ['SM86U0322509800000000270100', true],
146 | ['SA0380000000608010167519', true],
147 | ['RS35260005601001611379', true],
148 | ['SK3112000000198742637541', true],
149 | ['SI56263300012039086', true],
150 | ['ES9121000418450200051332', true],
151 | ['SE4550000000058398257466', true],
152 | ['CH9300762011623852957', true],
153 | ['TN5910006035183598478831', true],
154 | ['TR330006100519786457841326', true],
155 | ['AE070331234567890123456', true],
156 | ['GB29NWBK60161331926819', true],
157 | ['VG96VPVG0000012345678901', true],
158 | ['YY24KIHB12476423125915947930915268', true],
159 | ['ZZ25VLQT382332233206588011313776421', true],
160 |
161 | ['AL4721211009000000023569874', false],
162 | ['AD120001203020035910010', false],
163 | ['AT61190430023457320', false],
164 | ['AZ21NABZ0000000013701000194', false],
165 | ['BH67BMAG0000129912345', false],
166 | ['BE6853900754703', false],
167 | ['BA39129007940102849', false],
168 | ['BR7724891749412660603618210F', false],
169 | ['BG80BNBG9661102034567', false],
170 | ['CR051520200102628406', false],
171 | ['HR121001005186300016', false],
172 | ['CY1700200128000000120052760', false],
173 | ['CZ650800000019200014539', false],
174 | ['DK500040044011624', false],
175 | ['DO28BAGR0000000121245361132', false],
176 | ['EE38220022102014568', false],
177 | ['FO626460000163163', false],
178 | ['FI2112345600000780', false],
179 | ['FR1420041010050500013M0260', false],
180 | ['GE29NB000000010190491', false],
181 | ['DE8937040044053201300', false],
182 | ['GI75NWBK00000000709945', false],
183 | ['GR160110125000000001230069', false],
184 | ['GL896471000100020', false],
185 | ['GT82TRAJ0102000000121002969', false],
186 | ['HU4211773016111110180000000', false],
187 | ['IS14015926007654551073033', false],
188 | ['IE29AIBK9311521234567', false],
189 | ['IL62010800000009999999', false],
190 | ['IT60X054281110100000012345', false],
191 | ['KZ86125KZT500410010', false],
192 | ['KW81CBKU000000000000123456010', false],
193 | ['LV80BANK000043519500', false],
194 | ['LB6209990000000100190122911', false],
195 | ['LI21088100002324013A', false],
196 | ['LT12100001110100100', false],
197 | ['LU28001940064475000', false],
198 | ['MK0725012000005898', false],
199 | ['MT84MALT011000012345MTLCAST001', false],
200 | ['MR130002000101000012345675', false],
201 | ['MU17BOMM0101101030300200000MU', false],
202 | ['MD24AG00022510001310416', false],
203 | ['MC58112220000101234567890', false],
204 | ['ME2550500001234567895', false],
205 | ['NL91ABNA041716430', false],
206 | ['NO938601111794', false],
207 | ['PK36SCBL000000112345670', false],
208 | ['PL6110901014000007121981287', false],
209 | ['PS92PALS00000000040012345670', false],
210 | ['PT5000020123123456789015', false],
211 | ['QA58DOHB00001234567890ABCDEF', false],
212 | ['RO49AAAA1B3100759384000', false],
213 | ['SM86U032250980000000027010', false],
214 | ['SA038000000060801016751', false],
215 | ['RS3526000560100161137', false],
216 | ['SK311200000019874263754', false],
217 | ['SI5626330001203908', false],
218 | ['ES912100041845020005133', false],
219 | ['SE455000000005839825746', false],
220 | ['CH930076201162385295', false],
221 | ['TN591000603518359847883', false],
222 | ['TR33000610051978645784132', false],
223 | ['AE07033123456789012345', false],
224 | ['GB29NWBK6016133192681', false],
225 | ['VG96VPVG000001234567890', false],
226 | ['YY24KIHB1247642312591594793091526', false],
227 | ['ZZ25VLQT38233223320658801131377642', false],
228 | ];
229 | }
230 |
231 | #[DataProvider('validatorProvider')]
232 | public function testIsValid($iban, $isValid): void
233 | {
234 | $this->assertEquals($isValid, Iban::isValid($iban), $iban);
235 | }
236 |
237 | public static function alphaToNumberProvider()
238 | {
239 | return [
240 | ['A', 10],
241 | ['B', 11],
242 | ['C', 12],
243 | ['D', 13],
244 | ['E', 14],
245 | ['F', 15],
246 | ['G', 16],
247 | ['H', 17],
248 | ['I', 18],
249 | ['J', 19],
250 | ['K', 20],
251 | ['L', 21],
252 | ['M', 22],
253 | ['N', 23],
254 | ['O', 24],
255 | ['P', 25],
256 | ['Q', 26],
257 | ['R', 27],
258 | ['S', 28],
259 | ['T', 29],
260 | ['U', 30],
261 | ['V', 31],
262 | ['W', 32],
263 | ['X', 33],
264 | ['Y', 34],
265 | ['Z', 35],
266 | ];
267 | }
268 |
269 | #[DataProvider('alphaToNumberProvider')]
270 | public function testAlphaToNumber($letter, $number): void
271 | {
272 | self::assertEquals($number, Iban::alphaToNumber($letter), $letter);
273 | }
274 |
275 | public static function mod97Provider()
276 | {
277 | // Large numbers
278 | $return = [
279 | ['123456789123456789', 7],
280 | ['111222333444555666', 73],
281 | ['4242424242424242424242', 19],
282 | ['271828182845904523536028', 68],
283 | ];
284 |
285 | // 0-200
286 | for ($i = 0; $i < 200; $i++) {
287 | $return[] = [(string) $i, $i % 97];
288 | }
289 |
290 | return $return;
291 | }
292 |
293 | #[DataProvider('mod97Provider')]
294 | public function testMod97($number, $result): void
295 | {
296 | self::assertEquals($result, Iban::mod97($number), $number);
297 | }
298 | }
299 |
--------------------------------------------------------------------------------
/tests/Unit/Calculators/LuhnTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($isValid, Luhn::isValid((string) $number));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/Unit/ContainerMixinManifestTest.php:
--------------------------------------------------------------------------------
1 | forgetExtensions();
15 | $container->resolveExtensions([
16 | \Xefi\Faker\Tests\Support\Extensions\MixinTestExtension::class,
17 | ]);
18 | }
19 |
20 | public function testContainerMixinBuild()
21 | {
22 | @unlink('/tmp/ContainerMixin.php');
23 | $container = new \Xefi\Faker\Container\Container(shouldBuildContainerMixin: false);
24 | $manifest = new \Xefi\Faker\Manifests\ContainerMixinManifest(__DIR__.'/../Support', '/tmp/ContainerMixin.php');
25 | $manifest->build($container->getExtensionMethods(), $container->getExtensions());
26 |
27 | $this->assertFileExists('/tmp/ContainerMixin.php');
28 |
29 | $containerMixinContent = file_get_contents('/tmp/ContainerMixin.php');
30 |
31 | $this->assertStringContainsString(
32 | '@method mixed withoutParameters()',
33 | $containerMixinContent
34 | );
35 |
36 | $this->assertStringContainsString(
37 | '@method mixed withNoTypeParameters(mixed $one, mixed $two)',
38 | $containerMixinContent
39 | );
40 |
41 | $this->assertStringContainsString(
42 | '@method mixed withTypedParameters(int $one, string $two)',
43 | $containerMixinContent
44 | );
45 |
46 | $this->assertStringContainsString(
47 | '@method void withVoidReturnType()',
48 | $containerMixinContent
49 | );
50 |
51 | $this->assertStringContainsString(
52 | '@method string withStringReturnType()',
53 | $containerMixinContent
54 | );
55 |
56 | $this->assertStringContainsString(
57 | '@method string withNullableParameter(?string $one = \'default value\')',
58 | $containerMixinContent
59 | );
60 |
61 | $this->assertStringContainsString(
62 | '@method string|int withCompoundType(string|int $param)',
63 | $containerMixinContent
64 | );
65 |
66 | $this->assertStringNotContainsString(
67 | '@method string|int withCompoundType(string&int $param)',
68 | $containerMixinContent
69 | );
70 |
71 | unlink('/tmp/ContainerMixin.php');
72 | }
73 |
74 | public function testContainerMixinNamespace()
75 | {
76 | @unlink('/tmp/ContainerMixin.php');
77 | $container = new \Xefi\Faker\Container\Container(shouldBuildContainerMixin: false);
78 | $manifest = new \Xefi\Faker\Manifests\ContainerMixinManifest(__DIR__.'/../Support', '/tmp/ContainerMixin.php');
79 | $manifest->build($container->getExtensionMethods(), $container->getExtensions());
80 |
81 | $this->assertFileExists('/tmp/ContainerMixin.php');
82 |
83 | $containerMixinContent = file_get_contents('/tmp/ContainerMixin.php');
84 |
85 | $this->assertStringContainsString(
86 | 'namespace Xefi\\Faker\\Container;',
87 | $containerMixinContent
88 | );
89 |
90 | unlink('/tmp/ContainerMixin.php');
91 | }
92 |
93 | public function testShouldRecompile()
94 | {
95 | @unlink('/tmp/ContainerMixin.php');
96 | $container = new \Xefi\Faker\Container\Container(shouldBuildContainerMixin: false);
97 | $manifest = new \Xefi\Faker\Manifests\ContainerMixinManifest(__DIR__.'/../Support', '/tmp/ContainerMixin.php');
98 | $manifest->build($container->getExtensionMethods(), $container->getExtensions());
99 | touch(__DIR__.'/../Support/vendor/composer/installed.json', time() - 1);
100 |
101 | $this->assertFalse($manifest->shouldRecompile());
102 |
103 | // Test on current time
104 | touch(__DIR__.'/../Support/vendor/composer/installed.json');
105 | $this->assertTrue($manifest->shouldRecompile());
106 |
107 | // Test on future
108 | touch(__DIR__.'/../Support/vendor/composer/installed.json', time() + 1);
109 | $this->assertTrue($manifest->shouldRecompile());
110 |
111 | unlink('/tmp/ContainerMixin.php');
112 | }
113 |
114 | public function testNoExtension()
115 | {
116 | @unlink('/tmp/ContainerMixin.php');
117 | $container = new \Xefi\Faker\Container\Container(shouldBuildContainerMixin: false);
118 | $container->forgetExtensions();
119 |
120 | $manifest = new \Xefi\Faker\Manifests\ContainerMixinManifest(__DIR__.'/../Support', '/tmp/ContainerMixin.php');
121 | $manifest->build($container->getExtensionMethods(), $container->getExtensions());
122 |
123 | $this->assertFileExists('/tmp/ContainerMixin.php');
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/tests/Unit/ContainerTest.php:
--------------------------------------------------------------------------------
1 | assertFileExists('/tmp/packages.php');
21 |
22 | unlink('/tmp/packages.php');
23 | }
24 |
25 | public function testExtensionsCorrectlyRegistered(): void
26 | {
27 | @unlink('/tmp/packages.php');
28 |
29 | $container = new Container();
30 |
31 | $this->assertEquals(
32 | [
33 | 'number-test-extension' => new NumberTestExtension(new Randomizer()),
34 | 'string-test-extension' => new StringTestExtension(new Randomizer()),
35 | ],
36 | $container->getExtensions()
37 | );
38 |
39 | unlink('/tmp/packages.php');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/Unit/ExtensionTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(
17 | 'hello',
18 | $container->returnHello()
19 | );
20 | }
21 |
22 | public function testExtensionReturnOne(): void
23 | {
24 | $container = new Container();
25 |
26 | $this->assertEquals(
27 | 1,
28 | $container->returnOne()
29 | );
30 | }
31 |
32 | public function testExtensionPickArrayRandomElements(): void
33 | {
34 | $elements = range(1, 100);
35 |
36 | $method = (new ReflectionClass(Extension::class))->getMethod('pickArrayRandomElements');
37 | $result = $method->invoke(new Extension(new Randomizer()), $elements, 5);
38 |
39 | $this->assertCount(
40 | 5,
41 | $result
42 | );
43 |
44 | foreach ($result as $item) {
45 | $this->assertGreaterThanOrEqual(1, $item);
46 | $this->assertLessThanOrEqual(100, $item);
47 | }
48 | }
49 |
50 | public function testExtensionPickArrayRandomElement(): void
51 | {
52 | $elements = range(1, 100);
53 |
54 | $method = (new ReflectionClass(Extension::class))->getMethod('pickArrayRandomElement');
55 | $result = $method->invoke(new Extension(new Randomizer()), $elements);
56 |
57 | $this->assertIsNotArray($result);
58 | $this->assertGreaterThanOrEqual(1, $result);
59 | $this->assertLessThanOrEqual(100, $result);
60 | }
61 |
62 | public function testExtensionPickArrayRandomKeys(): void
63 | {
64 | $elements = [
65 | 'a' => 1,
66 | 'b' => 2,
67 | 'c' => 3,
68 | 'd' => 4,
69 | 'e' => 5,
70 | ];
71 |
72 | $method = (new ReflectionClass(Extension::class))->getMethod('pickArrayRandomKeys');
73 | $result = $method->invoke(new Extension(new Randomizer()), $elements, 3);
74 |
75 | $this->assertCount(
76 | 3,
77 | $result
78 | );
79 |
80 | foreach ($result as $key) {
81 | $this->assertArrayHasKey($key, $elements);
82 | $this->assertIsString($key);
83 | }
84 | }
85 |
86 | public function testExtensionPickArrayRandomKey(): void
87 | {
88 | $elements = [
89 | 'a' => 1,
90 | 'b' => 2,
91 | 'c' => 3,
92 | 'd' => 4,
93 | 'e' => 5,
94 | ];
95 |
96 | $method = (new ReflectionClass(Extension::class))->getMethod('pickArrayRandomKeyNumber');
97 | $result = $method->invoke(new Extension(new Randomizer()), $elements);
98 |
99 | $this->assertArrayHasKey($result, $elements);
100 | $this->assertIsString($result);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/ArraysExtensionTest.php:
--------------------------------------------------------------------------------
1 | testArray = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5];
14 | }
15 |
16 | public function testRandomElement(): void
17 | {
18 | $elements = [];
19 | for ($i = 0; $i < count($this->testArray); $i++) {
20 | $elements[] = $this->faker->unique()->randomElement($this->testArray);
21 | }
22 |
23 | $this->assertEqualsCanonicalizing($elements, $this->testArray);
24 | }
25 |
26 | public function testRandomKeyNumber(): void
27 | {
28 | $elements = [];
29 | for ($i = 0; $i < count($this->testArray); $i++) {
30 | $elements[] = $this->faker->unique()->randomKeyNumber($this->testArray);
31 | }
32 |
33 | $this->assertEqualsCanonicalizing($elements, array_keys($this->testArray));
34 | }
35 |
36 | public function testRandomKey(): void
37 | {
38 | $inputArray = [
39 | ['firstname' => 'John'],
40 | ['lastname' => 'Doe'],
41 | ['nickname' => 'Johnny'],
42 | ['login' => 'j.doe'],
43 | ];
44 |
45 | $result = $this->faker->randomKey($inputArray);
46 | $this->assertContains($result, ['firstname', 'lastname', 'nickname', 'login']);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/BooleanExtensionTest.php:
--------------------------------------------------------------------------------
1 | faker->unique()->boolean();
14 | }
15 |
16 | $this->assertEqualsCanonicalizing($results, [true, false]);
17 | }
18 |
19 | public function testBooleanAlwaysTrue(): void
20 | {
21 | for ($i = 0; $i < 100; $i++) {
22 | $this->assertTrue($this->faker->boolean(100));
23 | }
24 | }
25 |
26 | public function testBooleanAlwaysFalse(): void
27 | {
28 | for ($i = 0; $i < 100; $i++) {
29 | $this->assertFalse($this->faker->boolean(0));
30 | }
31 | }
32 |
33 | public function testBooleanWithDefaultPercentage(): void
34 | {
35 | $trueCount = 0;
36 | $falseCount = 0;
37 |
38 | for ($i = 0; $i < 1000; $i++) {
39 | if ($this->faker->boolean()) {
40 | $trueCount++;
41 | } else {
42 | $falseCount++;
43 | }
44 | }
45 |
46 | // We expect 50% of "true" so we check that there is minimum 45% of each value
47 | $this->assertGreaterThan(450, $trueCount);
48 | $this->assertGreaterThan(450, $falseCount);
49 | }
50 |
51 | public function testBooleanWithPercentage(): void
52 | {
53 | $trueCount = 0;
54 | $falseCount = 0;
55 |
56 | for ($i = 0; $i < 1000; $i++) {
57 | if ($this->faker->boolean(30)) {
58 | $trueCount++;
59 | } else {
60 | $falseCount++;
61 | }
62 | }
63 |
64 | // We expect 30% of "true" so we check that there is minimum 25% of "true" and 65% of "false"
65 | $this->assertGreaterThan(250, $trueCount);
66 | $this->assertGreaterThan(650, $falseCount);
67 | }
68 |
69 | public function testBooleanWithPercentageLowerThan100(): void
70 | {
71 | $this->expectException(BadParameterException::class);
72 | $this->faker->boolean(-1);
73 | }
74 |
75 | public function testBooleanWithPercentageGreaterThan100(): void
76 | {
77 | $this->expectException(BadParameterException::class);
78 | $this->faker->boolean(101);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/ColorsExtensionTest.php:
--------------------------------------------------------------------------------
1 | safeColorNames = (new \ReflectionClass($colorExtension))->getProperty('safeColorNames')->getValue($colorExtension);
19 | $this->colorNames = (new \ReflectionClass($colorExtension))->getProperty('colorNames')->getValue($colorExtension);
20 | }
21 |
22 | public function testSafeColorName(): void
23 | {
24 | $results = [];
25 | for ($i = 0; $i < count($this->safeColorNames); $i++) {
26 | $results[] = $this->faker->unique()->safeColorName();
27 | }
28 |
29 | $this->assertEqualsCanonicalizing(
30 | $this->safeColorNames,
31 | $results
32 | );
33 | }
34 |
35 | public function testColorName(): void
36 | {
37 | $results = [];
38 | for ($i = 0; $i < count($this->colorNames); $i++) {
39 | $results[] = $this->faker->unique()->colorName();
40 | }
41 |
42 | $this->assertEqualsCanonicalizing(
43 | $this->colorNames,
44 | $results
45 | );
46 | }
47 |
48 | public function testSafeHexColor(): void
49 | {
50 | for ($i = 0; $i < 100; $i++) {
51 | $color = $this->faker->unique()->safeHexColor();
52 |
53 | $this->assertStringStartsWith('#', $color);
54 | $this->assertTrue(ctype_xdigit(substr($color, 1)));
55 | $this->assertEquals(7, strlen($color));
56 | }
57 | }
58 |
59 | public function testHexColor(): void
60 | {
61 | for ($i = 0; $i < 100; $i++) {
62 | $color = $this->faker->unique()->hexColor();
63 |
64 | $this->assertStringStartsWith('#', $color);
65 | $this->assertTrue(ctype_xdigit(substr($color, 1)));
66 | $this->assertEquals(7, strlen($color));
67 | }
68 | }
69 |
70 | public function testRgbColorAsArray(): void
71 | {
72 | for ($i = 0; $i < 100; $i++) {
73 | $color = $this->faker->unique()->rgbColorAsArray();
74 |
75 | $this->assertCount(3, $color);
76 |
77 | // Red
78 | $this->assertGreaterThanOrEqual(0, $color[0]);
79 | $this->assertLessThanOrEqual(255, $color[0]);
80 |
81 | // Green
82 | $this->assertGreaterThanOrEqual(0, $color[1]);
83 | $this->assertLessThanOrEqual(255, $color[1]);
84 |
85 | // Blue
86 | $this->assertGreaterThanOrEqual(0, $color[2]);
87 | $this->assertLessThanOrEqual(255, $color[2]);
88 | }
89 | }
90 |
91 | public function testRgbColor(): void
92 | {
93 | $regex = '/^(\d+),(\d+),(\d+)$/';
94 |
95 | for ($i = 0; $i < 100; $i++) {
96 | $color = $this->faker->unique()->rgbColor();
97 | preg_match($regex, $color, $matches);
98 |
99 | /// Red
100 | $this->assertGreaterThanOrEqual(0, $matches[1]);
101 | $this->assertLessThanOrEqual(255, $matches[1]);
102 |
103 | // Green
104 | $this->assertGreaterThanOrEqual(0, $matches[2]);
105 | $this->assertLessThanOrEqual(255, $matches[2]);
106 |
107 | // Blue
108 | $this->assertGreaterThanOrEqual(0, $matches[3]);
109 | $this->assertLessThanOrEqual(255, $matches[3]);
110 | }
111 | }
112 |
113 | public function testRgbCssColor(): void
114 | {
115 | $regex = '/^rgb\((\d+),(\d+),(\d+)\)$/';
116 |
117 | for ($i = 0; $i < 100; $i++) {
118 | $color = $this->faker->unique()->rgbCssColor();
119 | preg_match($regex, $color, $matches);
120 |
121 | // String
122 | $this->assertStringStartsWith('rgb(', $color);
123 | $this->assertStringEndsWith(')', $color);
124 |
125 | /// Red
126 | $this->assertGreaterThanOrEqual(0, $matches[1]);
127 | $this->assertLessThanOrEqual(255, $matches[1]);
128 |
129 | // Green
130 | $this->assertGreaterThanOrEqual(0, $matches[2]);
131 | $this->assertLessThanOrEqual(255, $matches[2]);
132 |
133 | // Blue
134 | $this->assertGreaterThanOrEqual(0, $matches[3]);
135 | $this->assertLessThanOrEqual(255, $matches[3]);
136 | }
137 | }
138 |
139 | public function testRgbaColorAsArray(): void
140 | {
141 | for ($i = 0; $i < 100; $i++) {
142 | $color = $this->faker->unique()->rgbaColorAsArray();
143 |
144 | $this->assertCount(4, $color);
145 |
146 | // Red
147 | $this->assertGreaterThanOrEqual(0, $color[0]);
148 | $this->assertLessThanOrEqual(255, $color[0]);
149 |
150 | // Green
151 | $this->assertGreaterThanOrEqual(0, $color[1]);
152 | $this->assertLessThanOrEqual(255, $color[1]);
153 |
154 | // Blue
155 | $this->assertGreaterThanOrEqual(0, $color[2]);
156 | $this->assertLessThanOrEqual(255, $color[2]);
157 |
158 | // Alpha
159 | $this->assertGreaterThanOrEqual(0, $color[3]);
160 | $this->assertLessThanOrEqual(1, $color[3]);
161 | }
162 | }
163 |
164 | public function testRgbaColor(): void
165 | {
166 | $regex = '/^(\d+),(\d+),(\d+),([01]|0\.\d+)$/';
167 |
168 | for ($i = 0; $i < 100; $i++) {
169 | $color = $this->faker->unique()->rgbaColor();
170 | preg_match($regex, $color, $matches);
171 |
172 | /// Red
173 | $this->assertGreaterThanOrEqual(0, $matches[1]);
174 | $this->assertLessThanOrEqual(255, $matches[1]);
175 |
176 | // Green
177 | $this->assertGreaterThanOrEqual(0, $matches[2]);
178 | $this->assertLessThanOrEqual(255, $matches[2]);
179 |
180 | // Blue
181 | $this->assertGreaterThanOrEqual(0, $matches[3]);
182 | $this->assertLessThanOrEqual(255, $matches[3]);
183 |
184 | // Alpha
185 | $this->assertGreaterThanOrEqual(0, $matches[4]);
186 | $this->assertLessThanOrEqual(1, $matches[4]);
187 | }
188 | }
189 |
190 | public function testRgbaCssColor(): void
191 | {
192 | $regex = '/^rgba\((\d+),(\d+),(\d+),([01]|0\.\d+)\)$/';
193 |
194 | for ($i = 0; $i < 100; $i++) {
195 | $color = $this->faker->unique()->rgbaCssColor();
196 | preg_match($regex, $color, $matches);
197 |
198 | // String
199 | $this->assertStringStartsWith('rgba(', $color);
200 | $this->assertStringEndsWith(')', $color);
201 |
202 | /// Red
203 | $this->assertGreaterThanOrEqual(0, $matches[1]);
204 | $this->assertLessThanOrEqual(255, $matches[1]);
205 |
206 | // Green
207 | $this->assertGreaterThanOrEqual(0, $matches[2]);
208 | $this->assertLessThanOrEqual(255, $matches[2]);
209 |
210 | // Blue
211 | $this->assertGreaterThanOrEqual(0, $matches[3]);
212 | $this->assertLessThanOrEqual(255, $matches[3]);
213 |
214 | // Alpha
215 | $this->assertGreaterThanOrEqual(0, $matches[4]);
216 | $this->assertLessThanOrEqual(1, $matches[4]);
217 | }
218 | }
219 |
220 | public function testHslColorAsArray(): void
221 | {
222 | for ($i = 0; $i < 100; $i++) {
223 | $color = $this->faker->unique()->hslColorAsArray();
224 |
225 | $this->assertCount(3, $color);
226 |
227 | // HUE
228 | $this->assertGreaterThanOrEqual(0, $color[0]);
229 | $this->assertLessThanOrEqual(360, $color[0]);
230 |
231 | // Saturation
232 | $this->assertGreaterThanOrEqual(0, $color[1]);
233 | $this->assertLessThanOrEqual(100, $color[1]);
234 |
235 | // Lightness
236 | $this->assertGreaterThanOrEqual(0, $color[2]);
237 | $this->assertLessThanOrEqual(100, $color[2]);
238 | }
239 | }
240 |
241 | public function testHslColor(): void
242 | {
243 | $regex = '/^(\d+),(\d+),(\d+)$/';
244 |
245 | for ($i = 0; $i < 100; $i++) {
246 | $color = $this->faker->unique()->hslColor();
247 | preg_match($regex, $color, $matches);
248 |
249 | // HUE
250 | $this->assertGreaterThanOrEqual(0, $matches[1]);
251 | $this->assertLessThanOrEqual(360, $matches[1]);
252 |
253 | // Saturation
254 | $this->assertGreaterThanOrEqual(0, $matches[2]);
255 | $this->assertLessThanOrEqual(100, $matches[2]);
256 |
257 | // Lightness
258 | $this->assertGreaterThanOrEqual(0, $matches[3]);
259 | $this->assertLessThanOrEqual(100, $matches[3]);
260 | }
261 | }
262 |
263 | public function testHslCssColor(): void
264 | {
265 | $regex = '/^hsl\((\d+),(\d+),(\d+)\)$/';
266 |
267 | for ($i = 0; $i < 100; $i++) {
268 | $color = $this->faker->unique()->hslCssColor();
269 |
270 | preg_match($regex, $color, $matches);
271 |
272 | // String
273 | $this->assertStringStartsWith('hsl(', $color);
274 | $this->assertStringEndsWith(')', $color);
275 |
276 | // HUE
277 | $this->assertGreaterThanOrEqual(0, $matches[1]);
278 | $this->assertLessThanOrEqual(360, $matches[1]);
279 |
280 | // Saturation
281 | $this->assertGreaterThanOrEqual(0, $matches[2]);
282 | $this->assertLessThanOrEqual(100, $matches[2]);
283 |
284 | // Lightness
285 | $this->assertGreaterThanOrEqual(0, $matches[3]);
286 | $this->assertLessThanOrEqual(100, $matches[3]);
287 | }
288 | }
289 |
290 | public function testHslaColorAsArray(): void
291 | {
292 | for ($i = 0; $i < 100; $i++) {
293 | $color = $this->faker->unique()->hslaColorAsArray();
294 |
295 | $this->assertIsArray($color);
296 | $this->assertCount(4, $color);
297 |
298 | // HUE
299 | $this->assertGreaterThanOrEqual(0, $color[0]);
300 | $this->assertLessThanOrEqual(360, $color[0]);
301 |
302 | // Saturation
303 | $this->assertGreaterThanOrEqual(0, $color[1]);
304 | $this->assertLessThanOrEqual(100, $color[1]);
305 |
306 | // Lightness
307 | $this->assertGreaterThanOrEqual(0, $color[2]);
308 | $this->assertLessThanOrEqual(100, $color[2]);
309 |
310 | // Alpha
311 | $this->assertGreaterThanOrEqual(0, $color[3]);
312 | $this->assertLessThanOrEqual(1, $color[3]);
313 | }
314 | }
315 |
316 | public function testHslaColor(): void
317 | {
318 | $regex = '/^(\d+),(\d+),(\d+),([01]|0\.\d+)$/';
319 |
320 | for ($i = 0; $i < 100; $i++) {
321 | $color = $this->faker->unique()->hslaColor();
322 | preg_match($regex, $color, $matches);
323 |
324 | // HUE
325 | $this->assertGreaterThanOrEqual(0, $matches[1]);
326 | $this->assertLessThanOrEqual(360, $matches[1]);
327 |
328 | // Saturation
329 | $this->assertGreaterThanOrEqual(0, $matches[2]);
330 | $this->assertLessThanOrEqual(100, $matches[2]);
331 |
332 | // Lightness
333 | $this->assertGreaterThanOrEqual(0, $matches[3]);
334 | $this->assertLessThanOrEqual(100, $matches[3]);
335 |
336 | // Alpha
337 | $this->assertGreaterThanOrEqual(0, $matches[4]);
338 | $this->assertLessThanOrEqual(1, $matches[4]);
339 | }
340 | }
341 |
342 | public function testHslaCssColor(): void
343 | {
344 | $regex = '/^hsla\((\d+),(\d+),(\d+),([01]|0\.\d+)\)$/';
345 |
346 | for ($i = 0; $i < 100; $i++) {
347 | $color = $this->faker->unique()->hslaCssColor();
348 | preg_match($regex, $color, $matches);
349 |
350 | // HUE
351 | $this->assertGreaterThanOrEqual(0, $matches[1]);
352 | $this->assertLessThanOrEqual(360, $matches[1]);
353 |
354 | // Saturation
355 | $this->assertGreaterThanOrEqual(0, $matches[2]);
356 | $this->assertLessThanOrEqual(100, $matches[2]);
357 |
358 | // Lightness
359 | $this->assertGreaterThanOrEqual(0, $matches[3]);
360 | $this->assertLessThanOrEqual(100, $matches[3]);
361 |
362 | // Alpha
363 | $this->assertGreaterThanOrEqual(0, $matches[4]);
364 | $this->assertLessThanOrEqual(1, $matches[4]);
365 | }
366 | }
367 | }
368 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/DatetimeExtensionTest.php:
--------------------------------------------------------------------------------
1 | faker->timestamp(0, 5000);
15 | }
16 |
17 | foreach ($results as $result) {
18 | $this->assertGreaterThanOrEqual(0, $result);
19 | $this->assertLessThanOrEqual(5000, $result);
20 | }
21 | }
22 |
23 | public function testTimestampWithWrongIntOrder(): void
24 | {
25 | $this->expectException(\ValueError::class);
26 | $this->faker->timestamp(5000, 0);
27 | }
28 |
29 | public function testTimestampUsingDatetime(): void
30 | {
31 | $results = [];
32 | $fromDateTime = new \DateTime('1998-06-29');
33 | $toDateTime = new \DateTime('1998-09-09');
34 |
35 | for ($i = 0; $i < 50; $i++) {
36 | $results[] = $this->faker->timestamp($fromDateTime, $toDateTime);
37 | }
38 |
39 | foreach ($results as $result) {
40 | $this->assertGreaterThanOrEqual($fromDateTime->getTimestamp(), $result);
41 | $this->assertLessThanOrEqual($toDateTime->getTimestamp(), $result);
42 | }
43 | }
44 |
45 | public function testTimestampUsingString(): void
46 | {
47 | $results = [];
48 |
49 | for ($i = 0; $i < 50; $i++) {
50 | $results[] = $this->faker->timestamp('-10 years', '+20 years');
51 | }
52 |
53 | $fromDateTime = new DateTime('-10 years');
54 | $toDateTime = new DateTime('+20 years');
55 |
56 | foreach ($results as $result) {
57 | $this->assertGreaterThanOrEqual($fromDateTime->getTimestamp(), $result);
58 | $this->assertLessThanOrEqual($toDateTime->getTimestamp(), $result);
59 | }
60 | }
61 |
62 | public function testDateTime(): void
63 | {
64 | $results = [];
65 |
66 | for ($i = 0; $i < 50; $i++) {
67 | $results[] = $this->faker->dateTime('-30 years', 'now');
68 | }
69 |
70 | $fromDateTime = new DateTime('-30 years');
71 | $toDateTime = new DateTime('now');
72 |
73 | foreach ($results as $result) {
74 | $this->assertGreaterThanOrEqual($fromDateTime->getTimestamp(), $result->getTimestamp());
75 | $this->assertLessThanOrEqual($toDateTime->getTimestamp(), $result->getTimestamp());
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/FinancialExtensionTest.php:
--------------------------------------------------------------------------------
1 | faker->iban();
12 |
13 | $this->assertEquals(28, strlen($iban));
14 | $this->assertMatchesRegularExpression('/^[A-Z]{2}/', $iban, 'IBAN does\'t contain a country code');
15 | $this->assertTrue(Iban::isValid($iban));
16 | }
17 |
18 | public function testIbanWithCustomCountryCode()
19 | {
20 | $iban = $this->faker->iban(countryCode: 'FR');
21 |
22 | $this->assertEquals(28, strlen($iban));
23 | $this->assertStringStartsWith('FR', $iban);
24 | }
25 |
26 | public function testIbanWithAnyFormat()
27 | {
28 | $iban = $this->faker->iban(format: str_repeat('{a}', 10));
29 |
30 | $this->assertEquals(14, strlen($iban));
31 | $this->assertMatchesRegularExpression('/^[A-Z0-9]+$/', substr($iban, 4));
32 | }
33 |
34 | public function testIbanWithLetterFormat()
35 | {
36 | $iban = $this->faker->iban(format: str_repeat('{l}', 10));
37 |
38 | $this->assertEquals(14, strlen($iban));
39 | $this->assertMatchesRegularExpression('/^[A-Z]+$/', substr($iban, 4));
40 | }
41 |
42 | public function testIbanWithDigitFormat()
43 | {
44 | $iban = $this->faker->iban(format: str_repeat('{d}', 10));
45 |
46 | $this->assertEquals(14, strlen($iban));
47 | $this->assertMatchesRegularExpression('/^[0-9]+$/', substr($iban, 4));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/HashExtensionTest.php:
--------------------------------------------------------------------------------
1 | faker->sha1();
10 |
11 | $this->assertMatchesRegularExpression('/^[a-z0-9]{40}$/', $result);
12 | }
13 |
14 | public function testSha256(): void
15 | {
16 | $result = $this->faker->sha256();
17 |
18 | $this->assertMatchesRegularExpression('/^[a-z0-9]{64}$/', $result);
19 | }
20 |
21 | public function testSha512(): void
22 | {
23 | $result = $this->faker->sha512();
24 |
25 | $this->assertMatchesRegularExpression('/^[a-z0-9]{128}$/', $result);
26 | }
27 |
28 | public function testMd5(): void
29 | {
30 | $result = $this->faker->md5();
31 |
32 | $this->assertMatchesRegularExpression('/^[a-fA-F0-9]{32}$/', $result);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/InternetExtensionTest.php:
--------------------------------------------------------------------------------
1 | tld = (new ReflectionClass($internetExtension))->getProperty('tld')->getValue($internetExtension);
18 | }
19 |
20 | public function testSdl(): void
21 | {
22 | $faker = new Container(false);
23 |
24 | $results = [];
25 |
26 | for ($i = 0; $i < 50; $i++) {
27 | $results[] = $faker->sdl();
28 | }
29 |
30 | foreach ($results as $result) {
31 | $this->assertTrue(ctype_alnum($result));
32 | }
33 | }
34 |
35 | public function testTld(): void
36 | {
37 | $faker = new Container(false);
38 |
39 | $results = [];
40 |
41 | for ($i = 0; $i < count($this->tld); $i++) {
42 | $results[] = $faker->unique()->tld();
43 | }
44 |
45 | $this->assertEqualsCanonicalizing($results, $this->tld);
46 | }
47 |
48 | public function testDomain(): void
49 | {
50 | $faker = new Container(false);
51 |
52 | $results = [];
53 |
54 | for ($i = 0; $i < 50; $i++) {
55 | $results[] = $faker->domain();
56 | }
57 |
58 | foreach ($results as $result) {
59 | $this->assertMatchesRegularExpression('/^([a-zA-Z0-9-]{1,63}\.)+[a-zA-Z]{2,}$/', $result);
60 | }
61 | }
62 |
63 | public function testIpv4(): void
64 | {
65 | $faker = new Container(false);
66 |
67 | $results = [];
68 |
69 | for ($i = 0; $i < 50; $i++) {
70 | $results[] = $faker->ipv4();
71 | }
72 |
73 | foreach ($results as $result) {
74 | $this->assertNotFalse(filter_var($result, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4));
75 | }
76 | }
77 |
78 | public function testIpv6(): void
79 | {
80 | $faker = new Container(false);
81 |
82 | $results = [];
83 |
84 | for ($i = 0; $i < 50; $i++) {
85 | $results[] = $faker->ipv6();
86 | }
87 |
88 | foreach ($results as $result) {
89 | $this->assertNotFalse(filter_var($result, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6));
90 | }
91 | }
92 |
93 | public function testMacAddress(): void
94 | {
95 | $faker = new Container(false);
96 |
97 | $results = [];
98 |
99 | for ($i = 0; $i < 50; $i++) {
100 | $results[] = $faker->macAddress();
101 | }
102 |
103 | foreach ($results as $result) {
104 | $this->assertNotFalse(filter_var($result, FILTER_VALIDATE_MAC));
105 | }
106 | }
107 |
108 | public function testEmail(): void
109 | {
110 | $faker = new Container(false);
111 |
112 | $results = [];
113 |
114 | for ($i = 0; $i < 100; $i++) {
115 | $results[] = $faker->unique()->email();
116 | }
117 |
118 | foreach ($results as $result) {
119 | // Email regex according to RFC 5322 Official Standard (reference : https://emailregex.com/)
120 | $this->assertMatchesRegularExpression('/^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/iD', $result);
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/NumbersExtensionTest.php:
--------------------------------------------------------------------------------
1 | faker->unique()->digit();
14 | }
15 |
16 | $this->assertEqualsCanonicalizing(
17 | range(0, 9),
18 | $results
19 | );
20 | }
21 |
22 | public function testNumberWithUniqueValues(): void
23 | {
24 | $results = [];
25 | for ($i = 0; $i < 100; $i++) {
26 | $results[] = $this->faker->unique()->number(1, 100);
27 | }
28 |
29 | $this->assertEqualsCanonicalizing(
30 | range(1, 100),
31 | $results
32 | );
33 | }
34 |
35 | public function testNumberWithRandomValues(): void
36 | {
37 | $results = [];
38 | for ($i = 0; $i < 100; $i++) {
39 | $results[] = $this->faker->number(1, 100);
40 | }
41 |
42 | foreach ($results as $result) {
43 | $this->assertLessThanOrEqual(100, $result);
44 | $this->assertGreaterThanOrEqual(1, $result);
45 | }
46 | }
47 |
48 | public static function floatProvider()
49 | {
50 | return [
51 | [1.0, 10.0, 2],
52 | [0.0, 1.0, 4],
53 | [-10.0, 10.0, 3],
54 | [5.5, 5.9, 1],
55 | [0.1, 0.2, 6],
56 | [-1000.0, 1000.0, 0],
57 | [3.333, 3.334, 5],
58 | [-50.0, -25.0, 2],
59 | [0.0, 0.1, 1],
60 | [999.9, 1000.0, 1],
61 | [-100.0, 100.0, 1],
62 | [50.0, 100.0, 0],
63 | [0.1234, 0.5678, 4],
64 | [10.5, 10.9, 2],
65 | [-0.1, 0.1, 5],
66 | [-200.0, -100.0, 1],
67 | [0.0001, 0.0002, 6],
68 | [-5.555, 5.555, 3],
69 | [0.0, 100000.0, 0],
70 | [123.456, 789.012, 3],
71 | [-0.0001, 0.0001, 6],
72 | [1.111, 1.119, 4],
73 | [2500.0, 5000.0, 0],
74 | [-0.999, 0.999, 2],
75 | [1234.567, 2345.678, 3],
76 | [-300.3, -100.1, 1],
77 | [0.000001, 0.000009, 7],
78 | [-50.25, -50.1, 2],
79 | [9.99, 10.0, 1],
80 | [10.20, 10.20, 2],
81 | ];
82 | }
83 |
84 | #[DataProvider('floatProvider')]
85 | public function testFloatWithRandomValues(float $min, float $max, int $decimals): void
86 | {
87 | $result = $this->faker->float($min, $max, $decimals);
88 |
89 | $this->assertLessThanOrEqual($this->numberFormatPrecision($max, $decimals), $result);
90 | $this->assertGreaterThanOrEqual($this->numberFormatPrecision($min, $decimals), $result);
91 |
92 | $formattedResult = number_format($result, $decimals, '.', '');
93 | $decimalParts = explode('.', $formattedResult);
94 | $decimalCount = isset($decimalParts[1]) ? strlen($decimalParts[1]) : 0;
95 | $this->assertEquals($decimals, $decimalCount);
96 | }
97 |
98 | /**
99 | * Used to cut numbers without round.
100 | *
101 | * @param float $number
102 | * @param int $precision
103 | * @param string $separator
104 | *
105 | * @return string
106 | */
107 | protected function numberFormatPrecision(float $number, int $precision = 2, string $separator = '.')
108 | {
109 | $numberParts = explode($separator, $number);
110 | $response = $numberParts[0];
111 | if (count($numberParts) > 1 && $precision > 0) {
112 | $response .= $separator;
113 | $response .= substr($numberParts[1], 0, $precision);
114 | }
115 |
116 | return $response;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/PersonExtensionTest.php:
--------------------------------------------------------------------------------
1 | firstNameMale = (new ReflectionClass($personExtension))->getProperty('firstNameMale')->getValue($personExtension);
22 | $this->firstNameFemale = (new ReflectionClass($personExtension))->getProperty('firstNameFemale')->getValue($personExtension);
23 | $this->lastName = (new ReflectionClass($personExtension))->getProperty('lastName')->getValue($personExtension);
24 | $this->titleMale = (new ReflectionClass($personExtension))->getProperty('titleMale')->getValue($personExtension);
25 | $this->titleFemale = (new ReflectionClass($personExtension))->getProperty('titleFemale')->getValue($personExtension);
26 | }
27 |
28 | public function testFirstNameFemale(): void
29 | {
30 | $results = [];
31 | for ($i = 0; $i < count($this->firstNameFemale); $i++) {
32 | $results[] = $this->faker->unique()->firstName(PersonExtension::GENDER_FEMALE);
33 | }
34 |
35 | $this->assertEqualsCanonicalizing(
36 | $this->firstNameFemale,
37 | $results
38 | );
39 | }
40 |
41 | public function testFirstNameMale(): void
42 | {
43 | $results = [];
44 | for ($i = 0; $i < count($this->firstNameMale); $i++) {
45 | $results[] = $this->faker->unique()->firstName(PersonExtension::GENDER_MALE);
46 | }
47 |
48 | $this->assertEqualsCanonicalizing(
49 | $this->firstNameMale,
50 | $results
51 | );
52 | }
53 |
54 | public function testFirstName(): void
55 | {
56 | $results = [];
57 | $firstnames = array_unique(array_merge($this->firstNameMale, $this->firstNameFemale));
58 | for ($i = 0; $i < count($firstnames); $i++) {
59 | $results[] = $this->faker->unique()->firstName();
60 | }
61 |
62 | $this->assertEqualsCanonicalizing(
63 | $firstnames,
64 | $results
65 | );
66 | }
67 |
68 | public function testLastName(): void
69 | {
70 | $results = [];
71 | for ($i = 0; $i < count($this->lastName); $i++) {
72 | $results[] = $this->faker->unique()->lastName();
73 | }
74 |
75 | $this->assertEqualsCanonicalizing(
76 | $this->lastName,
77 | $results
78 | );
79 | }
80 |
81 | public function testNameMale(): void
82 | {
83 | $results = [];
84 | for ($i = 0; $i < 100; $i++) {
85 | $results[] = $this->faker->name(PersonExtension::GENDER_MALE);
86 | }
87 |
88 | foreach ($results as $result) {
89 | $matchesFirstName = array_filter($this->firstNameMale, function ($firstName) use ($result) {
90 | return str_contains($result, $firstName);
91 | });
92 | $this->assertNotEmpty($matchesFirstName, "The first part of the result '{$result}' does not match any first name.");
93 |
94 | $matchesLastName = array_filter($this->lastName, function ($lastName) use ($result) {
95 | return str_contains($result, $lastName);
96 | });
97 | $this->assertNotEmpty($matchesLastName, "The second part of the result '{$result}' does not match any last name.");
98 | }
99 | }
100 |
101 | public function testNameFemale(): void
102 | {
103 | $results = [];
104 | for ($i = 0; $i < 100; $i++) {
105 | $results[] = $this->faker->name(PersonExtension::GENDER_FEMALE);
106 | }
107 |
108 | foreach ($results as $result) {
109 | $matchesFirstName = array_filter($this->firstNameFemale, function ($firstName) use ($result) {
110 | return str_contains($result, $firstName);
111 | });
112 | $this->assertNotEmpty($matchesFirstName, "The first part of the result '{$result}' does not match any first name.");
113 |
114 | $matchesLastName = array_filter($this->lastName, function ($lastName) use ($result) {
115 | return str_contains($result, $lastName);
116 | });
117 | $this->assertNotEmpty($matchesLastName, "The second part of the result '{$result}' does not match any last name.");
118 | }
119 | }
120 |
121 | public function testName(): void
122 | {
123 | $results = [];
124 | for ($i = 0; $i < 100; $i++) {
125 | $results[] = $this->faker->name();
126 | }
127 |
128 | foreach ($results as $result) {
129 | $matchesFirstName = array_filter(array_merge($this->firstNameFemale, $this->firstNameMale), function ($firstName) use ($result) {
130 | return str_contains($result, $firstName);
131 | });
132 | $this->assertNotEmpty($matchesFirstName, "The first part of the result '{$result}' does not match any first name.");
133 |
134 | $matchesLastName = array_filter($this->lastName, function ($lastName) use ($result) {
135 | return str_contains($result, $lastName);
136 | });
137 | $this->assertNotEmpty($matchesLastName, "The second part of the result '{$result}' does not match any last name.");
138 | }
139 | }
140 |
141 | public function testTitleFemale(): void
142 | {
143 | $results = [];
144 | for ($i = 0; $i < count($this->titleFemale); $i++) {
145 | $results[] = $this->faker->unique()->title(PersonExtension::GENDER_FEMALE);
146 | }
147 |
148 | $this->assertEqualsCanonicalizing(
149 | $this->titleFemale,
150 | $results
151 | );
152 | }
153 |
154 | public function testTitleMale(): void
155 | {
156 | $results = [];
157 | for ($i = 0; $i < count($this->titleMale); $i++) {
158 | $results[] = $this->faker->unique()->title(PersonExtension::GENDER_MALE);
159 | }
160 |
161 | $this->assertEqualsCanonicalizing(
162 | $this->titleMale,
163 | $results
164 | );
165 | }
166 |
167 | public function testTitle(): void
168 | {
169 | $titles = array_unique(array_merge($this->titleFemale, $this->titleMale));
170 |
171 | $results = [];
172 | for ($i = 0; $i < count($titles); $i++) {
173 | $results[] = $this->faker->unique()->title();
174 | }
175 |
176 | $this->assertEqualsCanonicalizing(
177 | $titles,
178 | $results
179 | );
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/StringsExtensionTest.php:
--------------------------------------------------------------------------------
1 | faker->unique()->letter();
12 | }
13 |
14 | $this->assertEqualsCanonicalizing(
15 | range('a', 'z'),
16 | $results
17 | );
18 | }
19 |
20 | public function testShuffleString(): void
21 | {
22 | $string = '!?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
23 | $result = $this->faker->shuffle($string);
24 |
25 | foreach (str_split($string) as $character) {
26 | $this->assertStringContainsString($character, $result);
27 | }
28 | }
29 |
30 | public function testShuffleArray(): void
31 | {
32 | $array = ['!', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
33 | $result = $this->faker->shuffle($array);
34 |
35 | foreach ($array as $character) {
36 | $this->assertContains($character, $result);
37 | }
38 | }
39 |
40 | public function testConvertCharacters(): void
41 | {
42 | $result = $this->faker->convertCharacters('NotConverted|#####|?????|*****');
43 |
44 | $result = explode('|', $result);
45 |
46 | $this->assertEquals('NotConverted', $result[0]);
47 |
48 | $this->assertTrue(ctype_digit($result[1]));
49 |
50 | $this->assertTrue(ctype_alpha($result[2]));
51 |
52 | $this->assertTrue(ctype_alnum($result[3]));
53 | }
54 |
55 | public function testSemVer(): void
56 | {
57 | // From: https://semver.org/spec/v2.0.0.html
58 | $regex = '/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/';
59 |
60 | $result = $this->faker->semver();
61 |
62 | $this->assertMatchesRegularExpression(
63 | $regex,
64 | $result
65 | );
66 | }
67 |
68 | public function testEmoji(): void
69 | {
70 | $result = $this->faker->emoji();
71 |
72 | $this->assertMatchesRegularExpression('/^\p{So}$/u', $result);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/TestCase.php:
--------------------------------------------------------------------------------
1 | boot();
17 |
18 | $this->faker = new Container(false);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/Unit/Extensions/TextExtensionTest.php:
--------------------------------------------------------------------------------
1 | paragraphs = (new ReflectionClass($testExtension))->getProperty('paragraphs')->getValue($testExtension);
18 | }
19 |
20 | public function testWordsWithDefaultValue(): void
21 | {
22 | $sentences = array_merge(...$this->paragraphs);
23 | $words = array_merge(...$sentences);
24 | $wordsWithoutPunctuationAndLowercased = array_map(function (string $word) { return strtolower(preg_replace('/[.,]/', '', $word)); }, $words);
25 | $result = $this->faker->words();
26 |
27 | $this->assertCount(3, explode(' ', $result));
28 | foreach (explode(' ', $result) as $word) {
29 | $this->assertContains($word, $wordsWithoutPunctuationAndLowercased);
30 | }
31 | }
32 |
33 | public static function wordsProvider()
34 | {
35 | return [
36 | [1],
37 | [2],
38 | [3],
39 | [4],
40 | [5],
41 | [6],
42 | [7],
43 | [8],
44 | [9],
45 | [10],
46 | ];
47 | }
48 |
49 | #[DataProvider('wordsProvider')]
50 | public function testWords(int $count): void
51 | {
52 | $sentences = array_merge(...$this->paragraphs);
53 | $words = array_merge(...$sentences);
54 | $wordsWithoutPunctuationAndLowercased = array_map(function (string $word) { return strtolower(preg_replace('/[.,]/', '', $word)); }, $words);
55 | $result = $this->faker->unique()->words(words: $count);
56 |
57 | $this->assertCount($count, explode(' ', $result));
58 | foreach (explode(' ', $result) as $word) {
59 | $this->assertContains($word, $wordsWithoutPunctuationAndLowercased);
60 | }
61 | }
62 |
63 | public function testSentencesWithDefaultValue(): void
64 | {
65 | $sentences = array_merge(...$this->paragraphs);
66 | $words = array_merge(...$sentences);
67 | $result = $this->faker->sentences();
68 |
69 | $this->assertCount(3, array_filter(explode('.', $result)));
70 | foreach (explode(' ', $result) as $word) {
71 | $this->assertContains($word, $words);
72 | }
73 | }
74 |
75 | public static function sentencesProvider()
76 | {
77 | return [
78 | [1],
79 | [2],
80 | [3],
81 | [4],
82 | [5],
83 | [6],
84 | [7],
85 | [8],
86 | [9],
87 | [10],
88 | ];
89 | }
90 |
91 | #[DataProvider('sentencesProvider')]
92 | public function testSentences(int $count): void
93 | {
94 | $sentences = array_merge(...$this->paragraphs);
95 | $words = array_merge(...$sentences);
96 | $result = $this->faker->unique()->sentences(sentences: $count);
97 |
98 | $this->assertCount($count, array_filter(explode('.', $result)));
99 | foreach (explode(' ', $result) as $word) {
100 | $this->assertContains($word, $words);
101 | }
102 | }
103 |
104 | public function testParagraphsWithDefaultValue(): void
105 | {
106 | $sentences = array_merge(...$this->paragraphs);
107 | $words = array_merge(...$sentences);
108 | $result = $this->faker->paragraphs();
109 |
110 | $this->assertCount(3, array_filter(explode(PHP_EOL, $result)));
111 | foreach (preg_split('/\s+/', $result) as $word) {
112 | $this->assertContains($word, $words);
113 | }
114 | }
115 |
116 | public static function paragraphsProvider()
117 | {
118 | return [
119 | [1],
120 | [2],
121 | [3],
122 | [4],
123 | [5],
124 | ];
125 | }
126 |
127 | #[DataProvider('paragraphsProvider')]
128 | public function testParagraphs(int $count): void
129 | {
130 | $sentences = array_merge(...$this->paragraphs);
131 | $words = array_merge(...$sentences);
132 | $result = $this->faker->unique()->paragraphs(paragraphs: $count);
133 |
134 | $this->assertCount($count, array_filter(explode(PHP_EOL, $result)));
135 | foreach (preg_split('/\s+/', $result) as $word) {
136 | $this->assertContains($word, $words);
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/tests/Unit/LocaleTest.php:
--------------------------------------------------------------------------------
1 | resolveExtensions([
10 | \Xefi\Faker\Tests\Support\Extensions\NullLocaleExtensionTest::class,
11 | \Xefi\Faker\Tests\Support\Extensions\EnEnExtensionTest::class,
12 | \Xefi\Faker\Tests\Support\Extensions\EnUsExtensionTest::class,
13 | \Xefi\Faker\Tests\Support\Extensions\FrFrExtensionTest::class,
14 | ]);
15 | }
16 |
17 | public function testExtensionsCorrectlyRegistered()
18 | {
19 | $this->assertEquals(
20 | [
21 | 'locales' => [
22 | null => new \Xefi\Faker\Tests\Support\Extensions\NullLocaleExtensionTest(new \Random\Randomizer()),
23 | 'en_EN' => new \Xefi\Faker\Tests\Support\Extensions\EnEnExtensionTest(new \Random\Randomizer()),
24 | 'en_US' => new \Xefi\Faker\Tests\Support\Extensions\EnUsExtensionTest(new \Random\Randomizer()),
25 | 'fr_FR' => new \Xefi\Faker\Tests\Support\Extensions\FrFrExtensionTest(new \Random\Randomizer()),
26 | ],
27 | ],
28 | (new \Xefi\Faker\Container\Container())->getExtensions()['locale-extension-test']
29 | );
30 | }
31 |
32 | public function testCallingDefaultExtension()
33 | {
34 | $this->assertEquals(
35 | null,
36 | (new \Xefi\Faker\Faker())->returnLocale()
37 | );
38 | }
39 |
40 | public function testUsingDefaultLocale()
41 | {
42 | $faker = new Xefi\Faker\Faker('fr_FR');
43 | $this->assertEquals(
44 | 'fr_FR',
45 | $faker->returnLocale()
46 | );
47 |
48 | $this->assertEquals(
49 | 'fr_FR',
50 | $faker->locale('fr_FR')->returnLocale()
51 | );
52 |
53 | $this->assertEquals(
54 | 'en_EN',
55 | $faker->locale('en_EN')->returnLocale()
56 | );
57 |
58 | $this->assertEquals(
59 | 'fr_FR',
60 | $faker->returnLocale()
61 | );
62 |
63 | $this->assertEquals(
64 | 'en_US',
65 | $faker->locale('en_US')->returnLocale()
66 | );
67 | }
68 |
69 | public function testResettingLocale()
70 | {
71 | $faker = new Xefi\Faker\Faker('fr_FR');
72 | $this->assertEquals(
73 | 'fr_FR',
74 | $faker->returnLocale()
75 | );
76 |
77 | $this->assertEquals(
78 | null,
79 | $faker->locale(null)->returnLocale()
80 | );
81 | }
82 |
83 | public function testUsingNotExistingLocaleFallingBackToNullLocale()
84 | {
85 | $faker = new Xefi\Faker\Faker('not-existing-locale');
86 | $this->assertEquals(
87 | null,
88 | $faker->returnLocale()
89 | );
90 | }
91 |
92 | public function testUsingNotExistingLocaleWithoutNullLocale()
93 | {
94 | $container = new \Xefi\Faker\Container\Container();
95 | $container->forgetExtensions();
96 | $container->forgetBootstrappers();
97 | $container->resolveExtensions([
98 | \Xefi\Faker\Tests\Support\Extensions\EnEnExtensionTest::class,
99 | \Xefi\Faker\Tests\Support\Extensions\EnUsExtensionTest::class,
100 | \Xefi\Faker\Tests\Support\Extensions\FrFrExtensionTest::class,
101 | ]);
102 |
103 | $this->expectException(\Xefi\Faker\Exceptions\NoExtensionLocaleFound::class);
104 | $this->expectExceptionMessage('Locale \'not-existing-locale\' and \'null\' for method \'returnLocale\' was not found');
105 |
106 | $faker = new Xefi\Faker\Faker('not-existing-locale');
107 | $faker->returnLocale();
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/tests/Unit/Modifiers/LowercaseModifierTest.php:
--------------------------------------------------------------------------------
1 | lowercase();
16 |
17 | $this->assertEquals(
18 | [new LowercaseModifier()],
19 | $container->getModifiers()
20 | );
21 | }
22 |
23 | public function testLowercaseModifier(): void
24 | {
25 | $faker = new Faker();
26 |
27 | $this->assertEquals(
28 | 'hello',
29 | $faker->lowercase()->returnHelloUppercase(),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Unit/Modifiers/OptionalModifierTest.php:
--------------------------------------------------------------------------------
1 | nullable();
17 |
18 | $this->assertEquals(
19 | [new NullableModifier(new Randomizer())],
20 | $container->getModifiers()
21 | );
22 | }
23 |
24 | public function testOptionalModifierWithDefaultValue(): void
25 | {
26 | $faker = new Faker();
27 |
28 | $this->assertContains(
29 | $faker->nullable()->returnHello(),
30 | ['hello', null]
31 | );
32 | }
33 |
34 | public function testOptionalModifierWithZeroValue(): void
35 | {
36 | $faker = new Faker();
37 |
38 | $this->assertEquals(
39 | 'hello',
40 | $faker->nullable(0)->returnHello()
41 | );
42 | }
43 |
44 | public function testOptionalModifierWithHundredValue(): void
45 | {
46 | $faker = new Faker();
47 |
48 | $this->assertEquals(
49 | null,
50 | $faker->nullable(100)->returnHello()
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/tests/Unit/Modifiers/UppercaseModifierTest.php:
--------------------------------------------------------------------------------
1 | uppercase();
16 |
17 | $this->assertEquals(
18 | [new UppercaseModifier()],
19 | $container->getModifiers()
20 | );
21 | }
22 |
23 | public function testUppercaseModifier(): void
24 | {
25 | $faker = new Faker();
26 |
27 | $this->assertEquals(
28 | 'HELLO',
29 | $faker->uppercase()->returnHello()
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Unit/PackageManifestTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(
15 | [
16 | 'autoload-needed' => [\Xefi\Faker\Tests\Support\TestServiceProvider::class],
17 | ],
18 | $manifest->providers()
19 | );
20 | $this->assertNotContains(['common-package' => []], $manifest->providers());
21 | unlink('/tmp/packages.php');
22 | }
23 |
24 | public function testShouldRecompile()
25 | {
26 | @unlink('/tmp/packages.php');
27 | $manifest = new PackageManifest(__DIR__.'/../Support', '/tmp/packages.php');
28 | $manifest->build();
29 | touch(__DIR__.'/../Support/vendor/composer/installed.json', time() - 1);
30 |
31 | $this->assertFalse($manifest->shouldRecompile());
32 |
33 | // Test on current time
34 | touch(__DIR__.'/../Support/vendor/composer/installed.json');
35 | $this->assertTrue($manifest->shouldRecompile());
36 |
37 | // Test on future
38 | touch(__DIR__.'/../Support/vendor/composer/installed.json', time() + 1);
39 | $this->assertTrue($manifest->shouldRecompile());
40 |
41 | unlink('/tmp/packages.php');
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Unit/ProviderRepositoryTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(
14 | $repo->createProvider(\Xefi\Faker\Tests\Support\TestServiceProvider::class),
15 | new \Xefi\Faker\Tests\Support\TestServiceProvider()
16 | );
17 | }
18 |
19 | public function testLoad()
20 | {
21 | $testServiceProvider = $this->createMock(\Xefi\Faker\Tests\Support\TestServiceProvider::class);
22 |
23 | $testServiceProvider->expects($this->once())
24 | ->method('boot');
25 |
26 | $repo = new \Xefi\Faker\Providers\ProviderRepository();
27 | $repo->load([
28 | $testServiceProvider,
29 | ]);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Unit/Strategies/RegexStrategyTest.php:
--------------------------------------------------------------------------------
1 | regex('//');
18 |
19 | $this->assertEquals(
20 | [new RegexStrategy('//')],
21 | $container->getStrategies()
22 | );
23 | }
24 |
25 | public function testUniqueSingleTest(): void
26 | {
27 | $faker = new Faker();
28 |
29 | $this->assertEquals(
30 | 'hello',
31 | $faker->regex('//')->returnHello()
32 | );
33 | }
34 |
35 | public function testUniqueThrowExceptionOnMaxRetriesReached(): void
36 | {
37 | $faker = new Faker();
38 |
39 | $this->expectException(MaximumTriesReached::class);
40 | $this->expectExceptionMessage('Maximum tries of 20000 reached without finding a value');
41 |
42 | $faker->regex('/^\d$/')->returnHello();
43 | }
44 |
45 | public static function regexProvider(): array
46 | {
47 | return [
48 | ['/\d/', 0, 9],
49 | ['/\d+/', 0, 100],
50 | ['/^[1-9]\d*$/', 1, 1000],
51 | ['/^-?\d+$/', -100, 100],
52 | ['/^[0-9]{1,3}$/', 0, 999],
53 | ['/^[1-9][0-9]{2,5}$/', 100, 999999],
54 | ['/^0$/', 0, 0],
55 | ];
56 | }
57 |
58 | #[DataProvider('regexProvider')]
59 | public function testMultipleRegexCases(string $regex, int $min, int $max): void
60 | {
61 | $faker = new Faker();
62 |
63 | $result = $faker->regex($regex)->returnNumberBetween($min, $max);
64 |
65 | $this->assertMatchesRegularExpression($regex, (string) $result);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/tests/Unit/Strategies/UniqueStrategyTest.php:
--------------------------------------------------------------------------------
1 | unique();
17 |
18 | $this->assertEquals(
19 | [new UniqueStrategy()],
20 | $container->getStrategies()
21 | );
22 | }
23 |
24 | public function testUniqueSingleTest(): void
25 | {
26 | $faker = new Faker();
27 |
28 | $this->assertEquals(
29 | 'hello',
30 | $faker->unique()->returnHello()
31 | );
32 | }
33 |
34 | public function testUniqueThrowExceptionOnMaxRetriesReached(): void
35 | {
36 | $faker = new Faker();
37 |
38 | $this->assertEquals(
39 | 'hello',
40 | $faker->unique()->returnHello()
41 | );
42 |
43 | $this->expectException(MaximumTriesReached::class);
44 | $this->expectExceptionMessage('Maximum tries of 20000 reached without finding a value');
45 |
46 | $faker->unique()->returnHello();
47 | }
48 |
49 | public function testUniqueGetAllElements(): void
50 | {
51 | $faker = new Faker();
52 |
53 | $numbers = [];
54 | for ($i = 0; $i < 10; $i++) {
55 | $numbers[] = $faker->unique()->returnNumberBetween(1, 10);
56 | }
57 |
58 | $this->assertEqualsCanonicalizing(range(1, 10), $numbers);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/tests/Unit/TestCase.php:
--------------------------------------------------------------------------------
1 |