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