diff --git a/config/api_platform/resources.xml b/config/api_platform/resources.xml
index 5f6a9db..2885aa3 100644
--- a/config/api_platform/resources.xml
+++ b/config/api_platform/resources.xml
@@ -77,6 +77,7 @@
+
@@ -108,7 +109,6 @@
public
-
@@ -118,4 +118,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/migrations/Version20240129212818.php b/migrations/Version20240129212818.php
deleted file mode 100644
index da5f16d..0000000
--- a/migrations/Version20240129212818.php
+++ /dev/null
@@ -1,31 +0,0 @@
-addSql('CREATE SCHEMA public');
- }
-}
diff --git a/migrations/Version20240219220159.php b/migrations/Version20240219220159.php
new file mode 100644
index 0000000..f3fa10f
--- /dev/null
+++ b/migrations/Version20240219220159.php
@@ -0,0 +1,112 @@
+addSql('CREATE TABLE "character" (id UUID NOT NULL, dojo_id UUID DEFAULT NULL, name VARCHAR(255) NOT NULL, strength INT NOT NULL, constitution INT NOT NULL, agility INT NOT NULL, chi INT NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE INDEX IDX_937AB03432F09E9C ON "character" (dojo_id)');
+ $this->addSql('COMMENT ON COLUMN "character".id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN "character".dojo_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('CREATE TABLE character_technique (character_id UUID NOT NULL, technique_id UUID NOT NULL, PRIMARY KEY(character_id, technique_id))');
+ $this->addSql('CREATE INDEX IDX_506B3A7A1136BE75 ON character_technique (character_id)');
+ $this->addSql('CREATE INDEX IDX_506B3A7A1F8ACB26 ON character_technique (technique_id)');
+ $this->addSql('COMMENT ON COLUMN character_technique.character_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN character_technique.technique_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('CREATE TABLE city (id UUID NOT NULL, dungeon_id UUID NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE UNIQUE INDEX UNIQ_2D5B0234B606863 ON city (dungeon_id)');
+ $this->addSql('COMMENT ON COLUMN city.id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN city.dungeon_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('CREATE TABLE country (id UUID NOT NULL, capital_id UUID NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE UNIQUE INDEX UNIQ_5373C966FC2D9FF7 ON country (capital_id)');
+ $this->addSql('COMMENT ON COLUMN country.id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN country.capital_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('CREATE TABLE dojo (id UUID NOT NULL, village_id UUID DEFAULT NULL, owner_id UUID NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE UNIQUE INDEX UNIQ_9494CCB15E237E06 ON dojo (name)');
+ $this->addSql('CREATE INDEX IDX_9494CCB15E0D5582 ON dojo (village_id)');
+ $this->addSql('CREATE UNIQUE INDEX UNIQ_9494CCB17E3C61F9 ON dojo (owner_id)');
+ $this->addSql('COMMENT ON COLUMN dojo.id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN dojo.village_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN dojo.owner_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('CREATE TABLE dungeon (id UUID NOT NULL, city_id UUID NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE UNIQUE INDEX UNIQ_3FFA1F908BAC62AF ON dungeon (city_id)');
+ $this->addSql('COMMENT ON COLUMN dungeon.id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN dungeon.city_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('CREATE TABLE prefecture (id UUID NOT NULL, capital_id UUID NOT NULL, country_id UUID NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE UNIQUE INDEX UNIQ_ABE6511AFC2D9FF7 ON prefecture (capital_id)');
+ $this->addSql('CREATE INDEX IDX_ABE6511AF92F3E70 ON prefecture (country_id)');
+ $this->addSql('COMMENT ON COLUMN prefecture.id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN prefecture.capital_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN prefecture.country_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('CREATE TABLE technique (id UUID NOT NULL, prerequisite_id UUID DEFAULT NULL, costs INT NOT NULL, damage VARCHAR(255) NOT NULL, energy VARCHAR(255) NOT NULL, accuracy VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE UNIQUE INDEX UNIQ_D73B9841276AF86B ON technique (prerequisite_id)');
+ $this->addSql('COMMENT ON COLUMN technique.id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN technique.prerequisite_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('CREATE TABLE "user" (id UUID NOT NULL, dojo_id UUID DEFAULT NULL, auth_name VARCHAR(255) NOT NULL, properties JSON NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE UNIQUE INDEX UNIQ_8D93D64932F09E9C ON "user" (dojo_id)');
+ $this->addSql('COMMENT ON COLUMN "user".id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN "user".dojo_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('CREATE TABLE village (id UUID NOT NULL, prefecture_id UUID NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE INDEX IDX_4E6C7FAA9D39C865 ON village (prefecture_id)');
+ $this->addSql('COMMENT ON COLUMN village.id IS \'(DC2Type:ulid)\'');
+ $this->addSql('COMMENT ON COLUMN village.prefecture_id IS \'(DC2Type:ulid)\'');
+ $this->addSql('ALTER TABLE "character" ADD CONSTRAINT FK_937AB03432F09E9C FOREIGN KEY (dojo_id) REFERENCES dojo (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE character_technique ADD CONSTRAINT FK_506B3A7A1136BE75 FOREIGN KEY (character_id) REFERENCES "character" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE character_technique ADD CONSTRAINT FK_506B3A7A1F8ACB26 FOREIGN KEY (technique_id) REFERENCES technique (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE city ADD CONSTRAINT FK_2D5B0234B606863 FOREIGN KEY (dungeon_id) REFERENCES dungeon (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE country ADD CONSTRAINT FK_5373C966FC2D9FF7 FOREIGN KEY (capital_id) REFERENCES city (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE dojo ADD CONSTRAINT FK_9494CCB15E0D5582 FOREIGN KEY (village_id) REFERENCES village (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE dojo ADD CONSTRAINT FK_9494CCB17E3C61F9 FOREIGN KEY (owner_id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE dungeon ADD CONSTRAINT FK_3FFA1F908BAC62AF FOREIGN KEY (city_id) REFERENCES city (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE prefecture ADD CONSTRAINT FK_ABE6511AFC2D9FF7 FOREIGN KEY (capital_id) REFERENCES city (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE prefecture ADD CONSTRAINT FK_ABE6511AF92F3E70 FOREIGN KEY (country_id) REFERENCES country (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE technique ADD CONSTRAINT FK_D73B9841276AF86B FOREIGN KEY (prerequisite_id) REFERENCES technique (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE "user" ADD CONSTRAINT FK_8D93D64932F09E9C FOREIGN KEY (dojo_id) REFERENCES dojo (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE village ADD CONSTRAINT FK_4E6C7FAA9D39C865 FOREIGN KEY (prefecture_id) REFERENCES prefecture (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ }
+
+ public function down(Schema $schema): void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->addSql('CREATE SCHEMA public');
+ $this->addSql('ALTER TABLE "character" DROP CONSTRAINT FK_937AB03432F09E9C');
+ $this->addSql('ALTER TABLE character_technique DROP CONSTRAINT FK_506B3A7A1136BE75');
+ $this->addSql('ALTER TABLE character_technique DROP CONSTRAINT FK_506B3A7A1F8ACB26');
+ $this->addSql('ALTER TABLE city DROP CONSTRAINT FK_2D5B0234B606863');
+ $this->addSql('ALTER TABLE country DROP CONSTRAINT FK_5373C966FC2D9FF7');
+ $this->addSql('ALTER TABLE dojo DROP CONSTRAINT FK_9494CCB15E0D5582');
+ $this->addSql('ALTER TABLE dojo DROP CONSTRAINT FK_9494CCB17E3C61F9');
+ $this->addSql('ALTER TABLE dungeon DROP CONSTRAINT FK_3FFA1F908BAC62AF');
+ $this->addSql('ALTER TABLE prefecture DROP CONSTRAINT FK_ABE6511AFC2D9FF7');
+ $this->addSql('ALTER TABLE prefecture DROP CONSTRAINT FK_ABE6511AF92F3E70');
+ $this->addSql('ALTER TABLE technique DROP CONSTRAINT FK_D73B9841276AF86B');
+ $this->addSql('ALTER TABLE "user" DROP CONSTRAINT FK_8D93D64932F09E9C');
+ $this->addSql('ALTER TABLE village DROP CONSTRAINT FK_4E6C7FAA9D39C865');
+ $this->addSql('DROP TABLE "character"');
+ $this->addSql('DROP TABLE character_technique');
+ $this->addSql('DROP TABLE city');
+ $this->addSql('DROP TABLE country');
+ $this->addSql('DROP TABLE dojo');
+ $this->addSql('DROP TABLE dungeon');
+ $this->addSql('DROP TABLE prefecture');
+ $this->addSql('DROP TABLE technique');
+ $this->addSql('DROP TABLE "user"');
+ $this->addSql('DROP TABLE village');
+ }
+}
diff --git a/src/Controller/GetUserDojo.php b/src/Controller/GetUserDojo.php
new file mode 100644
index 0000000..d6607b2
--- /dev/null
+++ b/src/Controller/GetUserDojo.php
@@ -0,0 +1,21 @@
+getRepository(Dojo::class)->findOneByOwner($this->security->getUser());
+ }
+}
+
diff --git a/src/Entity/Character.php b/src/Entity/Character.php
index 58569f6..41231bd 100644
--- a/src/Entity/Character.php
+++ b/src/Entity/Character.php
@@ -1,6 +1,8 @@
getStrength());
+ $costs += self::skillCosts($this->getConstitution());
+ $costs += self::skillCosts($this->getAgility());
+ $costs += self::skillCosts($this->getChi());
+
+ foreach ($this->getTechniques() as $tech) {
+ $costs += $tech->getCosts();
+ }
+ return $available - $costs;
}
- public function getDojo(): ?Dojo
+ public static function loadValidatorMetadata(ClassMetadata $metadata): void
{
- return $this->dojo;
+ $metadata->addConstraint(new CharacterStats());
}
- public function setDojo(?Dojo $dojo): static
+ /**
+ * Calculates the aged based on the ulid value?
+ */
+ #[Groups('public')]
+ public function getAge(): int
{
- $this->dojo = $dojo;
+ return 21;
+ }
- return $this;
+ public static function skillCosts(int $value)
+ {
+ return pow(2, $value);
}
public function getName(): ?string
@@ -92,14 +118,14 @@ class Character extends Thing
return $this;
}
- public function getConstition(): ?int
+ public function getConstitution(): ?int
{
- return $this->constition;
+ return $this->constitution;
}
- public function setConstition(int $constition): static
+ public function setConstitution(int $constitution): static
{
- $this->constition = $constition;
+ $this->constitution = $constitution;
return $this;
}
@@ -116,45 +142,48 @@ class Character extends Thing
return $this;
}
- /**
- * @return Collection
- */
- public function getTechniques(): Collection
+ public function getChi(): ?int
{
- return $this->techniques;
+ return $this->chi;
}
- public function setTechniques(string $techniques): static
+ public function setChi(int $chi): static
{
- $this->techniques = $techniques;
+ $this->chi = $chi;
return $this;
}
- public function addTechnique(Technique $technique): static
+ public function getDojo(): ?Dojo
{
- if (!$this->techniques->contains($technique)) {
- $this->techniques->add($technique);
- }
-
- return $this;
+ return $this->dojo;
}
- public function removeTechnique(Technique $technique): static
+ public function setDojo(?Dojo $dojo): static
{
- $this->techniques->removeElement($technique);
+ $this->dojo = $dojo;
return $this;
}
- public function getConstitution(): ?int
+ /**
+ *
+ * @return Technique[]
+ */
+ public function getTechniques(): mixed
{
- return $this->constitution;
+ return $this->techniques->getValues();
}
- public function setConstitution(int $constitution): static
+ public function addTechnique(Technique $technique): static
{
- $this->constitution = $constitution;
+ $this->techniques[] = $technique;
+ return $this;
+ }
+
+ public function removeTechnique(Technique $technique): static
+ {
+ $this->techniques->removeElement($technique);
return $this;
}
diff --git a/src/Entity/Technique.php b/src/Entity/Technique.php
index b16d980..340d6b5 100644
--- a/src/Entity/Technique.php
+++ b/src/Entity/Technique.php
@@ -6,7 +6,7 @@ use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\OneToOne;
-#[Entity]
+#[Entity(repositoryClass: 'App\Repository\TechniqueRepository')]
class Technique extends Thing
{
@@ -17,19 +17,19 @@ class Technique extends Thing
public int $costs;
/**
- * Forumula to calculate the damage based on the stats.
+ * Formula to calculate the damage based on the stats.
*/
#[Column]
public string $damage;
/**
- * Forumula to calculate the damage based on the stats.
+ * Formula to calculate the consumed energy on use based on the stats.
*/
#[Column]
public string $energy;
/**
- * Forumula to calculate the damage based on the stats.
+ * Formula to calculate the hit chance accuracy based on the stats.
*/
#[Column]
public string $accuracy;
diff --git a/src/Entity/Thing.php b/src/Entity/Thing.php
index 4d19bea..f883cdb 100644
--- a/src/Entity/Thing.php
+++ b/src/Entity/Thing.php
@@ -3,6 +3,7 @@ namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UlidType;
+use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Uid\Ulid;
abstract class Thing
@@ -12,6 +13,12 @@ abstract class Thing
#[ORM\Column(type: UlidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.ulid_generator')]
+ #[Groups('public')]
public ?Ulid $id;
+
+ public function getId(): ?Ulid
+ {
+ return $this->id;
+ }
}
diff --git a/src/Entity/User.php b/src/Entity/User.php
index e50aa35..c22d298 100644
--- a/src/Entity/User.php
+++ b/src/Entity/User.php
@@ -9,7 +9,7 @@ use Doctrine\ORM\Mapping\OneToOne;
use Doctrine\ORM\Mapping\Table;
use Symfony\Component\Security\Core\User\UserInterface;
-#[Entity(repositoryClass: "App\Repository\UserRepository")]
+#[Entity(repositoryClass: 'App\Repository\UserRepository')]
#[Table(name: '`user`')]
class User extends Thing implements UserInterface
{
diff --git a/src/Factory/CharacterFactory.php b/src/Factory/CharacterFactory.php
index bf9cdbb..0b61aae 100644
--- a/src/Factory/CharacterFactory.php
+++ b/src/Factory/CharacterFactory.php
@@ -47,10 +47,11 @@ final class CharacterFactory extends ModelFactory
protected function getDefaults(): array
{
return [
- 'name' => self::faker()->text(),
+ 'name' => self::faker()->firstName(),
'strength' => self::faker()->numberBetween(1, 4),
'constitution' => self::faker()->numberBetween(1, 4),
'agility' => self::faker()->numberBetween(1, 4),
+ 'chi' => self::faker()->numberBetween(1, 4),
'techniques' => TechniqueFactory::createMany(2)
];
}
diff --git a/src/Repository/TechniqueRepository.php b/src/Repository/TechniqueRepository.php
new file mode 100644
index 0000000..d8a97c3
--- /dev/null
+++ b/src/Repository/TechniqueRepository.php
@@ -0,0 +1,24 @@
+
+ *
+ * @method Technique|null find($id, $lockMode = null, $lockVersion = null)
+ * @method Technique|null findOneBy(array $criteria, array $orderBy = null)
+ * @method Technique[] findAll()
+ * @method Technique[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class TechniqueRepository extends ServiceEntityRepository
+{
+
+ public function __construct(ManagerRegistry $registry)
+ {
+ parent::__construct($registry, Technique::class);
+ }
+}
diff --git a/src/Validator/CharacterStats.php b/src/Validator/CharacterStats.php
new file mode 100644
index 0000000..bc1cee6
--- /dev/null
+++ b/src/Validator/CharacterStats.php
@@ -0,0 +1,16 @@
+getFreeSkillPoints() < 0) {
+ $this->context->buildViolation($constraint->noMoreSkillPointsMessage)
+ ->atPath('character.freeSkillPoints')
+ ->addViolation();
+ }
+ }
+}
+
diff --git a/tests/AbstractTest.php b/tests/AbstractTest.php
new file mode 100644
index 0000000..f110a1f
--- /dev/null
+++ b/tests/AbstractTest.php
@@ -0,0 +1,42 @@
+format("c");
+
+ return sodium_bin2base64(sodium_crypto_sign($message, $sign_secret), SODIUM_BASE64_VARIANT_URLSAFE);
+ }
+
+ protected static function createClientWithToken($authName = null): Client
+ {
+ return static::createClient([],
+ [
+ 'headers' => [
+ 'accept' => 'application/json',
+ 'X-AUTH-TOKEN' => static::generateAuthToken($authName)
+ ]
+ ]);
+ }
+}
+
diff --git a/tests/CharacterTest.php b/tests/CharacterTest.php
index 627202a..c3fa502 100644
--- a/tests/CharacterTest.php
+++ b/tests/CharacterTest.php
@@ -1,28 +1,13 @@
format("c");
-
- return sodium_bin2base64(sodium_crypto_sign($message, $sign_secret), SODIUM_BASE64_VARIANT_URLSAFE);
- }
/**
* Requirement: A user should be able see all characters from a dojo, but only the public fields!
@@ -36,65 +21,173 @@ class CharacterTest extends ApiTestCase
]);
CharacterFactory::createMany(10);
- $response = static::createClient()->request('GET', '/api/dojo/' . $dojo->id . '/characters',
- [
- 'headers' => [
- 'accept' => 'application/json',
- 'X-AUTH-TOKEN' => $this->generateAuthToken($requestUser->authName)
- ]
- ]);
+ $response = static::createClientWithToken($requestUser->authName)->request('GET',
+ '/api/dojo/' . $dojo->id . '/characters');
$this->assertResponseStatusCodeSame(200);
+ $this->assertNotEquals("[[],[],[],[]]", $response->getContent());
+
// Because test fixtures are automatically loaded between each test, you can assert on them
$this->assertCount(4, $response->toArray());
- $this->assertNotEquals("[[],[],[],[]]", $response->getContent());
-
$chars = $response->toArray();
+ $this->assertEquals(4, count($chars[0]));
+ $this->assertArrayHasKey('id', $chars[0]);
$this->assertArrayHasKey('name', $chars[0]);
- $this->assertArrayHasKey('dojo', $chars[0]);
+ $this->assertEquals('/api/dojos/' . $dojo->getId()
+ ->toBase32(), $chars[0]['dojo']);
+ $this->assertArrayHasKey('age', $chars[0]);
+ $this->assertArrayNotHasKey('freeSkillPoints', $chars[0]);
$this->assertArrayNotHasKey('strength', $chars[0]); // not accessible via this route
$this->assertArrayNotHasKey('constitution', $chars[0]); // not accessible via this route
$this->assertArrayNotHasKey('agility', $chars[0]); // not accessible via this route
+ $this->assertArrayNotHasKey('chi', $chars[0]); // not accessible via this route
$this->assertArrayNotHasKey('techniques', $chars[0]); // not accessible via this route
}
/**
- * Requirement: A user should be able see all characters from a dojo, but only the public fields!
+ * Requirement: A user should be able see all of the characters from his dojo, not restricted by public fields!
*/
public function testRetrieveCharactersFromOwnDojoDetail(): void
{
$dojo = DojoFactory::createOne([
'owner' => UserFactory::createOne()
]);
- CharacterFactory::createMany(4, [
- 'dojo' => $dojo
+
+ $technique = TechniqueFactory::createOne();
+
+ $foo = CharacterFactory::createMany(4, [
+ 'dojo' => $dojo,
+ 'techniques' => [
+ $technique
+ ]
]);
+
+ $this->assertEquals(1, count($foo[0]->getTechniques()));
+
CharacterFactory::createMany(10);
- $response = static::createClient()->request('GET', '/api/dojo/characters',
- [
- 'headers' => [
- 'accept' => 'application/json',
- 'X-AUTH-TOKEN' => $this->generateAuthToken($dojo->getOwner()->authName)
- ]
- ]);
+ $response = static::createClientWithToken($dojo->getOwner()->authName)->request('GET', '/api/dojo/characters');
$this->assertResponseStatusCodeSame(200);
- // Because test fixtures are automatically loaded between each test, you can assert on them
- $this->assertCount(4, $response->toArray());
-
$this->assertNotEquals("[[],[],[],[]]", $response->getContent());
$chars = $response->toArray();
+ $this->assertEquals(10, count($chars[0]));
+ $this->assertArrayHasKey('id', $chars[0]);
$this->assertArrayHasKey('name', $chars[0]);
$this->assertArrayHasKey('dojo', $chars[0]);
- $this->assertArrayHasKey('strength', $chars[0]); // not accessible via this route
- $this->assertArrayHasKey('constitution', $chars[0]); // not accessible via this route
- $this->assertArrayHasKey('agility', $chars[0]); // not accessible via this route
- $this->assertArrayHasKey('techniques', $chars[0]); // not accessible via this route
+ $this->assertEquals('/api/dojos/' . $dojo->getId()
+ ->toBase32(), $chars[0]['dojo']);
+ $this->assertArrayHasKey('age', $chars[0]);
+ $this->assertArrayHasKey('freeSkillPoints', $chars[0]);
+ $this->assertArrayHasKey('strength', $chars[0]);
+ $this->assertArrayHasKey('constitution', $chars[0]);
+ $this->assertArrayHasKey('agility', $chars[0]);
+ $this->assertArrayHasKey('chi', $chars[0]);
+ $this->assertArrayHasKey('techniques', $chars[0]);
+ $this->assertEquals('/api/techniques/' . $technique->getId()
+ ->toBase32(), $chars[0]['techniques'][0]);
+ }
+
+ /**
+ * Requirement: MVP only (in the future the recuitment will be different).
+ * A user should be able to create a single character.
+ */
+ public function testCreateCharacter(): void
+ {
+ $dojo = DojoFactory::createOne([
+ 'owner' => UserFactory::createOne()
+ ]);
+
+ $tech = TechniqueFactory::createOne([
+ 'prerequisite' => NULL
+ ]);
+
+ $response = static::createClientWithToken($dojo->getOwner()->authName)->request('POST', '/api/characters',
+ [
+ 'json' => [
+ 'name' => 'Dude',
+ 'strength' => 1,
+ 'constitution' => 1,
+ 'agility' => 1,
+ 'chi' => 1,
+ 'techniques' => [
+ '/api/techniques/' . $tech->getId()
+ ->toBase32()
+ ]
+ ]
+ ]);
+
+ $this->assertResponseStatusCodeSame(201);
+
+ $this->assertArrayHasKey('id', $response->toArray());
+ }
+
+ /**
+ * Requirement: MVP only (in the future the recuitment will be different).
+ * A user should NOT be able spent more skill points than available.
+ */
+ public function testCreateCharacterStatsTooHigh(): void
+ {
+ $dojo = DojoFactory::createOne([
+ 'owner' => UserFactory::createOne()
+ ]);
+
+ $tech = TechniqueFactory::createOne([
+ 'prerequisite' => NULL
+ ]);
+
+ static::createClientWithToken($dojo->getOwner()->authName)->request('POST', '/api/characters',
+ [
+ 'json' => [
+ 'name' => 'Dude',
+ 'strength' => 99,
+ 'constitution' => 1,
+ 'agility' => 1,
+ 'chi' => 1,
+ 'techniques' => [
+ '/api/techniques/' . $tech->getId()
+ ->toBase32()
+ ]
+ ]
+ ]);
+
+ $this->assertResponseStatusCodeSame(422);
+ }
+
+ /**
+ * Requirement: MVP only (in the future the recuitment will be different).
+ * A user should NOT be able spent more skill points than available.
+ */
+ public function testCreateCharacterTooExpensiveTechnique(): void
+ {
+ $dojo = DojoFactory::createOne([
+ 'owner' => UserFactory::createOne()
+ ]);
+
+ $tech = TechniqueFactory::createOne([
+ 'costs' => 99
+ ]);
+
+ static::createClientWithToken($dojo->getOwner()->authName)->request('POST', '/api/characters',
+ [
+ 'json' => [
+ 'name' => 'Dude',
+ 'strength' => 1,
+ 'constitution' => 1,
+ 'agility' => 1,
+ 'chi' => 1,
+ 'techniques' => [
+ '/api/techniques/' . $tech->getId()
+ ->toBase32()
+ ]
+ ]
+ ]);
+
+ $this->assertResponseStatusCodeSame(422);
}
}
diff --git a/tests/DojoTest.php b/tests/DojoTest.php
index 0975c82..8d0520c 100644
--- a/tests/DojoTest.php
+++ b/tests/DojoTest.php
@@ -1,30 +1,12 @@
format("c");
-
- return sodium_bin2base64(sodium_crypto_sign($message, $sign_secret), SODIUM_BASE64_VARIANT_URLSAFE);
- }
/**
* Requirement: A user should be able to create a dojo!
@@ -37,22 +19,63 @@ class DojoTest extends ApiTestCase
$this->assertCount(0, $userRepository->findByAuthName($userName));
- static::createClient()->request('POST', '/api/dojos',
- [
- 'headers' => [
- 'accept' => 'application/json',
- 'X-AUTH-TOKEN' => $this->generateAuthToken($userName)
- ],
- 'json' => [
- 'name' => $dojoName
- ]
- ]);
+ static::createClientWithToken($userName)->request('POST', '/api/dojos', [
+ 'json' => [
+ 'name' => $dojoName
+ ]
+ ]);
$this->assertResponseStatusCodeSame(201);
$this->assertCount(1, $userRepository->findByAuthName($userName));
}
+ /**
+ * Requirement: A user should be request his own dojo!
+ */
+ public function testUserReadDojo(): void
+ {
+ $userName = "FooBarFigher";
+ $dojoName = "BigFightDojo";
+ $dojo = DojoFactory::createOne(
+ [
+ 'name' => $dojoName,
+ 'owner' => UserFactory::createOne([
+ 'authName' => $userName
+ ])
+ ]);
+
+ static::createClientWithToken($userName)->request('GET', '/api/dojo');
+
+ $this->assertResponseStatusCodeSame(200);
+
+ $this->assertJsonContains(
+ [
+ 'name' => 'BigFightDojo',
+ 'members' => [],
+ 'owner' => '/api/users/' . $dojo->owner->getId()
+ ->toBase32(),
+ 'id' => $dojo->getId()
+ ->toBase32()
+ ]);
+ }
+
+ /**
+ * Requirement: A user should be request his own dojo!
+ * Fails, if the dojo is not yet created.
+ */
+ public function testUserReadDojoNotYetCreated(): void
+ {
+ $userName = "FooBarFigher";
+ $userRepository = $this->getContainer()->get(UserRepository::class);
+
+ $this->assertCount(0, $userRepository->findByAuthName($userName));
+
+ static::createClientWithToken($userName)->request('GET', '/api/dojo');
+
+ $this->assertResponseStatusCodeSame(404);
+ }
+
/**
* Requirement: A user should NOT be able to create more than one dojos!
*/
@@ -67,16 +90,11 @@ class DojoTest extends ApiTestCase
])
]);
- static::createClient()->request('POST', '/api/dojos',
- [
- 'headers' => [
- 'accept' => 'application/json',
- 'X-AUTH-TOKEN' => $this->generateAuthToken($userName)
- ],
- 'json' => [
- 'name' => $dojoName
- ]
- ]);
+ static::createClientWithToken($userName)->request('POST', '/api/dojos', [
+ 'json' => [
+ 'name' => $dojoName
+ ]
+ ]);
$this->assertResponseStatusCodeSame(409); // 409 Conflict
}
@@ -98,12 +116,10 @@ class DojoTest extends ApiTestCase
])
]);
- static::createClient()->request('PATCH', '/api/dojos/' . $dojo->id,
+ static::createClientWithToken($userName)->request('PATCH', '/api/dojos/' . $dojo->id,
[
'headers' => [
- 'content-type' => 'application/merge-patch+json',
- 'accept' => 'application/json',
- 'X-AUTH-TOKEN' => $this->generateAuthToken($userName)
+ 'content-type' => 'application/merge-patch+json'
],
'json' => [
'name' => $newDojoName