Files
Gnuboard7/modules/_bundled/sirsoft-ecommerce/tests/Unit/Enums/ShippingPolicyEnumsTest.php
T
HeuJung 55bc9399e6 fix(ecommerce): 배송비 구간 경계 포함 + 무게/부피 단위 환산
구간별 배송비의 종료값이 구간에 포함되지 않아 경계값이 무료배송으로
새고, 상품 옵션의 g/cm³ 저장값을 정책의 kg/L 로 환산하지 않아 금액이
1000배로 청구되던 문제를 수정한다.

- 구간 매칭을 종료값 오름차순 사다리로 교체 — 시작값은 표시 전용이
 되어 기존 저장 데이터의 두 형태 모두에서 정확히 계산된다
- 단위 환산을 배송비 계산 한 지점으로 모으고, 부피무게와 실무게를
 같은 kg 단위로 비교하도록 교정
- 계산이 조용히 0원이 되는 설정(구간 미등록·단위값/기준금액 누락·
 중간 구간 무제한·계산 API 폴백 0원)을 저장 시점에 차단하고,
 런타임 잔여 경로에는 경고 로그를 남긴다
- 연속성 규칙을 정책 타입별로 분리해 소수 구간(2.5kg) 저장을 허용
- 상품 옵션 무게/부피 응답 왕복, 주문 총 무게/부피 실값 기록
2026-08-12 23:43:08 +09:00

255 lines
11 KiB
PHP

