1212use Doctrine \Common \DataFixtures \Purger \ORMPurger ;
1313use Doctrine \ORM \EntityManager ;
1414use Symfony \Bridge \Doctrine \Types \UuidType ;
15+ use Symfony \Component \Serializer \Annotation \Groups ;
1516use Symfony \Component \Uid \Uuid ;
1617
18+ /**
19+ * Base class for all tests of the project.
20+ * It provides some helper methods.
21+ */
1722abstract class EtuUTTApiTestCase extends ApiTestCase
1823{
1924 protected EntityManager $ em ;
2025 protected User $ user ;
2126 private array $ databaseBackup ;
2227
28+ /**
29+ * Initializes $this->em and $this->user.
30+ * $this->user is an admin user. Its login is 'test'. Tests may use it to connect to the API.
31+ * It also purges the database.
32+ */
2333 protected function setUp (): void
2434 {
2535 $ this ->em = static ::getContainer ()->get ('doctrine.orm.entity_manager ' );
@@ -28,6 +38,12 @@ protected function setUp(): void
2838 $ this ->user = $ this ->createUser ('test ' , 'test ' , 'test ' , 'ROLE_ADMIN ' );
2939 }
3040
41+ /**
42+ * Asserts that the received group is the same as the expected one. It should have the layout defined by the {@see Groups} 'group:read:some' in the {@see Group} entity.
43+ *
44+ * @param Group $expected The group that should be received
45+ * @param mixed $actual The group that was received (as an stdClass)
46+ */
3147 protected static function assertSameGroupReadSome (Group $ expected , mixed $ actual ): void
3248 {
3349 static ::assertIsObject ($ actual );
@@ -43,6 +59,12 @@ protected static function assertSameGroupReadSome(Group $expected, mixed $actual
4359 static ::assertSame ($ expected ->getNumberOfMembers (), $ actual ->numberOfMembers );
4460 }
4561
62+ /**
63+ * Asserts that the received group is the same as the expected one. It should have the layout defined by the {@see Groups} 'group:read:one' in the {@see Group} entity.
64+ *
65+ * @param Group $expected The group that should be received
66+ * @param mixed $actual The group that was received (as an stdClass)
67+ */
4668 protected static function assertSameGroupReadOne (Group $ expected , mixed $ actual ): void
4769 {
4870 static ::assertIsObject ($ actual );
@@ -66,6 +88,12 @@ protected static function assertSameGroupReadOne(Group $expected, mixed $actual)
6688 static ::assertSame ($ expected ->getUpdatedAt ()->format (\DateTimeInterface::RFC3339 ), $ actual ->updatedAt );
6789 }
6890
91+ /**
92+ * Asserts that the received translation is the same as the expected one.
93+ *
94+ * @param Translation $expected The translation that should be received
95+ * @param mixed $actual The translation that was received (as an stdClass)
96+ */
6997 protected static function assertSameTranslation (Translation $ expected , mixed $ actual ): void
7098 {
7199 static ::assertFalse (null === $ expected xor null === $ actual );
@@ -80,6 +108,12 @@ protected static function assertSameTranslation(Translation $expected, mixed $ac
80108 static ::assertSame ($ expected ->getChinese (), $ actual ->chinese );
81109 }
82110
111+ /**
112+ * Asserts that the received user is the same as the expected one. It should have the layout defined by the {@see Groups} 'user:read:some' in the {@see User} entity.
113+ *
114+ * @param User $expected The user that should be received
115+ * @param mixed $actual The user that was received (as an stdClass)
116+ */
83117 protected static function assertSameUserReadSome (User $ expected , mixed $ actual ): void
84118 {
85119 static ::assertIsObject ($ actual );
@@ -93,6 +127,12 @@ protected static function assertSameUserReadSome(User $expected, mixed $actual):
93127 static ::assertSameUserInfosReadSome ($ expected ->getInfos (), $ actual ->infos );
94128 }
95129
130+ /**
131+ * Asserts that the received user infos are the same as the expected one. It should have the layout defined by the {@see Groups} 'user:read:some' in the {@see UserInfos} entity.
132+ *
133+ * @param UserInfos $expected The user infos that should be received
134+ * @param mixed $actual The user infos that was received (as an stdClass)
135+ */
96136 protected static function assertSameUserInfosReadSome (UserInfos $ expected , mixed $ actual ): void
97137 {
98138 static ::assertIsObject ($ actual );
@@ -103,6 +143,11 @@ protected static function assertSameUserInfosReadSome(UserInfos $expected, mixed
103143 static ::assertSame ($ expected ->getNickname (), $ actual ->nickname );
104144 }
105145
146+ /**
147+ * Loads the given fixtures.
148+ *
149+ * @param Fixture ...$fixtures The fixtures to load
150+ */
106151 protected function loadFixtures (Fixture ...$ fixtures )
107152 {
108153 $ fixtureLoader = new Loader ();
@@ -114,6 +159,15 @@ protected function loadFixtures(Fixture ...$fixtures)
114159 }
115160 }
116161
162+ /**
163+ * Creates, persists, and returns a user. It can also flush the database if specified.
164+ *
165+ * @param string $firstName The first name of the user
166+ * @param string $lastName The last name of the user
167+ * @param string $login The login of the user
168+ * @param null|string $role The role of the user (defaults to 'ROLE_USER')
169+ * @param bool $flush Whether to flush the database or not (defaults to true)
170+ */
117171 protected function createUser (string $ firstName , string $ lastName , string $ login , ?string $ role = 'ROLE_USER ' , bool $ flush = true ): User
118172 {
119173 $ user = new User ();
@@ -129,12 +183,44 @@ protected function createUser(string $firstName, string $lastName, string $login
129183 return $ user ;
130184 }
131185
186+ /**
187+ * Backups the database. It sets the value of {@see $databaseBackup}. It should be used before the database is altered.
188+ * After changes, tests should use {@see assertDatabaseSameExcept} to assert that only specified fields have been modified.
189+ */
132190 protected function backupDatabase (): void
133191 {
134192 $ this ->databaseBackup = [];
135193 $ this ->_backupDatabase ($ this ->databaseBackup );
136194 }
137195
196+ /**
197+ * Asserts that the database is the same as the backup, except for the specified fields.
198+ *
199+ * @param array $diff The fields that should be different from the backup. It should be an array of the form:
200+ *
201+ * <code>
202+ * [
203+ * '<table_name>' => [
204+ * 'where' => [
205+ * '<field>' => '<value>', // Changes are only expected where <field> have value <value>
206+ * ],
207+ * 'diff' => [
208+ * '<modified_field>' => '<new_value>',
209+ * ],
210+ * ],
211+ * ]
212+ * </code>
213+ * @param array $new The new entries that should be in the database. It should be an array of the form:
214+ *
215+ * <code>
216+ * [
217+ * '<table_name>' => [
218+ * [
219+ * '<field>' => '<value>',
220+ * ], // Each array is a new entry
221+ * ],
222+ * </code>
223+ */
138224 protected function assertDatabaseSameExcept (array $ diff , array $ new ): void
139225 {
140226 $ actualDatabase = [];
@@ -153,18 +239,31 @@ protected function assertDatabaseSameExcept(array $diff, array $new): void
153239 $ this ->databaseBackup [$ table ][] = $ entry ;
154240 }
155241 }
156- static ::assertEquals ($ this ->databaseBackup , $ actualDatabase );
242+ // Yes, that's dumb, but PHPFixer keeps changing it to assertSame
243+ \call_user_func_array ([static ::class, 'assertEquals ' ], [$ this ->databaseBackup , $ actualDatabase ]);
157244 }
158245
246+ /**
247+ * Backups the database in the given array.
248+ *
249+ * @param array $backup A reference to the array in which the backup will be stored
250+ */
159251 private function _backupDatabase (array &$ backup ): void
160252 {
161253 $ backup = [];
254+ // Fetch all tables
162255 $ tables = $ this ->em ->getConnection ()->createSchemaManager ()->listTables ();
163256 foreach ($ tables as $ table ) {
164257 $ tableName = $ table ->getName ();
165258 $ backup [$ tableName ] = [];
259+ // Fetch all rows
166260 $ rows = $ this ->em ->getConnection ()->prepare ("SELECT * FROM {$ tableName }" )->executeQuery ()->fetchAllAssociative ();
167- $ getPrintableValue = fn (string $ column , $ value ): ?string => UuidType::class === $ table ->getColumn ($ column )->getType ()::class && null !== $ value ? Uuid::fromBinary ($ value )->jsonSerialize () : $ value ;
261+ // We don't want to directly use the binary value of the UUIDs, but the more human-readable representation
262+ $ getPrintableValue = function (string $ column , $ value ) use ($ table ): ?string {
263+ $ shouldConvert = UuidType::class === $ table ->getColumn ($ column )->getType ()::class && null !== $ value ;
264+
265+ return $ shouldConvert ? Uuid::fromBinary ($ value )->jsonSerialize () : $ value ;
266+ };
168267 foreach ($ rows as $ row ) {
169268 // Convert all values to printable values
170269 foreach ($ row as $ column => &$ value ) {
0 commit comments