Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
90.91% |
60 / 66 |
|
50.00% |
3 / 6 |
CRAP | |
0.00% |
0 / 1 |
ApieObjectFaker | |
90.91% |
60 / 66 |
|
50.00% |
3 / 6 |
29.63 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
createWithDefaultFakers | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
1 | |||
fakeClass | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
3.07 | |||
fakeArgumentsOfMethod | |
72.73% |
8 / 11 |
|
0.00% |
0 / 1 |
6.73 | |||
fakeMixed | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
fakeFromType | |
92.59% |
25 / 27 |
|
0.00% |
0 / 1 |
17.12 |
1 | <?php |
2 | namespace Apie\Faker; |
3 | |
4 | use Apie\Core\Exceptions\InvalidTypeException; |
5 | use Apie\Core\Identifiers\IdentifierInterface; |
6 | use Apie\Faker\Exceptions\ClassCanNotBeFakedException; |
7 | use Apie\Faker\Fakers\CheckBaseClassFaker; |
8 | use Apie\Faker\Fakers\DateValueObjectFaker; |
9 | use Apie\Faker\Fakers\EnumFaker; |
10 | use Apie\Faker\Fakers\ItemHashmapFaker; |
11 | use Apie\Faker\Fakers\ItemListFaker; |
12 | use Apie\Faker\Fakers\ItemSetFaker; |
13 | use Apie\Faker\Fakers\PasswordValueObjectFaker; |
14 | use Apie\Faker\Fakers\PhpDateTimeObjectFaker; |
15 | use Apie\Faker\Fakers\PolymorphicEntityFaker; |
16 | use Apie\Faker\Fakers\StringableFaker; |
17 | use Apie\Faker\Fakers\StringValueObjectWithRegexFaker; |
18 | use Apie\Faker\Fakers\UploadedFileFaker; |
19 | use Apie\Faker\Fakers\UseConstructorFaker; |
20 | use Apie\Faker\Fakers\UseFakeMethodFaker; |
21 | use Apie\Faker\Interfaces\ApieClassFaker; |
22 | use Apie\TypeConverter\ReflectionTypeFactory; |
23 | use Faker\Generator; |
24 | use Faker\Provider\Base; |
25 | use ReflectionClass; |
26 | use ReflectionIntersectionType; |
27 | use ReflectionMethod; |
28 | use ReflectionType; |
29 | use ReflectionUnionType; |
30 | |
31 | /** |
32 | * This is a stub class |
33 | */ |
34 | final class ApieObjectFaker extends Base |
35 | { |
36 | /** |
37 | * @var array<ApieClassFaker<object>> $fakers |
38 | */ |
39 | private array $fakers; |
40 | |
41 | /** |
42 | * @param ApieClassFaker<object> $fakers |
43 | */ |
44 | public function __construct(Generator $generator, ApieClassFaker... $fakers) |
45 | { |
46 | $this->fakers = $fakers; |
47 | parent::__construct($generator); |
48 | } |
49 | |
50 | /** |
51 | * @param ApieClassFaker<object> $additional |
52 | */ |
53 | public static function createWithDefaultFakers(Generator $generator, ApieClassFaker... $additional): self |
54 | { |
55 | return new self( |
56 | $generator, |
57 | ...[ |
58 | ...$additional, |
59 | new UseFakeMethodFaker(), |
60 | new CheckBaseClassFaker(new ReflectionClass(IdentifierInterface::class)), |
61 | new UploadedFileFaker(), |
62 | new PolymorphicEntityFaker(), |
63 | new ItemListFaker(), |
64 | new ItemHashmapFaker(), |
65 | new ItemSetFaker(), |
66 | new PasswordValueObjectFaker(), |
67 | new DateValueObjectFaker(), |
68 | new StringValueObjectWithRegexFaker(), |
69 | new EnumFaker(), |
70 | new PhpDateTimeObjectFaker(), |
71 | new StringableFaker(), |
72 | new UseConstructorFaker(), |
73 | ] |
74 | ); |
75 | } |
76 | |
77 | /** |
78 | * @template T of object |
79 | * @param class-string<T> $className |
80 | * @return T |
81 | */ |
82 | public function fakeClass(string $className): object |
83 | { |
84 | $refl = new ReflectionClass($className); |
85 | foreach ($this->fakers as $faker) { |
86 | if ($faker->supports($refl)) { |
87 | return $faker->fakeFor($this->generator, $refl); |
88 | } |
89 | } |
90 | |
91 | throw new ClassCanNotBeFakedException($refl); |
92 | } |
93 | |
94 | /** |
95 | * @return array<int, mixed> |
96 | */ |
97 | public function fakeArgumentsOfMethod(ReflectionMethod $method): array |
98 | { |
99 | $arguments = []; |
100 | foreach ($method->getParameters() as $parameter) { |
101 | $type = $parameter->getType(); |
102 | if ($parameter->isVariadic()) { |
103 | $rand = $this->generator->numberBetween(0, 4); |
104 | for ($i = 0; $i < $rand; $i++) { |
105 | $arguments[] = $this->generator->fakeFromType($type); |
106 | } |
107 | } elseif ($parameter->allowsNull() && 1 === $this->generator->numberBetween(0, 4)) { |
108 | $arguments[] = null; |
109 | } else { |
110 | $arguments[] = $this->generator->fakeFromType($type); |
111 | } |
112 | } |
113 | |
114 | return $arguments; |
115 | } |
116 | |
117 | public function fakeMixed(): mixed |
118 | { |
119 | return $this->fakeFromType(ReflectionTypeFactory::createReflectionType('array|null|bool|float|string|int')); |
120 | } |
121 | |
122 | public function fakeFromType(?ReflectionType $typehint): mixed |
123 | { |
124 | if ($typehint === null) { |
125 | return $this->fakeMixed(); |
126 | } |
127 | if ($typehint instanceof ReflectionIntersectionType) { |
128 | throw new InvalidTypeException($typehint, 'ReflectionUnionType|ReflectionNamedType'); |
129 | } |
130 | $types = $typehint instanceof ReflectionUnionType ? $typehint->getTypes() : [$typehint]; |
131 | $type = $this->generator->randomElement($types); |
132 | if ($type->getName() === Generator::class) { |
133 | return $this->generator; |
134 | } |
135 | if ($type->allowsNull()) { |
136 | if ($this->generator->boolean()) { |
137 | return null; |
138 | } |
139 | } |
140 | return match ($type->getName()) { |
141 | 'array' => [ |
142 | $this->generator->word() => $this->generator->fakeMixed(), |
143 | $this->generator->word() => $this->generator->fakeMixed(), |
144 | $this->generator->word() => $this->generator->fakeMixed(), |
145 | ], |
146 | 'null' => null, |
147 | 'false' => false, |
148 | 'true' => true, |
149 | 'bool' => $this->generator->randomElement([true, false]), |
150 | 'float' => $this->generator->randomFloat(), |
151 | 'string' => $this->generator->word(), |
152 | 'int' => $this->generator->numberBetween(-2147483648, 2147483647), // compatible with integers in Mysql |
153 | 'mixed' => $this->fakeMixed(), |
154 | default => $this->fakeClass($type->getName()), |
155 | }; |
156 | } |
157 | } |