<?php
namespace Modules\Sirsoft\Ecommerce\Tests\Unit\Enums;
use Modules\Sirsoft\Ecommerce\Enums\ChargePolicyEnum;
use Modules\Sirsoft\Ecommerce\Enums\ShippingCountryEnum;
use Modules\Sirsoft\Ecommerce\Tests\ModuleTestCase;
/**
* 배송정책 관련 Enum 테스트
*/
class ShippingPolicyEnumsTest extends ModuleTestCase
{
// ========================================
// ChargePolicyEnum 테스트
// ========================================
public function test_charge_policy_has_correct_values(): void
{
$this->assertEquals('free', ChargePolicyEnum::FREE->value);
$this->assertEquals('fixed', ChargePolicyEnum::FIXED->value);
$this->assertEquals('conditional_free', ChargePolicyEnum::CONDITIONAL_FREE->value);
$this->assertEquals('range_amount', ChargePolicyEnum::RANGE_AMOUNT->value);
$this->assertEquals('range_quantity', ChargePolicyEnum::RANGE_QUANTITY->value);
$this->assertEquals('range_weight', ChargePolicyEnum::RANGE_WEIGHT->value);
$this->assertEquals('range_volume', ChargePolicyEnum::RANGE_VOLUME->value);
$this->assertEquals('range_volume_weight', ChargePolicyEnum::RANGE_VOLUME_WEIGHT->value);
$this->assertEquals('api', ChargePolicyEnum::API->value);
$this->assertEquals('per_quantity', ChargePolicyEnum::PER_QUANTITY->value);
$this->assertEquals('per_weight', ChargePolicyEnum::PER_WEIGHT->value);
$this->assertEquals('per_volume', ChargePolicyEnum::PER_VOLUME->value);
$this->assertEquals('per_volume_weight', ChargePolicyEnum::PER_VOLUME_WEIGHT->value);
$this->assertEquals('per_amount', ChargePolicyEnum::PER_AMOUNT->value);
}
public function test_charge_policy_values_returns_all_values(): void
{
$values = ChargePolicyEnum::values();
$this->assertIsArray($values);
$this->assertCount(14, $values);
$this->assertContains('free', $values);
$this->assertContains('fixed', $values);
$this->assertContains('conditional_free', $values);
$this->assertContains('range_amount', $values);
$this->assertContains('api', $values);
$this->assertContains('per_quantity', $values);
$this->assertContains('per_weight', $values);
$this->assertContains('per_volume', $values);
$this->assertContains('per_volume_weight', $values);
$this->assertContains('per_amount', $values);
}
public function test_charge_policy_to_select_options_returns_array(): void
{
$options = ChargePolicyEnum::toSelectOptions();
$this->assertIsArray($options);
$this->assertCount(14, $options);
foreach ($options as $option) {
$this->assertArrayHasKey('value', $option);
$this->assertArrayHasKey('label', $option);
}
}
public function test_charge_policy_requires_base_fee(): void
{
$this->assertTrue(ChargePolicyEnum::FIXED->requiresBaseFee());
$this->assertTrue(ChargePolicyEnum::CONDITIONAL_FREE->requiresBaseFee());
$this->assertTrue(ChargePolicyEnum::PER_QUANTITY->requiresBaseFee());
$this->assertTrue(ChargePolicyEnum::PER_WEIGHT->requiresBaseFee());
$this->assertTrue(ChargePolicyEnum::PER_VOLUME->requiresBaseFee());
$this->assertTrue(ChargePolicyEnum::PER_VOLUME_WEIGHT->requiresBaseFee());
$this->assertTrue(ChargePolicyEnum::PER_AMOUNT->requiresBaseFee());
// API 정책의 base_fee 는 외부 API 장애 시 폴백 배송비 — 0 이면 장애가 곧 무음 무료배송이 된다
$this->assertTrue(ChargePolicyEnum::API->requiresBaseFee());
$this->assertFalse(ChargePolicyEnum::FREE->requiresBaseFee());
$this->assertFalse(ChargePolicyEnum::RANGE_AMOUNT->requiresBaseFee());
}
public function test_charge_policy_has_discrete_range_values(): void
{
// 수량만 이산형 — "5개 다음은 6개"(max + 1)로 이어진다
$this->assertTrue(ChargePolicyEnum::RANGE_QUANTITY->hasDiscreteRangeValues());
// 금액·무게·부피는 연속값 — "5kg 다음은 5kg 초과"(다음 min = max)
$this->assertFalse(ChargePolicyEnum::RANGE_AMOUNT->hasDiscreteRangeValues());
$this->assertFalse(ChargePolicyEnum::RANGE_WEIGHT->hasDiscreteRangeValues());
$this->assertFalse(ChargePolicyEnum::RANGE_VOLUME->hasDiscreteRangeValues());
$this->assertFalse(ChargePolicyEnum::RANGE_VOLUME_WEIGHT->hasDiscreteRangeValues());
$this->assertFalse(ChargePolicyEnum::PER_QUANTITY->hasDiscreteRangeValues());
}
public function test_charge_policy_requires_free_threshold(): void
{
$this->assertTrue(ChargePolicyEnum::CONDITIONAL_FREE->requiresFreeThreshold());
$this->assertFalse(ChargePolicyEnum::FREE->requiresFreeThreshold());
$this->assertFalse(ChargePolicyEnum::FIXED->requiresFreeThreshold());
$this->assertFalse(ChargePolicyEnum::RANGE_AMOUNT->requiresFreeThreshold());
}
public function test_charge_policy_requires_ranges(): void
{
$this->assertTrue(ChargePolicyEnum::RANGE_AMOUNT->requiresRanges());
$this->assertTrue(ChargePolicyEnum::RANGE_QUANTITY->requiresRanges());
$this->assertTrue(ChargePolicyEnum::RANGE_WEIGHT->requiresRanges());
$this->assertTrue(ChargePolicyEnum::RANGE_VOLUME->requiresRanges());
$this->assertTrue(ChargePolicyEnum::RANGE_VOLUME_WEIGHT->requiresRanges());
$this->assertFalse(ChargePolicyEnum::FREE->requiresRanges());
$this->assertFalse(ChargePolicyEnum::FIXED->requiresRanges());
$this->assertFalse(ChargePolicyEnum::API->requiresRanges());
}
public function test_charge_policy_requires_api_endpoint(): void
{
$this->assertTrue(ChargePolicyEnum::API->requiresApiEndpoint());
$this->assertFalse(ChargePolicyEnum::FREE->requiresApiEndpoint());
$this->assertFalse(ChargePolicyEnum::FIXED->requiresApiEndpoint());
$this->assertFalse(ChargePolicyEnum::RANGE_AMOUNT->requiresApiEndpoint());
}
public function test_charge_policy_range_policies_returns_correct_list(): void
{
$rangePolicies = ChargePolicyEnum::rangePolicies();
$this->assertCount(5, $rangePolicies);
$this->assertContains(ChargePolicyEnum::RANGE_AMOUNT, $rangePolicies);
$this->assertContains(ChargePolicyEnum::RANGE_QUANTITY, $rangePolicies);
$this->assertContains(ChargePolicyEnum::RANGE_WEIGHT, $rangePolicies);
$this->assertContains(ChargePolicyEnum::RANGE_VOLUME, $rangePolicies);
$this->assertContains(ChargePolicyEnum::RANGE_VOLUME_WEIGHT, $rangePolicies);
}
public function test_charge_policy_requires_unit_value(): void
{
// 단위당 정책은 unit_value 필요
$this->assertTrue(ChargePolicyEnum::PER_QUANTITY->requiresUnitValue());
$this->assertTrue(ChargePolicyEnum::PER_WEIGHT->requiresUnitValue());
$this->assertTrue(ChargePolicyEnum::PER_VOLUME->requiresUnitValue());
$this->assertTrue(ChargePolicyEnum::PER_VOLUME_WEIGHT->requiresUnitValue());
$this->assertTrue(ChargePolicyEnum::PER_AMOUNT->requiresUnitValue());
// 비-단위당 정책은 unit_value 불필요
$this->assertFalse(ChargePolicyEnum::FREE->requiresUnitValue());
$this->assertFalse(ChargePolicyEnum::FIXED->requiresUnitValue());
$this->assertFalse(ChargePolicyEnum::CONDITIONAL_FREE->requiresUnitValue());
$this->assertFalse(ChargePolicyEnum::RANGE_AMOUNT->requiresUnitValue());
$this->assertFalse(ChargePolicyEnum::API->requiresUnitValue());
}
public function test_charge_policy_per_unit_policies_returns_correct_list(): void
{
$perUnitPolicies = ChargePolicyEnum::perUnitPolicies();
$this->assertCount(5, $perUnitPolicies);
$this->assertContains(ChargePolicyEnum::PER_QUANTITY, $perUnitPolicies);
$this->assertContains(ChargePolicyEnum::PER_WEIGHT, $perUnitPolicies);
$this->assertContains(ChargePolicyEnum::PER_VOLUME, $perUnitPolicies);
$this->assertContains(ChargePolicyEnum::PER_VOLUME_WEIGHT, $perUnitPolicies);
$this->assertContains(ChargePolicyEnum::PER_AMOUNT, $perUnitPolicies);
}
public function test_charge_policy_label_returns_string(): void
{
$label = ChargePolicyEnum::FREE->label();
$this->assertIsString($label);
$this->assertNotEmpty($label);
}
public function test_charge_policy_per_unit_label_returns_string(): void
{
foreach (ChargePolicyEnum::perUnitPolicies() as $policy) {
$label = $policy->label();
$this->assertIsString($label);
$this->assertNotEmpty($label, "{$policy->value}의 라벨이 비어있습니다");
}
}
// ========================================
// ShippingCountryEnum 테스트
// ========================================
public function test_shipping_country_has_correct_values(): void
{
$this->assertEquals('KR', ShippingCountryEnum::KR->value);
$this->assertEquals('US', ShippingCountryEnum::US->value);
$this->assertEquals('CN', ShippingCountryEnum::CN->value);
$this->assertEquals('JP', ShippingCountryEnum::JP->value);
}
public function test_shipping_country_values_returns_all_values(): void
{
$values = ShippingCountryEnum::values();
$this->assertIsArray($values);
$this->assertCount(4, $values);
$this->assertContains('KR', $values);
$this->assertContains('US', $values);
$this->assertContains('CN', $values);
$this->assertContains('JP', $values);
}
public function test_shipping_country_to_select_options_returns_array(): void
{
$options = ShippingCountryEnum::toSelectOptions();
$this->assertIsArray($options);
$this->assertCount(4, $options);
foreach ($options as $option) {
$this->assertArrayHasKey('value', $option);
$this->assertArrayHasKey('label', $option);
$this->assertArrayHasKey('flag', $option);
}
}
public function test_shipping_country_flag_returns_emoji(): void
{
$this->assertEquals("\u{1F1F0}\u{1F1F7}", ShippingCountryEnum::KR->flag());
$this->assertEquals("\u{1F1FA}\u{1F1F8}", ShippingCountryEnum::US->flag());
$this->assertEquals("\u{1F1E8}\u{1F1F3}", ShippingCountryEnum::CN->flag());
$this->assertEquals("\u{1F1EF}\u{1F1F5}", ShippingCountryEnum::JP->flag());
}
public function test_shipping_country_is_domestic(): void
{
$this->assertTrue(ShippingCountryEnum::KR->isDomestic());
$this->assertFalse(ShippingCountryEnum::US->isDomestic());
$this->assertFalse(ShippingCountryEnum::CN->isDomestic());
$this->assertFalse(ShippingCountryEnum::JP->isDomestic());
}
public function test_shipping_country_international_countries_returns_correct_list(): void
{
$internationalCountries = ShippingCountryEnum::internationalCountries();
$this->assertCount(3, $internationalCountries);
$this->assertContains(ShippingCountryEnum::US, $internationalCountries);
$this->assertContains(ShippingCountryEnum::CN, $internationalCountries);
$this->assertContains(ShippingCountryEnum::JP, $internationalCountries);
$this->assertNotContains(ShippingCountryEnum::KR, $internationalCountries);
}
public function test_shipping_country_label_returns_string(): void
{
$label = ShippingCountryEnum::KR->label();
$this->assertIsString($label);
$this->assertNotEmpty($label);
}
}