SchemaTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <?php
  2. namespace Test\PhpDevCommunity\RequestKit;
  3. use DateTime;
  4. use PhpDevCommunity\RequestKit\Exceptions\InvalidDataException;
  5. use PhpDevCommunity\RequestKit\Schema\Schema;
  6. use PhpDevCommunity\RequestKit\Type;
  7. use PhpDevCommunity\UniTester\TestCase;
  8. class SchemaTest extends TestCase
  9. {
  10. private ?Schema $schema = null;
  11. protected function setUp(): void
  12. {
  13. $this->schema = Schema::create([
  14. 'name' => Type::string()->length(3, 100)->required(),
  15. 'age' => Type::int()->min(18)->max(99),
  16. 'email' => Type::email()->lowercase(),
  17. 'date_of_birth' => Type::date()->format('Y-m-d'),
  18. 'created_at' => Type::datetime()->format('Y-m-d H:i:s')->default(date('2025-01-01 12:00:00')),
  19. 'active' => Type::bool()->strict(),
  20. ]);
  21. }
  22. protected function tearDown(): void
  23. {
  24. // TODO: Implement tearDown() method.
  25. }
  26. protected function execute(): void
  27. {
  28. $this->testValidData();
  29. $this->testInvalidEmail();
  30. $this->testEdgeCaseAge();
  31. $this->testStrictBool();
  32. $this->testMissingOptionalField();
  33. $this->testMissingRequiredField();
  34. $this->testMultipleValidationErrors();
  35. $this->testNestedData();
  36. $this->testCollection();
  37. $this->testExtend();
  38. $this->testExampleData();
  39. }
  40. public function testValidData(): void
  41. {
  42. $data = [
  43. 'name' => 'John Doe',
  44. 'age' => 25,
  45. 'email' => 'JOHN@EXAMPLE.COM',
  46. 'date_of_birth' => '1990-01-01',
  47. 'created_at' => '2023-01-01 12:00:00',
  48. 'active' => true,
  49. ];
  50. $result = $this->schema->process($data);
  51. $result = $result->toArray();
  52. $this->assertStrictEquals($result['name'], 'John Doe');
  53. $this->assertStrictEquals($result['age'], 25);
  54. $this->assertStrictEquals($result['email'], 'john@example.com');
  55. $this->assertStrictEquals($result['date_of_birth']->format('Y-m-d'), '1990-01-01');
  56. $this->assertStrictEquals($result['created_at']->format('Y-m-d H:i:s'), '2023-01-01 12:00:00');
  57. $this->assertStrictEquals($result['active'], true);
  58. }
  59. public function testInvalidEmail(): void
  60. {
  61. $data = [
  62. 'name' => 'John Doe',
  63. 'age' => 25,
  64. 'email' => 'invalid-email', // Email invalide
  65. 'date_of_birth' => '1990-01-01',
  66. 'created_at' => '2023-01-01 12:00:00',
  67. 'active' => true,
  68. ];
  69. $this->expectException(InvalidDataException::class, function () use ($data) {
  70. try {
  71. $result = $this->schema->process($data);
  72. } catch (InvalidDataException $e) {
  73. $this->assertNotEmpty($e->getErrors());
  74. $this->assertEquals(1, count($e->getErrors()));
  75. $this->assertNotEmpty($e->getError('email'));
  76. throw $e;
  77. }
  78. });
  79. }
  80. public function testEdgeCaseAge(): void
  81. {
  82. $data = [
  83. 'name' => 'John Doe',
  84. 'age' => '18', // Âge limite
  85. 'email' => 'john@example.com',
  86. 'date_of_birth' => '1990-01-01',
  87. 'created_at' => '2023-01-01 12:00:00',
  88. 'active' => true,
  89. ];
  90. $result = $this->schema->process($data);
  91. $result = $result->toArray();
  92. $this->assertEquals(18, $result['age']);
  93. }
  94. public function testStrictBool(): void
  95. {
  96. $data = [
  97. 'name' => 'John Doe',
  98. 'age' => 25,
  99. 'email' => 'john@example.com',
  100. 'date_of_birth' => '1990-01-01',
  101. 'created_at' => '2023-01-01 12:00:00',
  102. 'active' => 1, //
  103. ];
  104. $this->expectException(InvalidDataException::class, function () use ($data) {
  105. try {
  106. $result = $this->schema->process($data);
  107. } catch (InvalidDataException $e) {
  108. $this->assertNotEmpty($e->getErrors());
  109. $this->assertEquals(1, count($e->getErrors()));
  110. $this->assertNotEmpty($e->getError('active'));
  111. throw $e;
  112. }
  113. });
  114. }
  115. public function testMissingOptionalField(): void
  116. {
  117. $data = [
  118. 'name' => 'John Doe',
  119. 'age' => 25,
  120. 'email' => 'john@example.com',
  121. 'date_of_birth' => '1990-01-01',
  122. // 'created_at'
  123. 'active' => true,
  124. ];
  125. $result = $this->schema->process($data);
  126. $result = $result->toArray();
  127. $this->assertInstanceOf(DateTime::class, $result['created_at']);
  128. }
  129. public function testMissingRequiredField(): void
  130. {
  131. $data = [
  132. // 'name' manquant
  133. 'age' => 25,
  134. 'email' => 'john@example.com',
  135. 'date_of_birth' => '1990-01-01',
  136. 'created_at' => '2023-01-01 12:00:00',
  137. 'active' => true,
  138. ];
  139. $this->expectException(InvalidDataException::class, function () use ($data) {
  140. try {
  141. $result = $this->schema->process($data);
  142. } catch (InvalidDataException $e) {
  143. $this->assertNotEmpty($e->getErrors());
  144. $this->assertEquals(1, count($e->getErrors()));
  145. $this->assertNotEmpty($e->getError('name'));
  146. throw $e;
  147. }
  148. });
  149. }
  150. public function testMultipleValidationErrors(): void
  151. {
  152. $data = [
  153. 'name' => 'John Doe',
  154. 'age' => 17, // Âge invalide
  155. 'email' => 'invalid-email', // Email invalide
  156. 'date_of_birth' => '1990-01-01',
  157. 'created_at' => '2023-01-01 12:00:00',
  158. 'active' => true,
  159. ];
  160. $this->expectException(InvalidDataException::class, function () use ($data) {
  161. try {
  162. $result = $this->schema->process($data);
  163. } catch (InvalidDataException $e) {
  164. $this->assertNotEmpty($e->getErrors());
  165. $this->assertEquals(2, count($e->getErrors()));
  166. $this->assertNotEmpty($e->getError('age'));
  167. $this->assertNotEmpty($e->getError('email'));
  168. throw $e;
  169. }
  170. });
  171. }
  172. public function testNestedData(): void
  173. {
  174. $schema = Schema::create([
  175. 'user' => Type::item([
  176. 'name' => Type::string()->length(20, 50)->required(),
  177. 'age' => Type::int()->strict()->alias('my_age'),
  178. 'roles' => Type::arrayOf(Type::string()->strict())->required(),
  179. 'address' => Type::item([
  180. 'street' => Type::string()->length(15, 100),
  181. 'city' => Type::string()->allowed('Paris', 'London'),
  182. ]),
  183. ]),
  184. ]);
  185. $data = [
  186. 'user' => [
  187. // 'name' => 'John Doe',
  188. 'my_age' => '25',
  189. // 'roles' => [
  190. // 1,
  191. // 2,
  192. // ],
  193. 'address' => [
  194. 'street' => 'Main Street',
  195. 'city' => 'New York',
  196. ]
  197. ],
  198. ];
  199. $this->expectException(InvalidDataException::class, function () use ($schema, $data) {
  200. try {
  201. $schema->process($data);
  202. } catch (InvalidDataException $e) {
  203. $this->assertNotEmpty($e->getErrors());
  204. $this->assertEquals(5, count($e->getErrors()));
  205. $this->assertNotEmpty($e->getError('user.name'));
  206. $this->assertNotEmpty($e->getError('user.age'));
  207. $this->assertNotEmpty($e->getError('user.address.street'));
  208. $this->assertNotEmpty($e->getError('user.address.city'));
  209. $this->assertNotEmpty($e->getError('user.roles'));
  210. throw $e;
  211. }
  212. });
  213. }
  214. public function testCollection(): void
  215. {
  216. $schema = Schema::create([
  217. 'users' => Type::arrayOf(Type::item([
  218. 'name' => Type::string()->length(3, 50)->required(),
  219. 'age' => Type::int(),
  220. 'roles' => Type::arrayOf(Type::string())->required(),
  221. 'address' => Type::item([
  222. 'street' => Type::string()->length(5, 100),
  223. 'city' => Type::string()->allowed('Paris', 'London'),
  224. ]),
  225. ])),
  226. ]);
  227. $data = [
  228. 'users' => [
  229. [
  230. 'name' => 'John Doe',
  231. 'age' => '25',
  232. 'roles' => [
  233. 1,
  234. 2,
  235. ],
  236. 'address' => [
  237. 'street' => 'Main Street',
  238. 'city' => 'London',
  239. ]
  240. ],
  241. [
  242. 'name' => 'Jane Doe',
  243. 'age' => '30',
  244. 'roles' => [
  245. 3,
  246. 4,
  247. ],
  248. 'address' => [
  249. 'street' => 'Main Street',
  250. 'city' => 'Paris',
  251. ]
  252. ],
  253. ]
  254. ];
  255. $result = $schema->process($data);
  256. $this->assertStrictEquals(2, count($result->get('users')));
  257. $this->assertStrictEquals('John Doe', $result->get('users.0.name'));
  258. $this->assertStrictEquals(25, $result->get('users.0.age'));
  259. $this->assertStrictEquals(2, count($result->get('users.0.roles')));
  260. $this->assertStrictEquals('Main Street', $result->get('users.0.address.street'));
  261. $this->assertStrictEquals('London', $result->get('users.0.address.city'));
  262. $this->assertStrictEquals('Jane Doe', $result->get('users.1.name'));
  263. $this->assertStrictEquals(30, $result->get('users.1.age'));
  264. $this->assertStrictEquals(2, count($result->get('users.1.roles')));
  265. $this->assertStrictEquals('Main Street', $result->get('users.1.address.street'));
  266. $this->assertStrictEquals('Paris', $result->get('users.1.address.city'));
  267. }
  268. private function testExtend()
  269. {
  270. $schema1 = Schema::create([
  271. 'name' => Type::string()->length(20, 50)->required(),
  272. 'age' => Type::int()->strict()->alias('my_age'),
  273. 'roles' => Type::arrayOf(Type::string()->strict())->required(),
  274. 'address' => Type::item([
  275. 'street' => Type::string()->length(15, 100),
  276. 'city' => Type::string()->allowed('Paris', 'London'),
  277. ]),
  278. ]);
  279. $schema2 = $schema1->extend([
  280. 'password' => Type::string()->length(10, 100),
  281. 'address' => Type::item([
  282. 'zip' => Type::string()->length(5, 10),
  283. ]),
  284. ]);
  285. $this->assertStrictEquals(5, count($schema2->copyDefinitions()));
  286. /**
  287. * @var Type\ItemType $address
  288. */
  289. $address = $schema2->copyDefinitions()['address'];
  290. $this->assertStrictEquals(1, count($address->copyDefinitions()));
  291. }
  292. private function testExampleData()
  293. {
  294. $schema1 = Schema::create([
  295. 'name' => Type::string()->length(20, 50)->required()->example('John Doe'),
  296. 'age' => Type::int()->strict()->alias('my_age')->example(20),
  297. 'roles' => Type::arrayOf(Type::string()->strict())->required()->example('admin'),
  298. 'address' => Type::item([
  299. 'street' => Type::string()->length(15, 100),
  300. 'city' => Type::string()->allowed('Paris', 'London'),
  301. ])->example([
  302. 'street' => 'Main Street',
  303. 'city' => 'London',
  304. ]
  305. ),
  306. ]);
  307. $this->assertEquals($schema1->generateExampleData(), [
  308. 'name' => 'John Doe',
  309. 'age' => 20,
  310. 'roles' => ['admin'],
  311. 'address' => [
  312. 'street' => 'Main Street',
  313. 'city' => 'London',
  314. ]
  315. ]);
  316. $schema2 = Schema::create([
  317. 'name' => Type::string()->length(20, 50)->required()->example('John Doe'),
  318. 'age' => Type::int()->strict()->alias('my_age')->example(20),
  319. 'roles' => Type::arrayOf(Type::string()->strict())->required()->example('admin'),
  320. 'address' => Type::item([
  321. 'street' => Type::string()->length(15, 100)->example('Main Street'),
  322. 'city' => Type::string()->allowed('Paris', 'London')->example('London'),
  323. ]),
  324. ]);
  325. $this->assertEquals($schema2->generateExampleData(), [
  326. 'name' => 'John Doe',
  327. 'age' => 20,
  328. 'roles' => ['admin'],
  329. 'address' => [
  330. 'street' => 'Main Street',
  331. 'city' => 'London',
  332. ]
  333. ]);
  334. }
  335. }