Files
kate522andClaude Opus 5 35bb96e82f refactor: rename the theme brand and every identifier from AKSRT to Jio
Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.

Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
  cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
  window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)

Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
  so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
  (dropped 3 stale entries, added the 17 missing ones)

Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
  get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
  when it is empty

Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.

Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-01 20:05:04 +08:00

116 lines
4.0 KiB
PHP

<?php
use Jio\Ledger\AssetType;
use Jio\Ledger\LedgerCommand;
use PHPUnit\Framework\TestCase;
final class LedgerCommandTest extends TestCase {
public function test_transfer_splits_principal_fee_and_net_receipt(): void {
$command = LedgerCommand::transfer(
'client-transfer:1:550e8400-e29b-41d4-a716-446655440000',
'transfer',
10,
20,
AssetType::BALANCE,
1000,
125
);
self::assertSame([-875, -125, 875], array_column($command->entries, 'delta_minor'));
self::assertSame(['transfer_out', 'fee', 'transfer_in'], array_column($command->entries, 'entry_type'));
self::assertSame(1000, $command->metadata['gross_minor']);
self::assertSame(125, $command->metadata['fee_minor']);
self::assertSame(875, $command->metadata['net_minor']);
self::assertSame(-125, array_sum(array_column($command->entries, 'delta_minor')));
}
public function test_transfer_rejects_net_below_one_minor_unit(): void {
$this->expectException(InvalidArgumentException::class);
LedgerCommand::transfer('transfer:key', 'transfer', 1, 2, AssetType::POINTS, 10, 10);
}
public function test_transfer_rejects_negative_fee_before_arithmetic(): void {
$this->expectException(InvalidArgumentException::class);
LedgerCommand::transfer('transfer:key', 'transfer', 1, 2, AssetType::POINTS, PHP_INT_MAX, -1);
}
public function test_validation_returns_400_for_bad_operation_key(): void {
$command = new LedgerCommand('bad key', 'credit', [[
'user_id' => 1,
'asset' => 'points',
'delta_minor' => 1,
'entry_type' => 'credit',
]]);
$error = $command->validate();
self::assertInstanceOf(WP_Error::class, $error);
self::assertSame('jio_ledger_operation_key', $error->get_error_code());
self::assertSame(400, $error->get_error_data()['status']);
}
public function test_payload_hash_is_stable_for_metadata_key_order(): void {
$entries = [['user_id' => 1, 'asset' => 'points', 'delta_minor' => 2, 'entry_type' => 'credit']];
$first = new LedgerCommand('stable:key', 'credit', $entries, '', '', 0, ['b' => 2, 'a' => 1]);
$second = new LedgerCommand('stable:key', 'credit', $entries, '', '', 0, ['a' => 1, 'b' => 2]);
self::assertSame($first->payload_hash(), $second->payload_hash());
}
public function test_payload_hash_changes_with_business_payload(): void {
$first = new LedgerCommand('stable:key', 'credit', [[
'user_id' => 1,
'asset' => 'points',
'delta_minor' => 2,
'entry_type' => 'credit',
]]);
$second = new LedgerCommand('stable:key', 'credit', [[
'user_id' => 1,
'asset' => 'points',
'delta_minor' => 3,
'entry_type' => 'credit',
]]);
self::assertNotSame($first->payload_hash(), $second->payload_hash());
}
public function test_validation_rejects_empty_entries_and_invalid_asset(): void {
$empty = new LedgerCommand('empty:key', 'credit', []);
self::assertSame('jio_ledger_entries', $empty->validate()->get_error_code());
$invalid = new LedgerCommand('asset:key', 'credit', [[
'user_id' => 1,
'asset' => 'cash',
'delta_minor' => 1,
'entry_type' => 'credit',
]]);
self::assertSame('jio_ledger_asset', $invalid->validate()->get_error_code());
}
public function test_validation_requires_integer_non_zero_entry_values(): void {
foreach (['1', 0, PHP_INT_MIN] as $delta) {
$command = new LedgerCommand('entry:key', 'credit', [[
'user_id' => 1,
'asset' => 'points',
'delta_minor' => $delta,
'entry_type' => 'credit',
]]);
self::assertSame('jio_ledger_entry', $command->validate()->get_error_code());
}
}
public function test_validation_rejects_negative_actor_and_invalid_entry_type(): void {
$actor = new LedgerCommand('actor:key', 'credit', [[
'user_id' => 1,
'asset' => 'points',
'delta_minor' => 1,
'entry_type' => 'credit',
]], '', '', -1);
self::assertSame('jio_ledger_actor', $actor->validate()->get_error_code());
$type = new LedgerCommand('type:key', 'credit', [[
'user_id' => 1,
'asset' => 'points',
'delta_minor' => 1,
'entry_type' => 'Bad Type',
]]);
self::assertSame('jio_ledger_entry', $type->validate()->get_error_code());
}
}