16 - Update tests for integer allocation_value
This commit is contained in:
parent
3a5126f51c
commit
d6f60ab987
5 changed files with 52 additions and 75 deletions
|
|
@ -23,7 +23,7 @@ protected function setUp(): void
|
|||
|
||||
public function test_can_update_starting_amount_only(): void
|
||||
{
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(1000)->create([
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(100000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'starting_amount' => 0,
|
||||
'priority' => 1,
|
||||
|
|
@ -44,7 +44,7 @@ public function test_can_update_starting_amount_only(): void
|
|||
|
||||
public function test_can_update_type_only(): void
|
||||
{
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(1000)->create([
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(100000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'priority' => 1,
|
||||
]);
|
||||
|
|
@ -63,7 +63,7 @@ public function test_can_update_type_only(): void
|
|||
|
||||
public function test_can_update_buffer_multiplier_only(): void
|
||||
{
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(1000)->create([
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(100000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'buffer_multiplier' => 0,
|
||||
'priority' => 1,
|
||||
|
|
@ -97,7 +97,7 @@ public function test_cannot_change_overflow_type(): void
|
|||
|
||||
public function test_starting_amount_rejects_negative(): void
|
||||
{
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(1000)->create([
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(100000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'priority' => 1,
|
||||
]);
|
||||
|
|
@ -112,7 +112,7 @@ public function test_starting_amount_rejects_negative(): void
|
|||
|
||||
public function test_buffer_multiplier_forced_to_zero_for_non_fixed_limit(): void
|
||||
{
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(1000)->create([
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(100000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'buffer_multiplier' => 1.5,
|
||||
'priority' => 1,
|
||||
|
|
@ -120,7 +120,7 @@ public function test_buffer_multiplier_forced_to_zero_for_non_fixed_limit(): voi
|
|||
|
||||
$response = $this->patchJson("/buckets/{$bucket->uuid}", [
|
||||
'allocation_type' => 'percentage',
|
||||
'allocation_value' => 25,
|
||||
'allocation_value' => 2500,
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
|
|
@ -133,7 +133,7 @@ public function test_buffer_multiplier_forced_to_zero_for_non_fixed_limit(): voi
|
|||
|
||||
public function test_response_includes_starting_amount(): void
|
||||
{
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(1000)->create([
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(100000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'starting_amount' => 500,
|
||||
'priority' => 1,
|
||||
|
|
@ -150,7 +150,7 @@ public function test_response_includes_starting_amount(): void
|
|||
|
||||
public function test_can_update_name_only(): void
|
||||
{
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(1000)->create([
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(100000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'name' => 'Old Name',
|
||||
'priority' => 1,
|
||||
|
|
@ -169,7 +169,7 @@ public function test_can_update_name_only(): void
|
|||
|
||||
public function test_partial_update_does_not_null_other_fields(): void
|
||||
{
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(1000)->create([
|
||||
$bucket = Bucket::factory()->need()->fixedLimit(100000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'starting_amount' => 500,
|
||||
'buffer_multiplier' => 1.5,
|
||||
|
|
@ -183,7 +183,7 @@ public function test_partial_update_does_not_null_other_fields(): void
|
|||
$response->assertOk();
|
||||
$bucket->refresh();
|
||||
$this->assertEquals(750, $bucket->starting_amount);
|
||||
$this->assertEquals(1000, (float) $bucket->allocation_value);
|
||||
$this->assertEquals(100000, $bucket->allocation_value);
|
||||
$this->assertEquals(1.5, (float) $bucket->buffer_multiplier);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@ protected function setUp(): void
|
|||
|
||||
public function test_preview_returns_correct_allocations(): void
|
||||
{
|
||||
// allocation_value is in dollars, but PipelineAllocationService treats
|
||||
// getEffectiveCapacity() return as cents (known unit mismatch).
|
||||
// fixedLimit(50000) = $500 capacity as seen by the service.
|
||||
Bucket::factory()->need()->fixedLimit(50000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'name' => 'Rent',
|
||||
|
|
@ -38,26 +35,24 @@ public function test_preview_returns_correct_allocations(): void
|
|||
'starting_amount' => 0,
|
||||
]);
|
||||
|
||||
// Send 70000 cents = $700
|
||||
$response = $this->postJson(
|
||||
"/scenarios/{$this->scenario->uuid}/projections/preview",
|
||||
['amount' => 700]
|
||||
['amount' => 70000]
|
||||
);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonCount(2, 'allocations');
|
||||
$response->assertJsonPath('allocations.0.bucket_name', 'Rent');
|
||||
$response->assertJsonPath('allocations.0.allocated_amount', 500);
|
||||
$response->assertJsonPath('allocations.0.allocated_amount', 50000);
|
||||
$response->assertJsonPath('allocations.1.bucket_name', 'Fun');
|
||||
$response->assertJsonPath('allocations.1.allocated_amount', 200);
|
||||
$response->assertJsonPath('total_allocated', 700);
|
||||
$response->assertJsonPath('allocations.1.allocated_amount', 20000);
|
||||
$response->assertJsonPath('total_allocated', 70000);
|
||||
$response->assertJsonPath('unallocated', 0);
|
||||
}
|
||||
|
||||
public function test_preview_returns_remaining_capacity(): void
|
||||
{
|
||||
// fixedLimit(50000) → getEffectiveCapacity() = 50000 (treated as cents by service)
|
||||
// Input $300 = 30000 cents, allocated = min(50000, 30000) = 30000 cents = $300
|
||||
// remaining = (50000 - 30000) / 100 = $200
|
||||
Bucket::factory()->need()->fixedLimit(50000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'name' => 'Savings',
|
||||
|
|
@ -65,14 +60,15 @@ public function test_preview_returns_remaining_capacity(): void
|
|||
'starting_amount' => 0,
|
||||
]);
|
||||
|
||||
// Send 30000 cents = $300
|
||||
$response = $this->postJson(
|
||||
"/scenarios/{$this->scenario->uuid}/projections/preview",
|
||||
['amount' => 300]
|
||||
['amount' => 30000]
|
||||
);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('allocations.0.allocated_amount', 300);
|
||||
$response->assertJsonPath('allocations.0.remaining_capacity', 200);
|
||||
$response->assertJsonPath('allocations.0.allocated_amount', 30000);
|
||||
$response->assertJsonPath('allocations.0.remaining_capacity', 20000);
|
||||
}
|
||||
|
||||
public function test_preview_returns_uuids_not_integer_ids(): void
|
||||
|
|
@ -85,7 +81,7 @@ public function test_preview_returns_uuids_not_integer_ids(): void
|
|||
|
||||
$response = $this->postJson(
|
||||
"/scenarios/{$this->scenario->uuid}/projections/preview",
|
||||
['amount' => 100]
|
||||
['amount' => 10000]
|
||||
);
|
||||
|
||||
$response->assertOk();
|
||||
|
|
@ -102,7 +98,7 @@ public function test_preview_includes_bucket_type(): void
|
|||
|
||||
$response = $this->postJson(
|
||||
"/scenarios/{$this->scenario->uuid}/projections/preview",
|
||||
['amount' => 100]
|
||||
['amount' => 10000]
|
||||
);
|
||||
|
||||
$response->assertOk();
|
||||
|
|
@ -146,13 +142,13 @@ public function test_preview_with_no_buckets_returns_empty_allocations(): void
|
|||
{
|
||||
$response = $this->postJson(
|
||||
"/scenarios/{$this->scenario->uuid}/projections/preview",
|
||||
['amount' => 1000]
|
||||
['amount' => 100000]
|
||||
);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('allocations', []);
|
||||
$response->assertJsonPath('total_allocated', 0);
|
||||
$response->assertJsonPath('unallocated', 1000);
|
||||
$response->assertJsonPath('unallocated', 100000);
|
||||
}
|
||||
|
||||
public function test_preview_respects_priority_ordering(): void
|
||||
|
|
@ -173,33 +169,14 @@ public function test_preview_respects_priority_ordering(): void
|
|||
|
||||
$response = $this->postJson(
|
||||
"/scenarios/{$this->scenario->uuid}/projections/preview",
|
||||
['amount' => 400]
|
||||
['amount' => 40000]
|
||||
);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('allocations.0.bucket_name', 'High Priority');
|
||||
$response->assertJsonPath('allocations.0.allocated_amount', 300);
|
||||
$response->assertJsonPath('allocations.0.allocated_amount', 30000);
|
||||
$response->assertJsonPath('allocations.1.bucket_name', 'Low Priority');
|
||||
$response->assertJsonPath('allocations.1.allocated_amount', 100);
|
||||
}
|
||||
|
||||
public function test_preview_handles_dollar_cent_conversion_accurately(): void
|
||||
{
|
||||
Bucket::factory()->need()->fixedLimit(100000)->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'priority' => 1,
|
||||
'starting_amount' => 0,
|
||||
]);
|
||||
|
||||
$response = $this->postJson(
|
||||
"/scenarios/{$this->scenario->uuid}/projections/preview",
|
||||
['amount' => 15.50]
|
||||
);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('allocations.0.allocated_amount', 15.5);
|
||||
$response->assertJsonPath('total_allocated', 15.5);
|
||||
$response->assertJsonPath('unallocated', 0);
|
||||
$response->assertJsonPath('allocations.1.allocated_amount', 10000);
|
||||
}
|
||||
|
||||
public function test_preview_with_overflow_bucket_captures_remainder(): void
|
||||
|
|
@ -220,16 +197,16 @@ public function test_preview_with_overflow_bucket_captures_remainder(): void
|
|||
|
||||
$response = $this->postJson(
|
||||
"/scenarios/{$this->scenario->uuid}/projections/preview",
|
||||
['amount' => 500]
|
||||
['amount' => 50000]
|
||||
);
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonPath('allocations.0.bucket_name', 'Rent');
|
||||
$response->assertJsonPath('allocations.0.allocated_amount', 200);
|
||||
$response->assertJsonPath('allocations.0.allocated_amount', 20000);
|
||||
$response->assertJsonPath('allocations.1.bucket_name', 'Overflow');
|
||||
$response->assertJsonPath('allocations.1.allocated_amount', 300);
|
||||
$response->assertJsonPath('allocations.1.allocated_amount', 30000);
|
||||
$response->assertJsonPath('allocations.1.remaining_capacity', null);
|
||||
$response->assertJsonPath('total_allocated', 500);
|
||||
$response->assertJsonPath('total_allocated', 50000);
|
||||
$response->assertJsonPath('unallocated', 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,14 +32,14 @@ public function test_can_create_fixed_limit_bucket(): void
|
|||
$this->scenario,
|
||||
'Test Bucket',
|
||||
BucketAllocationTypeEnum::FIXED_LIMIT,
|
||||
allocationValue: 1000.00
|
||||
allocationValue: 100000
|
||||
);
|
||||
|
||||
$this->assertInstanceOf(Bucket::class, $bucket);
|
||||
$this->assertEquals('Test Bucket', $bucket->name);
|
||||
$this->assertEquals(BucketTypeEnum::NEED, $bucket->type);
|
||||
$this->assertEquals(BucketAllocationTypeEnum::FIXED_LIMIT, $bucket->allocation_type);
|
||||
$this->assertEquals(1000.00, $bucket->allocation_value);
|
||||
$this->assertEquals(100000, $bucket->allocation_value);
|
||||
$this->assertEquals(1, $bucket->priority);
|
||||
$this->assertEquals(1, $bucket->sort_order);
|
||||
$this->assertEquals($this->scenario->id, $bucket->scenario_id);
|
||||
|
|
@ -51,11 +51,11 @@ public function test_can_create_percentage_bucket(): void
|
|||
$this->scenario,
|
||||
'Percentage Bucket',
|
||||
BucketAllocationTypeEnum::PERCENTAGE,
|
||||
allocationValue: 25.5
|
||||
allocationValue: 2550
|
||||
);
|
||||
|
||||
$this->assertEquals(BucketAllocationTypeEnum::PERCENTAGE, $bucket->allocation_type);
|
||||
$this->assertEquals(25.5, $bucket->allocation_value);
|
||||
$this->assertEquals(2550, $bucket->allocation_value);
|
||||
}
|
||||
|
||||
public function test_can_create_unlimited_overflow_bucket(): void
|
||||
|
|
@ -79,7 +79,7 @@ public function test_unlimited_overflow_bucket_ignores_allocation_value(): void
|
|||
'Overflow Bucket',
|
||||
BucketAllocationTypeEnum::UNLIMITED,
|
||||
BucketTypeEnum::OVERFLOW,
|
||||
999.99
|
||||
99999
|
||||
);
|
||||
|
||||
$this->assertEquals(BucketAllocationTypeEnum::UNLIMITED, $bucket->allocation_type);
|
||||
|
|
@ -279,26 +279,26 @@ public function test_throws_exception_for_percentage_without_allocation_value():
|
|||
public function test_throws_exception_for_percentage_below_minimum(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Percentage allocation value must be between 0.01 and 100');
|
||||
$this->expectExceptionMessage('Percentage allocation value must be between 1 and 10000');
|
||||
|
||||
$this->action->execute(
|
||||
$this->scenario,
|
||||
'Test Bucket',
|
||||
BucketAllocationTypeEnum::PERCENTAGE,
|
||||
allocationValue: 0.005
|
||||
allocationValue: 0
|
||||
);
|
||||
}
|
||||
|
||||
public function test_throws_exception_for_percentage_above_maximum(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Percentage allocation value must be between 0.01 and 100');
|
||||
$this->expectExceptionMessage('Percentage allocation value must be between 1 and 10000');
|
||||
|
||||
$this->action->execute(
|
||||
$this->scenario,
|
||||
'Test Bucket',
|
||||
BucketAllocationTypeEnum::PERCENTAGE,
|
||||
allocationValue: 101
|
||||
allocationValue: 10001
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -391,7 +391,7 @@ public function test_buffer_multiplier_forced_to_zero_for_percentage_bucket(): v
|
|||
$this->scenario,
|
||||
'Percentage Bucket',
|
||||
BucketAllocationTypeEnum::PERCENTAGE,
|
||||
allocationValue: 25.0,
|
||||
allocationValue: 2500,
|
||||
bufferMultiplier: 1.0,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ public function test_effective_capacity_with_zero_buffer_equals_allocation_value
|
|||
'buffer_multiplier' => 0,
|
||||
]);
|
||||
|
||||
$this->assertEquals(50000.0, $bucket->getEffectiveCapacity());
|
||||
$this->assertEquals(50000, $bucket->getEffectiveCapacity());
|
||||
}
|
||||
|
||||
public function test_effective_capacity_with_full_buffer_doubles_capacity(): void
|
||||
|
|
@ -99,7 +99,7 @@ public function test_effective_capacity_with_full_buffer_doubles_capacity(): voi
|
|||
'buffer_multiplier' => 1.0,
|
||||
]);
|
||||
|
||||
$this->assertEquals(100000.0, $bucket->getEffectiveCapacity());
|
||||
$this->assertEquals(100000, $bucket->getEffectiveCapacity());
|
||||
}
|
||||
|
||||
public function test_effective_capacity_with_half_buffer(): void
|
||||
|
|
@ -110,18 +110,18 @@ public function test_effective_capacity_with_half_buffer(): void
|
|||
'buffer_multiplier' => 0.5,
|
||||
]);
|
||||
|
||||
$this->assertEquals(75000.0, $bucket->getEffectiveCapacity());
|
||||
$this->assertEquals(75000, $bucket->getEffectiveCapacity());
|
||||
}
|
||||
|
||||
public function test_effective_capacity_for_percentage_returns_php_float_max(): void
|
||||
{
|
||||
$scenario = Scenario::factory()->create();
|
||||
$bucket = Bucket::factory()->percentage(25)->create([
|
||||
$bucket = Bucket::factory()->percentage(2500)->create([
|
||||
'scenario_id' => $scenario->id,
|
||||
'buffer_multiplier' => 1.0,
|
||||
]);
|
||||
|
||||
$this->assertEquals(PHP_FLOAT_MAX, $bucket->getEffectiveCapacity());
|
||||
$this->assertEquals(PHP_INT_MAX, $bucket->getEffectiveCapacity());
|
||||
}
|
||||
|
||||
public function test_effective_capacity_for_unlimited_returns_php_float_max(): void
|
||||
|
|
@ -132,7 +132,7 @@ public function test_effective_capacity_for_unlimited_returns_php_float_max(): v
|
|||
'buffer_multiplier' => 1.0,
|
||||
]);
|
||||
|
||||
$this->assertEquals(PHP_FLOAT_MAX, $bucket->getEffectiveCapacity());
|
||||
$this->assertEquals(PHP_INT_MAX, $bucket->getEffectiveCapacity());
|
||||
}
|
||||
|
||||
public function test_has_available_space_uses_effective_capacity(): void
|
||||
|
|
@ -171,6 +171,6 @@ public function test_get_available_space_uses_effective_capacity(): void
|
|||
]);
|
||||
|
||||
// Effective capacity 100000 - balance 30000 = 70000 available
|
||||
$this->assertEquals(70000.0, $bucket->getAvailableSpace());
|
||||
$this->assertEquals(70000, $bucket->getAvailableSpace());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public function test_percentage_bucket_gets_percentage_of_remaining_amount()
|
|||
$percentageBucket = Bucket::factory()->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
|
||||
'allocation_value' => 20.00, // 20%
|
||||
'allocation_value' => 2000, // 20% in basis points
|
||||
'starting_amount' => 0,
|
||||
'priority' => 2,
|
||||
]);
|
||||
|
|
@ -183,7 +183,7 @@ public function test_handles_complex_mixed_bucket_scenario()
|
|||
$percentage1 = Bucket::factory()->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
|
||||
'allocation_value' => 15.00, // 15%
|
||||
'allocation_value' => 1500, // 15% in basis points
|
||||
'starting_amount' => 0,
|
||||
'priority' => 2,
|
||||
]);
|
||||
|
|
@ -197,7 +197,7 @@ public function test_handles_complex_mixed_bucket_scenario()
|
|||
$percentage2 = Bucket::factory()->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
|
||||
'allocation_value' => 25.00, // 25%
|
||||
'allocation_value' => 2500, // 25% in basis points
|
||||
'starting_amount' => 0,
|
||||
'priority' => 4,
|
||||
]);
|
||||
|
|
@ -326,7 +326,7 @@ public function test_percentage_allocation_with_insufficient_remaining_amount()
|
|||
$percentageBucket = Bucket::factory()->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
|
||||
'allocation_value' => 20.00, // 20%
|
||||
'allocation_value' => 2000, // 20% in basis points
|
||||
'starting_amount' => 0,
|
||||
'priority' => 2,
|
||||
]);
|
||||
|
|
@ -381,7 +381,7 @@ public function test_buffer_does_not_affect_percentage_allocation(): void
|
|||
Bucket::factory()->create([
|
||||
'scenario_id' => $this->scenario->id,
|
||||
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
|
||||
'allocation_value' => 25.00,
|
||||
'allocation_value' => 2500, // 25% in basis points
|
||||
'buffer_multiplier' => 1.0,
|
||||
'starting_amount' => 0,
|
||||
'priority' => 1,
|
||||
|
|
|
|||
Loading…
Reference in a new issue