// SPDX-License-Identifier: MIT
pragma solidity =0.8.20;

import {Test} from "forge-std/Test.sol";

import "../src/UniswapV2ERC20.sol";

import "./tokens/Permit.t.sol";
import "./tokens/Allowance.t.sol";
import "./tokens/Transfer.t.sol";

contract UniswapV2ERC20Mintable is UniswapV2ERC20 {
    function mint(address to, uint256 value) public {
        _mint(to, value);
    }
}

contract UniswapV2ERC20Test is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferTest {
    UniswapV2ERC20Mintable uni;

    address constant alice     = 0x0000000000000000000000000000000000000001;
    address constant bob       = 0x0000000000000000000000000000000000000002;
    uint256 constant amount    = 1e23;
    uint256 constant maxAmount = type(uint256).max;

    function setUp() public {
        uni = new UniswapV2ERC20Mintable();
        initializePermit(address(uni), amount, maxAmount);
        initializeAllowance(alice, bob, address(uni), amount, maxAmount, amount);
        initializeTransfer(alice, bob, address(uni), amount, 0);
    }

    function testNameIsCorrect() public view {
        assertEq(uni.name(), "Uniswap V2");
    }

    function testSymbolIsCorrect() public view {
        assertEq(uni.symbol(), "UNI-V2");
    }

    function testNumberOfDecimalslIsCorrect() public view {
        assertEq(uni.decimals(), 18);
    }

    function testInitialSupplyIsZero() public view {
        assertEq(uni.totalSupply(), 0);
    }

    function testDomainSeparatorIsCorrect() public view {
        assertEq(uni.DOMAIN_SEPARATOR(), keccak256(
            abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                keccak256(bytes(uni.name())),
                keccak256(bytes("1")),
                block.chainid,
                address(uni)
            )
        ));
    }

    function testPermitTypeHashIsCorrect() public view {
        assertEq(
            uni.PERMIT_TYPEHASH(),
            keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")
        );
    }

    function _mintTransferTokens(address who, uint256 value) internal override {
        uni.mint(who, value);
    }

    function _mintAllowanceTokens(address who, uint256 value) internal override {
        uni.mint(who, value);
    }

    function _mintPermitTokens(address who, uint256 value) internal override {
        uni.mint(who, value);
    }
}