gcx/blockchain/genex-contracts/test/Coupon.t.sol

158 lines
4.9 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/Coupon.sol";
import "../src/interfaces/ICoupon.sol";
contract CouponTest is Test {
Coupon coupon;
address admin = address(1);
address factory = address(2);
address settler = address(3);
address user1 = address(4);
address user2 = address(5);
function setUp() public {
vm.startPrank(admin);
coupon = new Coupon();
coupon.initialize("Genex Coupon", "GXC", admin);
coupon.grantRole(keccak256("FACTORY_ROLE"), factory);
coupon.grantRole(keccak256("SETTLER_ROLE"), settler);
vm.stopPrank();
}
function test_MintSetsConfigCorrectly() public {
uint256 tokenId = _mintUtilityCoupon(user1, 100e6);
ICoupon.CouponConfig memory config = coupon.getConfig(tokenId);
assertEq(uint8(config.couponType), uint8(ICoupon.CouponType.Utility));
assertTrue(config.transferable);
assertEq(config.maxResaleCount, 3);
assertEq(coupon.ownerOf(tokenId), user1);
assertEq(coupon.getFaceValue(tokenId), 100e6);
}
function test_BurnByOwner() public {
uint256 tokenId = _mintUtilityCoupon(user1, 100e6);
vm.prank(user1);
coupon.burn(tokenId);
vm.expectRevert();
coupon.ownerOf(tokenId);
}
function test_BurnBySettler() public {
uint256 tokenId = _mintUtilityCoupon(user1, 100e6);
vm.prank(settler);
coupon.burn(tokenId);
}
function test_NonTransferableCouponReverts() public {
uint256 tokenId = _mintNonTransferableCoupon(user1, 50e6);
vm.prank(user1);
vm.expectRevert("Coupon: non-transferable");
coupon.safeTransferFrom(user1, user2, tokenId);
}
function test_TransferableTransferSucceeds() public {
uint256 tokenId = _mintUtilityCoupon(user1, 100e6);
vm.prank(user1);
coupon.safeTransferFrom(user1, user2, tokenId);
assertEq(coupon.ownerOf(tokenId), user2);
}
function test_MaxResaleCountEnforced() public {
uint256 tokenId = _mintUtilityCoupon(user1, 100e6);
// 使用 settler 增加到上限 (3)
vm.startPrank(settler);
coupon.incrementResaleCount(tokenId);
coupon.incrementResaleCount(tokenId);
coupon.incrementResaleCount(tokenId);
vm.stopPrank();
assertEq(coupon.getResaleCount(tokenId), 3);
// 转移应被拒绝
vm.prank(user1);
vm.expectRevert("Coupon: max resale count exceeded");
coupon.safeTransferFrom(user1, user2, tokenId);
}
function test_IncrementResaleCountOnlySettler() public {
uint256 tokenId = _mintUtilityCoupon(user1, 100e6);
vm.prank(user1);
vm.expectRevert();
coupon.incrementResaleCount(tokenId);
}
function test_BatchTransfer() public {
uint256[] memory tokenIds = new uint256[](3);
for (uint256 i = 0; i < 3; i++) {
tokenIds[i] = _mintUtilityCoupon(user1, 100e6);
}
vm.prank(user1);
coupon.batchTransfer(user1, user2, tokenIds);
for (uint256 i = 0; i < 3; i++) {
assertEq(coupon.ownerOf(tokenIds[i]), user2);
}
}
function test_ResaleCountInitiallyZero() public {
uint256 tokenId = _mintUtilityCoupon(user1, 100e6);
assertEq(coupon.getResaleCount(tokenId), 0);
}
function test_MintIncrementsTokenId() public {
uint256 id1 = _mintUtilityCoupon(user1, 100e6);
uint256 id2 = _mintUtilityCoupon(user1, 200e6);
assertEq(id2, id1 + 1);
}
// --- Helpers ---
function _mintUtilityCoupon(address to, uint256 faceValue) internal returns (uint256) {
bytes32[] memory stores = new bytes32[](0);
ICoupon.CouponConfig memory config = ICoupon.CouponConfig({
couponType: ICoupon.CouponType.Utility,
transferable: true,
maxResaleCount: 3,
maxPrice: faceValue,
expiryDate: block.timestamp + 180 days,
minPurchase: 0,
stackable: false,
allowedStores: stores,
issuer: admin,
faceValue: faceValue
});
vm.prank(factory);
return coupon.mint(to, faceValue, config);
}
function _mintNonTransferableCoupon(address to, uint256 faceValue) internal returns (uint256) {
bytes32[] memory stores = new bytes32[](0);
ICoupon.CouponConfig memory config = ICoupon.CouponConfig({
couponType: ICoupon.CouponType.Utility,
transferable: false,
maxResaleCount: 0,
maxPrice: faceValue,
expiryDate: block.timestamp + 180 days,
minPurchase: 0,
stackable: false,
allowedStores: stores,
issuer: admin,
faceValue: faceValue
});
vm.prank(factory);
return coupon.mint(to, faceValue, config);
}
}