diff --git a/README.md b/README.md
index 17ff0ea..ea4da08 100644
--- a/README.md
+++ b/README.md
@@ -152,6 +152,8 @@ Once the local server is running, go to [http://127.0.0.1:8000/](http://127.0.0.
| ├── Security/ # Login process and Voters
| └── Util/ # Static classes to centralize simple tasks
├── tests/ # Automated tests (e.g. Unit tests)
+| └── Groups/ # Tests for /groups routes
+| └── Users/ # Tests for /users routes
├── var/ # Generated files (cache, logs, etc)
├── vendor/ # The third-party dependencies
├── .czrc # Git Commitizen configuration file
diff --git a/tests/EtuUTTApiTestCase.php b/tests/EtuUTTApiTestCase.php
index 640ea7e..d6481c8 100644
--- a/tests/EtuUTTApiTestCase.php
+++ b/tests/EtuUTTApiTestCase.php
@@ -12,14 +12,24 @@
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\EntityManager;
use Symfony\Bridge\Doctrine\Types\UuidType;
+use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Uid\Uuid;
+/**
+ * Base class for all tests of the project.
+ * It provides some helper methods.
+ */
abstract class EtuUTTApiTestCase extends ApiTestCase
{
protected EntityManager $em;
protected User $user;
private array $databaseBackup;
+ /**
+ * Initializes $this->em and $this->user.
+ * $this->user is an admin user. Its login is 'test'. Tests may use it to connect to the API.
+ * It also purges the database.
+ */
protected function setUp(): void
{
$this->em = static::getContainer()->get('doctrine.orm.entity_manager');
@@ -28,6 +38,12 @@ protected function setUp(): void
$this->user = $this->createUser('test', 'test', 'test', 'ROLE_ADMIN');
}
+ /**
+ * 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.
+ *
+ * @param Group $expected The group that should be received
+ * @param mixed $actual The group that was received (as an stdClass)
+ */
protected static function assertSameGroupReadSome(Group $expected, mixed $actual): void
{
static::assertIsObject($actual);
@@ -43,6 +59,12 @@ protected static function assertSameGroupReadSome(Group $expected, mixed $actual
static::assertSame($expected->getNumberOfMembers(), $actual->numberOfMembers);
}
+ /**
+ * 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.
+ *
+ * @param Group $expected The group that should be received
+ * @param mixed $actual The group that was received (as an stdClass)
+ */
protected static function assertSameGroupReadOne(Group $expected, mixed $actual): void
{
static::assertIsObject($actual);
@@ -66,6 +88,12 @@ protected static function assertSameGroupReadOne(Group $expected, mixed $actual)
static::assertSame($expected->getUpdatedAt()->format(\DateTimeInterface::RFC3339), $actual->updatedAt);
}
+ /**
+ * Asserts that the received translation is the same as the expected one.
+ *
+ * @param Translation $expected The translation that should be received
+ * @param mixed $actual The translation that was received (as an stdClass)
+ */
protected static function assertSameTranslation(Translation $expected, mixed $actual): void
{
static::assertFalse(null === $expected xor null === $actual);
@@ -80,6 +108,12 @@ protected static function assertSameTranslation(Translation $expected, mixed $ac
static::assertSame($expected->getChinese(), $actual->chinese);
}
+ /**
+ * 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.
+ *
+ * @param User $expected The user that should be received
+ * @param mixed $actual The user that was received (as an stdClass)
+ */
protected static function assertSameUserReadSome(User $expected, mixed $actual): void
{
static::assertIsObject($actual);
@@ -93,6 +127,12 @@ protected static function assertSameUserReadSome(User $expected, mixed $actual):
static::assertSameUserInfosReadSome($expected->getInfos(), $actual->infos);
}
+ /**
+ * 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.
+ *
+ * @param UserInfos $expected The user infos that should be received
+ * @param mixed $actual The user infos that was received (as an stdClass)
+ */
protected static function assertSameUserInfosReadSome(UserInfos $expected, mixed $actual): void
{
static::assertIsObject($actual);
@@ -103,6 +143,11 @@ protected static function assertSameUserInfosReadSome(UserInfos $expected, mixed
static::assertSame($expected->getNickname(), $actual->nickname);
}
+ /**
+ * Loads the given fixtures.
+ *
+ * @param Fixture ...$fixtures The fixtures to load
+ */
protected function loadFixtures(Fixture ...$fixtures)
{
$fixtureLoader = new Loader();
@@ -114,6 +159,15 @@ protected function loadFixtures(Fixture ...$fixtures)
}
}
+ /**
+ * Creates, persists, and returns a user. It can also flush the database if specified.
+ *
+ * @param string $firstName The first name of the user
+ * @param string $lastName The last name of the user
+ * @param string $login The login of the user
+ * @param null|string $role The role of the user (defaults to 'ROLE_USER')
+ * @param bool $flush Whether to flush the database or not (defaults to true)
+ */
protected function createUser(string $firstName, string $lastName, string $login, ?string $role = 'ROLE_USER', bool $flush = true): User
{
$user = new User();
@@ -129,12 +183,44 @@ protected function createUser(string $firstName, string $lastName, string $login
return $user;
}
+ /**
+ * Backups the database. It sets the value of {@see $databaseBackup}. It should be used before the database is altered.
+ * After changes, tests should use {@see assertDatabaseSameExcept} to assert that only specified fields have been modified.
+ */
protected function backupDatabase(): void
{
$this->databaseBackup = [];
$this->_backupDatabase($this->databaseBackup);
}
+ /**
+ * Asserts that the database is the same as the backup, except for the specified fields.
+ *
+ * @param array $diff The fields that should be different from the backup. It should be an array of the form:
+ *
+ *
+ * [
+ * '' => [
+ * 'where' => [
+ * '' => '', // Changes are only expected where have value
+ * ],
+ * 'diff' => [
+ * '' => '',
+ * ],
+ * ],
+ * ]
+ *
+ * @param array $new The new entries that should be in the database. It should be an array of the form:
+ *
+ *
+ * [
+ * '' => [
+ * [
+ * '' => '',
+ * ], // Each array is a new entry
+ * ],
+ *
+ */
protected function assertDatabaseSameExcept(array $diff, array $new): void
{
$actualDatabase = [];
@@ -153,18 +239,31 @@ protected function assertDatabaseSameExcept(array $diff, array $new): void
$this->databaseBackup[$table][] = $entry;
}
}
- static::assertEquals($this->databaseBackup, $actualDatabase);
+ // Yes, that's dumb, but PHPFixer keeps changing it to assertSame
+ \call_user_func_array([static::class, 'assertEquals'], [$this->databaseBackup, $actualDatabase]);
}
+ /**
+ * Backups the database in the given array.
+ *
+ * @param array $backup A reference to the array in which the backup will be stored
+ */
private function _backupDatabase(array &$backup): void
{
$backup = [];
+ // Fetch all tables
$tables = $this->em->getConnection()->createSchemaManager()->listTables();
foreach ($tables as $table) {
$tableName = $table->getName();
$backup[$tableName] = [];
+ // Fetch all rows
$rows = $this->em->getConnection()->prepare("SELECT * FROM {$tableName}")->executeQuery()->fetchAllAssociative();
- $getPrintableValue = fn (string $column, $value): ?string => UuidType::class === $table->getColumn($column)->getType()::class && null !== $value ? Uuid::fromBinary($value)->jsonSerialize() : $value;
+ // We don't want to directly use the binary value of the UUIDs, but the more human-readable representation
+ $getPrintableValue = function (string $column, $value) use ($table): ?string {
+ $shouldConvert = UuidType::class === $table->getColumn($column)->getType()::class && null !== $value;
+
+ return $shouldConvert ? Uuid::fromBinary($value)->jsonSerialize() : $value;
+ };
foreach ($rows as $row) {
// Convert all values to printable values
foreach ($row as $column => &$value) {
diff --git a/tests/Groups/GetGroupFromSlug.php b/tests/Groups/GetGroupFromSlug.php
index 9375d32..c49b93d 100644
--- a/tests/Groups/GetGroupFromSlug.php
+++ b/tests/Groups/GetGroupFromSlug.php
@@ -11,6 +11,8 @@
* @internal
*
* @coversNothing
+ *
+ * Tests for route GET /groups/{slug}
*/
final class GetGroupFromSlug extends EtuUTTApiTestCase
{
diff --git a/tests/Groups/GetGroups.php b/tests/Groups/GetGroups.php
index d0f6d89..b093245 100644
--- a/tests/Groups/GetGroups.php
+++ b/tests/Groups/GetGroups.php
@@ -11,6 +11,8 @@
* @internal
*
* @coversNothing
+ *
+ * Tests for route GET /groups
*/
final class GetGroups extends EtuUTTApiTestCase
{
diff --git a/tests/Groups/UpdateGroup.php b/tests/Groups/UpdateGroup.php
index 01d7508..c2e56d7 100644
--- a/tests/Groups/UpdateGroup.php
+++ b/tests/Groups/UpdateGroup.php
@@ -11,6 +11,8 @@
* @internal
*
* @coversNothing
+ *
+ * Tests for route PATCH /groups/{slug}
*/
final class UpdateGroup extends EtuUTTApiTestCase
{
diff --git a/tests/Users/DeleteUser.php b/tests/Users/DeleteUser.php
index 89b0555..93be07e 100644
--- a/tests/Users/DeleteUser.php
+++ b/tests/Users/DeleteUser.php
@@ -11,6 +11,8 @@
* @internal
*
* @coversNothing
+ *
+ * Tests for route DELETE /users/{id}
*/
final class DeleteUser extends EtuUTTApiTestCase
{
diff --git a/tests/Users/GetUserFromId.php b/tests/Users/GetUserFromId.php
index dc032c4..aae5bc3 100644
--- a/tests/Users/GetUserFromId.php
+++ b/tests/Users/GetUserFromId.php
@@ -12,6 +12,8 @@
* @internal
*
* @coversNothing
+ *
+ * Tests for route GET /users/{id}
*/
final class GetUserFromId extends EtuUTTApiTestCase
{
diff --git a/tests/Users/GetUsers.php b/tests/Users/GetUsers.php
index c76f1ba..27aeef3 100644
--- a/tests/Users/GetUsers.php
+++ b/tests/Users/GetUsers.php
@@ -16,6 +16,8 @@
* @internal
*
* @coversNothing
+ *
+ * Tests for route GET /users
*/
final class GetUsers extends EtuUTTApiTestCase
{
diff --git a/tests/Users/UpdateUser.php b/tests/Users/UpdateUser.php
index f25d632..c185052 100644
--- a/tests/Users/UpdateUser.php
+++ b/tests/Users/UpdateUser.php
@@ -10,6 +10,8 @@
* @internal
*
* @coversNothing
+ *
+ * Tests for route PATCH /users/{id}
*/
final class UpdateUser extends EtuUTTApiTestCase
{