Skip to content

Commit

Permalink
Fix unit queue requirements check and update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rautamik committed Nov 3, 2024
1 parent b72f6dd commit 0064cfe
Show file tree
Hide file tree
Showing 15 changed files with 392 additions and 221 deletions.
2 changes: 1 addition & 1 deletion app/Http/Controllers/Abstracts/AbstractUnitsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public function index(Request $request, PlayerService $player, ObjectService $ob
$amount = $planet->getObjectAmount($object->machine_name);

// Check requirements of this building
$requirements_met = $objects->objectRequirementsMet($object->machine_name, $planet, $player);
$requirements_met = $objects->objectRequirementsMet($object->machine_name, $planet, $player, 0, false);

// Check if the current planet has enough resources to build this building.
$enough_resources = $planet->hasResources($objects->getObjectPrice($object->machine_name, $planet));
Expand Down
4 changes: 2 additions & 2 deletions app/Services/BuildingQueueService.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ public function add(PlanetService $planet, int $building_id): void
{
$build_queue = $this->retrieveQueue($planet);

$building = $this->objects->getObjectById($building_id);

// Max amount of buildings that can be in the queue in a given time.
// TODO: refactor throw exception into a more user-friendly message.
if ($build_queue->isQueueFull()) {
// Max amount of build queue items already exist, throw exception.
throw new Exception('Maximum number of items already in queue.');
}

$building = $this->objects->getObjectById($building_id);

// Check if user satisifes requirements to build this object.
// TODO: refactor throw exception into a more user-friendly message.
$requirements_met = $this->objects->objectRequirementsMet($building->machine_name, $planet, $planet->getPlayer());
Expand Down
2 changes: 1 addition & 1 deletion app/Services/ObjectService.php
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ public function objectRequirementsMet(string $machine_name, PlanetService $plane
$object_required = $this->getObjectByMachineName($requirement->object_machine_name);
$check_queue = $queued;

// SKip queue check for research lab as it must be present for research objects
// Skip queue check for research lab as it must be present for research objects
if ($object_required->machine_name === 'research_lab') {
$check_queue = false;
}
Expand Down
20 changes: 14 additions & 6 deletions app/Services/ResearchQueueService.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,21 +116,29 @@ public function retrieveFinishedForUser(PlayerService $player): \Illuminate\Supp
*/
public function add(PlayerService $player, PlanetService $planet, int $research_object_id): void
{
$build_queue = $this->retrieveQueue($planet);
$research_queue = $this->retrieveQueue($planet);

// Max amount of buildings that can be in the queue at a given time.
if ($build_queue->isQueueFull()) {
// Max amount of build queue items already exist, throw exception.
// Max amount of research items that can be in the queue at a given time.
// TODO: refactor throw exception into a more user-friendly message.
if ($research_queue->isQueueFull()) {
// Max amount of research queue items already exist, throw exception.
throw new Exception('Maximum number of items already in queue.');
}

$object = $this->objects->getResearchObjectById($research_object_id);

// Check if user satisifes requirements to research this object.
// TODO: refactor throw exception into a more user-friendly message.
$requirements_met = $this->objects->objectRequirementsMet($object->machine_name, $planet, $planet->getPlayer());
if (!$requirements_met) {
throw new Exception('Requirements not met to build this object.');
}

// @TODO: add checks that current logged in user is owner of planet
// and is able to add this object to the building queue.
// and is able to add this object to the research queue.
$current_level = $player->getResearchLevel($object->machine_name);

// Check to see how many other items of this building there are already
// Check to see how many other items of this technology there are already
// in the queue, because if so then the level needs to be higher than that.
$amount = $this->activeBuildingQueueItemCount($player, $research_object_id);
$next_level = $current_level + $amount + 1;
Expand Down
2 changes: 1 addition & 1 deletion app/Services/UnitQueueService.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public function add(PlanetService $planet, int $object_id, int $requested_build_
$object = $this->objects->getUnitObjectById($object_id);

// Check if user satisifes requirements to build this object.
$requirements_met = $this->objects->objectRequirementsMet($object->machine_name, $planet, $planet->getPlayer());
$requirements_met = $this->objects->objectRequirementsMet($object->machine_name, $planet, $planet->getPlayer(), 0, false);

// Sanity check: check if the planet has enough resources to build
// the amount requested. If not, then adjust the ordered amount.
Expand Down
68 changes: 66 additions & 2 deletions tests/AccountTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ protected function assertResourcesOnPage(TestResponse $response, Resources $reso
}
}

protected function assertObjectInQueue(TestResponse $response, string $machine_name, string $error_message = ''): void
protected function assertObjectInQueue(TestResponse $response, string $machine_name, int $level, string $error_message = ''): void
{
// Get object name from machine name.
try {
Expand All @@ -399,7 +399,7 @@ protected function assertObjectInQueue(TestResponse $response, string $machine_n
if (!$responseContent) {
$responseContent = '';
}
$condition1 = str_contains($responseContent, 'Cancel production of ' . $object->title);
$condition1 = str_contains($responseContent, 'Cancel production of ' . $object->title . ' level '. $level);
$condition2 = str_contains($responseContent, 'do you really want to cancel ' . $object->title);
$this->assertTrue($condition1 || $condition2, 'Neither of the expected texts were found in the response.');
} catch (Exception $e) {
Expand Down Expand Up @@ -432,6 +432,70 @@ protected function assertObjectNotInQueue(TestResponse $response, string $machin
}
}

protected function assertEmptyBuildingQueue(TestResponse $response, string $error_message = ''): void
{
// Check if "no buildings being built" text is present on page.
try {
$responseContent = $response->getContent();
if (!$responseContent) {
$responseContent = '';
}
$condition = str_contains($responseContent, 'no building being built');
$this->assertTrue($condition, 'expected text was not found in the response.');
} catch (Exception $e) {
if (!empty($error_message)) {
$this->fail($error_message . '. Error: ' . $e->getMessage());
} else {
$this->fail('Building queue is not empty. Error: ' . $e->getMessage());
}
}
}

protected function assertEmptyResearchQueue(TestResponse $response, string $error_message = ''): void
{
// Check if "no research done" text is present on page.
try {
$responseContent = $response->getContent();
if (!$responseContent) {
$responseContent = '';
}
$condition = str_contains($responseContent, 'no research done');
$this->assertTrue($condition, 'expected text was not found in the response.');
} catch (Exception $e) {
if (!empty($error_message)) {
$this->fail($error_message . '. Error: ' . $e->getMessage());
} else {
$this->fail('Research queue is not empty. Error: ' . $e->getMessage());
}
}
}

protected function assertRequirementsNotMet(TestResponse $response, string $machine_name, string $error_message = ''): void
{
// Get object name from machine name.
try {
$object = $this->planetService->objects->getObjectByMachineName($machine_name);
} catch (Exception $e) {
$this->fail('Failed to get object by machine name: ' . $machine_name . '. Error: ' . $e->getMessage());
}

// Check if "Requirements are not met" text is present on page.
try {
$responseContent = $response->getContent();
if (!$responseContent) {
$responseContent = '';
}
$condition = str_contains($responseContent, $object->title.'<br/>Requirements are not met!');
$this->assertTrue($condition, 'expected text was not found in the response.');
} catch (Exception $e) {
if (!empty($error_message)) {
$this->fail($error_message . '. Error: ' . $e->getMessage());
} else {
$this->fail('Requirements are met. Error: ' . $e->getMessage());
}
}
}

/**
* Add a resource build request to the current users current planet.
* @param string $machine_name
Expand Down
53 changes: 50 additions & 3 deletions tests/Feature/BuildQueueCancelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function testBuildQueueCancelMultiple(): void
Carbon::setTestNow($testTime);

$response = $this->get('/resources');
$this->assertObjectInQueue($response, 'metal_mine', 'Metal mine is expected in build queue but cannot be found.');
$this->assertObjectInQueue($response, 'metal_mine', 3, 'Metal mine level 3 is expected in build queue but cannot be found.');

// Extract first and second number on page which looks like this where num1/num2 are ints:
// "cancelProduction(num1,num2,"
Expand Down Expand Up @@ -95,7 +95,7 @@ public function testBuildQueueCancelRefundResources(): void
$this->addResourceBuildRequest('metal_mine');

$response = $this->get('/resources');
$this->assertObjectInQueue($response, 'metal_mine', 'Metal mine is not in build queue.');
$this->assertObjectInQueue($response, 'metal_mine', 1, 'Metal mine level 1 is not in build queue.');

// Extract first and second number on page which looks like this where num1/num2 are ints:
// "cancelProduction(num1,num2,"
Expand Down Expand Up @@ -149,7 +149,7 @@ public function testBuildQueueCancelSecondEntry(): void

// Extract first and second number on page which looks like this where num1/num2 are ints:
// "cancelbuilding(num1,num2,"
$this->assertObjectInQueue($response, 'crystal_mine', 'Crystal mine is not in build queue.');
$this->assertObjectInQueue($response, 'crystal_mine', 1, 'Crystal mine level 1 is not in build queue.');

// Extract the content from the response
$pageContent = $response->getContent();
Expand Down Expand Up @@ -178,4 +178,51 @@ public function testBuildQueueCancelSecondEntry(): void
$this->throwException(new BindingResolutionException('Less than two "cancelProduction" calls found.'));
}
}

/**
* Tests building queue item is cancelled if requirements are not met.
*/
public function testCancelObjectMissingRequirements(): void
{
// Assert that build queue is empty
$response = $this->get('/facilities');
$response->assertStatus(200);

$this->assertEmptyBuildingQueue($response);

// Add resource to build required facilities to planet
$this->planetAddResources(new Resources(5000, 5000, 5000, 0));

// Add required facilities to building queue
$this->addFacilitiesBuildRequest('robot_factory');
$this->addFacilitiesBuildRequest('robot_factory');
$this->addFacilitiesBuildRequest('shipyard');

$response = $this->get('/facilities');
$this->assertObjectInQueue($response, 'shipyard', 1, 'Shipyard level 1 is not in build queue.');

// Extract the first and second number from the first cancelbuilding call
$cancelProductionCall = $response->getContent();
if (empty($cancelProductionCall)) {
$cancelProductionCall = '';
}
$cancelProductionCall = explode('onclick="cancelbuilding(', $cancelProductionCall);
$cancelProductionCall = explode(',', $cancelProductionCall[1]);
$number1 = (int)$cancelProductionCall[0];
$number2 = (int)$cancelProductionCall[1];

// Check if both numbers are integers. If not, throw an exception.
if (empty($number1) || empty($number2)) {
throw new BindingResolutionException('Could not extract the building queue ID from the page.');
}

// Cancel Robotics Factory level 1, this will cancel also Robotics Factory level 2 and Shipyard level 1
$this->cancelFacilitiesBuildRequest($number1, $number2);

// Assert that building queue is empty
$response = $this->get('/facilities');
$response->assertStatus(200);

$this->assertEmptyBuildingQueue($response);
}
}
34 changes: 34 additions & 0 deletions tests/Feature/BuildQueueTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,40 @@ public function testBuildQueueFailUnfulfilledRequirements(): void
$this->assertObjectLevelOnPage($response, 'fusion_plant', 0, 'Fusion Reactor has been built while player has not satisfied building requirements.');
}

/**
* Verify that shipyard can be queued when robotics factory is in queue.
* @throws Exception
*/
public function testBuildQueueFacilitiesShipyardQueuedRequirements(): void
{
// Set the current time to a specific moment for testing
$testTime = Carbon::create(2024, 1, 1, 12, 0, 0);
Carbon::setTestNow($testTime);

// Add resource to build required facilities to planet
$this->planetAddResources(new Resources(5000, 5000, 5000, 0));

// Assert that building requirements for Shipyard are not met as Robotics Factory is missing
$response = $this->get('/facilities');
$response->assertStatus(200);
$this->assertRequirementsNotMet($response, 'shipyard', 'Shipyard building requirements not met.');

// Add Robotics Factory level 1 and 2 to build queue
$this->addFacilitiesBuildRequest('robot_factory');
$this->addFacilitiesBuildRequest('robot_factory');

// Add Shipyard level 1 to queue
$this->addFacilitiesBuildRequest('shipyard');

// Verify the research is finished 10 minute later.
$testTime = Carbon::create(2024, 1, 1, 12, 10, 0);
Carbon::setTestNow($testTime);

$response = $this->get('/facilities');
$response->assertStatus(200);
$this->assertObjectLevelOnPage($response, 'shipyard', 1, 'Shipyard is not at level one 10 minutes after build request issued.');
}

/**
* Verify that building construction time is calculated correctly (higher than 0)
* @throws Exception
Expand Down
53 changes: 50 additions & 3 deletions tests/Feature/ResearchQueueCancelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Tests\Feature;

use Exception;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Support\Carbon;
use Illuminate\Testing\TestResponse;
use OGame\Models\Resources;
Expand Down Expand Up @@ -39,7 +40,7 @@ public function testResearchQueueCancelMultiple(): void
Carbon::setTestNow($testTime);

$response = $this->get('/research');
$this->assertObjectInQueue($response, 'energy_technology', 'Energy Technology is expected in build queue but cannot be found.');
$this->assertObjectInQueue($response, 'energy_technology', 3, 'Energy Technology level 3 is expected in build queue but cannot be found.');

$this->pressCancelButtonOnPage($response);

Expand Down Expand Up @@ -81,7 +82,7 @@ public function testResearchQueueCancelRefundResources(): void

$response = $this->get('/research');
$response->assertStatus(200);
$this->assertObjectInQueue($response, 'energy_technology', 'Energy Technology is not in build queue.');
$this->assertObjectInQueue($response, 'energy_technology', 1, 'Energy Technology level 1 is not in build queue.');

$this->pressCancelButtonOnPage($response);

Expand Down Expand Up @@ -116,7 +117,7 @@ public function testBuildQueueCancelSecondEntry(): void
$response = $this->get('/research');
$response->assertStatus(200);

$this->assertObjectInQueue($response, 'computer_technology', 'Computer Technology is not in build queue.');
$this->assertObjectInQueue($response, 'computer_technology', 1, 'Computer Technology level 1 is not in build queue.');

// Extract the content from the response
$pageContent = $response->getContent();
Expand Down Expand Up @@ -208,4 +209,50 @@ private function pressCancelButtonOnPage(TestResponse $response): void
// Do POST to cancel build queue item:
$this->cancelResearchBuildRequest($number1, $number2);
}

/**
* Tests research queue item is cancelled if requirements are not met.
*/
public function testCancelResearchMissingRequirements(): void
{
// Assert that research queue is empty
$response = $this->get('/research');
$response->assertStatus(200);

$this->assertEmptyResearchQueue($response);

// Set facilities and add resources to planet that test requires.
$this->planetSetObjectLevel('research_lab', 2);
$this->planetAddResources(new Resources(5000, 5000, 5000, 0));

$this->addResearchBuildRequest('energy_technology');
$this->addResearchBuildRequest('impulse_drive');

$response = $this->get('/research');
$this->assertObjectInQueue($response, 'impulse_drive', 1, 'Impulse Drive 1 is not in research queue.');

// Extract the first and second number from the first cancelbuilding call
$cancelProductionCall = $response->getContent();
if (empty($cancelProductionCall)) {
$cancelProductionCall = '';
}
$cancelProductionCall = explode('onclick="cancelbuilding(', $cancelProductionCall);
$cancelProductionCall = explode(',', $cancelProductionCall[1]);
$number1 = (int)$cancelProductionCall[0];
$number2 = (int)$cancelProductionCall[1];

// Check if both numbers are integers. If not, throw an exception.
if (empty($number1) || empty($number2)) {
throw new BindingResolutionException('Could not extract the building queue ID from the page.');
}

// Cancel Energy technology level 1, this will cancel also Impulse Drive level 1
$this->cancelResearchBuildRequest($number1, $number2);

// Assert that building queue is empty
$response = $this->get('/research');
$response->assertStatus(200);

$this->assertEmptyResearchQueue($response);
}
}
Loading

0 comments on commit 0064cfe

Please sign in to comment.