|
1 | 1 | #[test_only] |
2 | 2 | module PaySplit::split_tests { |
3 | 3 | use 0x1::signer; |
4 | | - use 0x1::vector; |
5 | 4 | use PaySplit::split; |
6 | 5 |
|
7 | | - const A1: address = @0x1; |
8 | | - const A2: address = @0x2; |
9 | | - const A3: address = @0x3; |
| 6 | + // === 1) Точное распределение без остатка === |
| 7 | + // shares: 50/30/20; deposit: 100 -> A=50, B=30, C=20, fees=0 |
| 8 | + #[test(admin=@0xAA, a=@0xA, b=@0xB, c=@0xC)] |
| 9 | + public entry fun test_exact_split_ok( |
| 10 | + admin: &signer, a: &signer, b: &signer, c: &signer |
| 11 | + ) { |
| 12 | + let rcpts = vector[signer::address_of(a), signer::address_of(b), signer::address_of(c)]; |
| 13 | + let shares = vector[50, 30, 20]; |
| 14 | + split::init(admin, rcpts, shares); |
10 | 15 |
|
11 | | - // Happy path: 100 with shares [3,1] → 75/25 |
12 | | - #[test(admin = @0xA, payer = @0xB)] |
13 | | - public entry fun test_split_3_1(admin: &signer, payer: &signer) { |
14 | | - // recipients = [A1, A2] |
15 | | - let recips = vector::singleton<address>(A1); |
16 | | - let tail_r = vector::singleton<address>(A2); |
17 | | - vector::append(&mut recips, tail_r); |
18 | | - |
19 | | - // shares = [3, 1] |
20 | | - let shares = vector::singleton<u64>(3); |
21 | | - let tail_s = vector::singleton<u64>(1); |
22 | | - vector::append(&mut shares, tail_s); |
23 | | - |
24 | | - split::init(admin, recips, shares); |
25 | 16 | let admin_addr = signer::address_of(admin); |
| 17 | + split::deposit(admin, admin_addr, 100); |
26 | 18 |
|
27 | | - split::deposit(payer, admin_addr, 100); |
28 | | - |
29 | | - assert!(split::view_balance(admin_addr, A1) == 75, 0); |
30 | | - assert!(split::view_balance(admin_addr, A2) == 25, 1); |
| 19 | + assert!(split::view_balance(admin_addr, signer::address_of(a)) == 50, 0); |
| 20 | + assert!(split::view_balance(admin_addr, signer::address_of(b)) == 30, 1); |
| 21 | + assert!(split::view_balance(admin_addr, signer::address_of(c)) == 20, 2); |
31 | 22 | } |
32 | 23 |
|
33 | | - // Remainder path: [1,1,1] & 100 → each 33, remainder 1 → admin can withdraw fees |
34 | | - #[test(admin = @0xC, payer = @0xD, a1 = @0x1, a2 = @0x2, a3 = @0x3)] |
35 | | - public entry fun test_remainder_and_withdraw(admin: &signer, payer: &signer, a1: &signer, a2: &signer, a3: &signer) { |
36 | | - let addrs = vector::empty<address>(); |
37 | | - vector::push_back(&mut addrs, signer::address_of(a1)); |
38 | | - vector::push_back(&mut addrs, signer::address_of(a2)); |
39 | | - vector::push_back(&mut addrs, signer::address_of(a3)); |
40 | | - |
41 | | - let shares = vector::empty<u64>(); |
42 | | - vector::push_back(&mut shares, 1); |
43 | | - vector::push_back(&mut shares, 1); |
44 | | - vector::push_back(&mut shares, 1); |
| 24 | + // === 2) Остаток идёт в fees, затем админ забирает === |
| 25 | + // shares: 1/1; deposit: 1 -> parts=0/0, remainder=1 -> fees=1 -> withdraw_fees => admin=1 |
| 26 | + #[test(admin=@0xAB, a=@0xD, b=@0xE)] |
| 27 | + public entry fun test_remainder_goes_to_admin_ok( |
| 28 | + admin: &signer, a: &signer, b: &signer |
| 29 | + ) { |
| 30 | + let rcpts = vector[signer::address_of(a), signer::address_of(b)]; |
| 31 | + let shares = vector[1, 1]; |
| 32 | + split::init(admin, rcpts, shares); |
45 | 33 |
|
46 | | - split::init(admin, addrs, shares); |
47 | 34 | let admin_addr = signer::address_of(admin); |
| 35 | + split::deposit(admin, admin_addr, 1); // remainder = 1 |
| 36 | + split::withdraw_fees(admin, admin_addr); // move fees -> admin balance |
48 | 37 |
|
49 | | - split::deposit(payer, admin_addr, 100); |
50 | | - |
51 | | - assert!(split::view_balance(admin_addr, signer::address_of(a1)) == 33, 0); |
52 | | - assert!(split::view_balance(admin_addr, signer::address_of(a2)) == 33, 1); |
53 | | - assert!(split::view_balance(admin_addr, signer::address_of(a3)) == 33, 2); |
| 38 | + assert!(split::view_balance(admin_addr, admin_addr) == 1, 10); |
| 39 | + } |
54 | 40 |
|
55 | | - // fees = 1 → admin withdraws to own balance |
56 | | - split::withdraw_fees(admin, admin_addr); |
57 | | - assert!(split::view_balance(admin_addr, signer::address_of(admin)) == 1, 3); |
| 41 | + // === 3) Негатив: только админ может withdraw_fees (E_NOT_ADMIN = 4) === |
| 42 | + #[test(admin=@0xAC, bad=@0xEF, a=@0x1, b=@0x2)] |
| 43 | + #[expected_failure(abort_code = 4, location = PaySplit::split)] |
| 44 | + public entry fun test_withdraw_fees_only_admin_fails( |
| 45 | + admin: &signer, bad: &signer, a: &signer, b: &signer |
| 46 | + ) { |
| 47 | + let rcpts = vector[signer::address_of(a), signer::address_of(b)]; |
| 48 | + let shares = vector[1, 1]; |
| 49 | + split::init(admin, rcpts, shares); |
58 | 50 |
|
59 | | - // recipient withdraw example (a2) |
60 | | - split::withdraw(a2, admin_addr); |
61 | | - assert!(split::view_balance(admin_addr, signer::address_of(a2)) == 0, 4); |
| 51 | + let admin_addr = signer::address_of(admin); |
| 52 | + // не-админ вызывает — должно упасть с кодом 4 |
| 53 | + split::withdraw_fees(bad, admin_addr); |
62 | 54 | } |
63 | 55 | } |
0 commit comments