Open peterduhon opened 1 month ago
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Skia Poker Unit Tests", function() {
let bettingAndPotManagement, cardManagement, roomManagement, userManagement, aiPlayerManagement;
let owner, player1, player2, houseAccount;
const minimumBet = ethers.utils.parseEther("0.1");
beforeEach(async function() {
[owner, player1, player2, houseAccount] = await ethers.getSigners();
const CardManagement = await ethers.getContractFactory("CardManagement");
cardManagement = await CardManagement.deploy();
const RoomManagement = await ethers.getContractFactory("RoomManagement");
roomManagement = await RoomManagement.deploy();
const UserManagement = await ethers.getContractFactory("UserManagement");
userManagement = await UserManagement.deploy();
const AIPlayerManagement = await ethers.getContractFactory("AIPlayerManagement");
aiPlayerManagement = await AIPlayerManagement.deploy();
const BettingAndPotManagement = await ethers.getContractFactory("BettingAndPotManagement");
bettingAndPotManagement = await BettingAndPotManagement.deploy(
0, // roomId
houseAccount.address,
cardManagement.address,
roomManagement.address,
userManagement.address,
aiPlayerManagement.address,
minimumBet,
ethers.constants.AddressZero, // VRF Coordinator (mock for testing)
ethers.constants.AddressZero, // LINK token (mock for testing)
ethers.utils.formatBytes32String(""), // keyHash (mock for testing)
ethers.utils.parseEther("0.1") // fee (mock for testing)
);
});
describe("Game Initialization", function() {
it("should initialize game state correctly", async function() {
expect(await bettingAndPotManagement.gameState()).to.equal(0); // WaitingForPlayers
});
it("should set minimum bet correctly", async function() {
expect(await bettingAndPotManagement.minimumBet()).to.equal(minimumBet);
});
});
describe("Player Management", function() {
it("should allow players to join the game", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
const player = await bettingAndPotManagement.players(player1.address);
expect(player.addr).to.equal(player1.address);
expect(player.balance).to.equal(minimumBet);
});
it("should not allow players to join with insufficient funds", async function() {
await expect(
bettingAndPotManagement.connect(player1).joinGame({ value: ethers.utils.parseEther("0.05") })
).to.be.revertedWith("Insufficient chips sent to join the game");
});
});
describe("Game Actions", function() {
beforeEach(async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
});
it("should allow players to bet", async function() {
await bettingAndPotManagement.connect(player1).playerAction(4, minimumBet); // PlayerAction.Bet
const player = await bettingAndPotManagement.players(player1.address);
expect(player.currentBet).to.equal(minimumBet);
});
it("should not allow players to bet less than the minimum", async function() {
await expect(
bettingAndPotManagement.connect(player1).playerAction(4, ethers.utils.parseEther("0.05"))
).to.be.revertedWith("Bet amount below minimum");
});
});
// Add more unit tests as needed
});
cc: @JW-dev0505 I've adapted for our contracts but please review and update per our needs. Thank you!
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Skia Poker Integration Tests", function() {
let bettingAndPotManagement, cardManagement, roomManagement, userManagement, aiPlayerManagement;
let owner, player1, player2, houseAccount;
const minimumBet = ethers.utils.parseEther("0.1");
const roomId = 0;
beforeEach(async function() {
[owner, player1, player2, houseAccount] = await ethers.getSigners();
const CardManagement = await ethers.getContractFactory("CardManagement");
cardManagement = await CardManagement.deploy();
const RoomManagement = await ethers.getContractFactory("RoomManagement");
roomManagement = await RoomManagement.deploy();
const UserManagement = await ethers.getContractFactory("UserManagement");
userManagement = await UserManagement.deploy();
const AIPlayerManagement = await ethers.getContractFactory("AIPlayerManagement");
aiPlayerManagement = await AIPlayerManagement.deploy();
const BettingAndPotManagement = await ethers.getContractFactory("BettingAndPotManagement");
bettingAndPotManagement = await BettingAndPotManagement.deploy(
roomId,
houseAccount.address,
cardManagement.address,
roomManagement.address,
userManagement.address,
aiPlayerManagement.address,
minimumBet,
ethers.constants.AddressZero, // VRF Coordinator (mock for testing)
ethers.constants.AddressZero, // LINK token (mock for testing)
ethers.utils.formatBytes32String(""), // keyHash (mock for testing)
ethers.utils.parseEther("0.1") // fee (mock for testing)
);
// Set up the room in RoomManagement
await roomManagement.createGameRoom("Test Room", minimumBet, 10);
});
it("should allow players to join a game room and start the game", async function() {
await userManagement.connect(player1).registerUser("Player1");
await userManagement.connect(player2).registerUser("Player2");
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
expect(await bettingAndPotManagement.gameState()).to.equal(1); // PreFlop
});
it("should handle a full round of betting", async function() {
await userManagement.connect(player1).registerUser("Player1");
await userManagement.connect(player2).registerUser("Player2");
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
// Player 1 bets
await bettingAndPotManagement.connect(player1).playerAction(4, minimumBet); // PlayerAction.Bet
// Player 2 calls
await bettingAndPotManagement.connect(player2).playerAction(3, minimumBet); // PlayerAction.Call
// Check that the bets were placed correctly
const player1Data = await bettingAndPotManagement.players(player1.address);
const player2Data = await bettingAndPotManagement.players(player2.address);
expect(player1Data.currentBet).to.equal(minimumBet);
expect(player2Data.currentBet).to.equal(minimumBet);
});
// Add more integration tests as needed
});
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Skia Poker State Transition Tests", function() {
let bettingAndPotManagement, cardManagement, roomManagement, userManagement, aiPlayerManagement;
let owner, player1, player2, houseAccount;
const minimumBet = ethers.utils.parseEther("0.1");
const roomId = 0;
beforeEach(async function() {
[owner, player1, player2, houseAccount] = await ethers.getSigners();
const CardManagement = await ethers.getContractFactory("CardManagement");
cardManagement = await CardManagement.deploy();
const RoomManagement = await ethers.getContractFactory("RoomManagement");
roomManagement = await RoomManagement.deploy();
const UserManagement = await ethers.getContractFactory("UserManagement");
userManagement = await UserManagement.deploy();
const AIPlayerManagement = await ethers.getContractFactory("AIPlayerManagement");
aiPlayerManagement = await AIPlayerManagement.deploy();
const BettingAndPotManagement = await ethers.getContractFactory("BettingAndPotManagement");
bettingAndPotManagement = await BettingAndPotManagement.deploy(
roomId,
houseAccount.address,
cardManagement.address,
roomManagement.address,
userManagement.address,
aiPlayerManagement.address,
minimumBet,
ethers.constants.AddressZero, // VRF Coordinator (mock for testing)
ethers.constants.AddressZero, // LINK token (mock for testing)
ethers.utils.formatBytes32String(""), // keyHash (mock for testing)
ethers.utils.parseEther("0.1") // fee (mock for testing)
);
// Set up the room in RoomManagement
await roomManagement.createGameRoom("Test Room", minimumBet, 10);
// Register players
await userManagement.connect(player1).registerUser("Player1");
await userManagement.connect(player2).registerUser("Player2");
// Players join the game
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
});
it("should transition from WaitingForPlayers to PreFlop when game starts", async function() {
expect(await bettingAndPotManagement.gameState()).to.equal(0); // WaitingForPlayers
await bettingAndPotManagement.connect(owner).startGame();
expect(await bettingAndPotManagement.gameState()).to.equal(1); // PreFlop
});
it("should transition through all betting rounds", async function() {
await bettingAndPotManagement.connect(owner).startGame();
expect(await bettingAndPotManagement.gameState()).to.equal(1); // PreFlop
// Simulate PreFlop actions
await bettingAndPotManagement.connect(player1).playerAction(4, minimumBet); // Bet
await bettingAndPotManagement.connect(player2).playerAction(3, minimumBet); // Call
// Move to Flop
await bettingAndPotManagement.connect(owner).nextGameState();
expect(await bettingAndPotManagement.gameState()).to.equal(2); // Flop
// Simulate Flop actions
await bettingAndPotManagement.connect(player1).playerAction(2, 0); // Check
await bettingAndPotManagement.connect(player2).playerAction(2, 0); // Check
// Move to Turn
await bettingAndPotManagement.connect(owner).nextGameState();
expect(await bettingAndPotManagement.gameState()).to.equal(3); // Turn
// Simulate Turn actions
await bettingAndPotManagement.connect(player1).playerAction(4, minimumBet); // Bet
await bettingAndPotManagement.connect(player2).playerAction(3, minimumBet); // Call
// Move to River
await bettingAndPotManagement.connect(owner).nextGameState();
expect(await bettingAndPotManagement.gameState()).to.equal(4); // River
// Simulate River actions
await bettingAndPotManagement.connect(player1).playerAction(2, 0); // Check
await bettingAndPotManagement.connect(player2).playerAction(2, 0); // Check
// Move to Showdown
await bettingAndPotManagement.connect(owner).nextGameState();
expect(await bettingAndPotManagement.gameState()).to.equal(5); // Showdown
});
// Add more state transition tests as needed
});
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Skia Poker Edge Case Tests", function() {
let bettingAndPotManagement, cardManagement, roomManagement, userManagement, aiPlayerManagement;
let owner, player1, player2, player3, houseAccount;
const minimumBet = ethers.utils.parseEther("0.1");
const roomId = 0;
beforeEach(async function() {
[owner, player1, player2, player3, houseAccount] = await ethers.getSigners();
const CardManagement = await ethers.getContractFactory("CardManagement");
cardManagement = await CardManagement.deploy();
const RoomManagement = await ethers.getContractFactory("RoomManagement");
roomManagement = await RoomManagement.deploy();
const UserManagement = await ethers.getContractFactory("UserManagement");
userManagement = await UserManagement.deploy();
const AIPlayerManagement = await ethers.getContractFactory("AIPlayerManagement");
aiPlayerManagement = await AIPlayerManagement.deploy();
const BettingAndPotManagement = await ethers.getContractFactory("BettingAndPotManagement");
bettingAndPotManagement = await BettingAndPotManagement.deploy(
roomId,
houseAccount.address,
cardManagement.address,
roomManagement.address,
userManagement.address,
aiPlayerManagement.address,
minimumBet,
ethers.constants.AddressZero,
ethers.constants.AddressZero,
ethers.utils.formatBytes32String(""),
ethers.utils.parseEther("0.1")
);
// Set up the room in RoomManagement
await roomManagement.createGameRoom("Test Room", minimumBet, 10);
// Register players
await userManagement.connect(player1).registerUser("Player1");
await userManagement.connect(player2).registerUser("Player2");
await userManagement.connect(player3).registerUser("Player3");
});
it("should handle minimum player count (2 players)", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
expect(await bettingAndPotManagement.gameState()).to.equal(1); // PreFlop
});
it("should handle maximum player count (10 players)", async function() {
const players = await ethers.getSigners();
for (let i = 0; i < 10; i++) {
await userManagement.connect(players[i]).registerUser(`Player${i}`);
await bettingAndPotManagement.connect(players[i]).joinGame({ value: minimumBet });
}
await bettingAndPotManagement.connect(owner).startGame();
expect(await bettingAndPotManagement.gameState()).to.equal(1); // PreFlop
});
it("should reject joining when room is full", async function() {
// Fill the room to capacity
const players = await ethers.getSigners();
for (let i = 0; i < 10; i++) {
await userManagement.connect(players[i]).registerUser(`Player${i}`);
await bettingAndPotManagement.connect(players[i]).joinGame({ value: minimumBet });
}
// Try to join with an 11th player
await expect(
bettingAndPotManagement.connect(players[10]).joinGame({ value: minimumBet })
).to.be.revertedWith("Not enough players to start the game");
});
it("should handle all players folding except one", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player3).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
await bettingAndPotManagement.connect(player1).playerAction(1, 0); // Fold
await bettingAndPotManagement.connect(player2).playerAction(1, 0); // Fold
// The game should end with player3 as the winner
expect(await bettingAndPotManagement.gameState()).to.equal(5); // Showdown
// You might need to implement a getWinner function to check the winner
});
it("should handle a player going all-in", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
await bettingAndPotManagement.connect(player1).playerAction(6, minimumBet); // All-in
const player1Data = await bettingAndPotManagement.players(player1.address);
expect(player1Data.balance).to.equal(0);
expect(player1Data.currentBet).to.equal(minimumBet);
});
});
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Skia Poker Security Tests", function() {
let bettingAndPotManagement, cardManagement, roomManagement, userManagement, aiPlayerManagement;
let owner, player1, player2, attacker, houseAccount;
const minimumBet = ethers.utils.parseEther("0.1");
const roomId = 0;
beforeEach(async function() {
[owner, player1, player2, attacker, houseAccount] = await ethers.getSigners();
const CardManagement = await ethers.getContractFactory("CardManagement");
cardManagement = await CardManagement.deploy();
const RoomManagement = await ethers.getContractFactory("RoomManagement");
roomManagement = await RoomManagement.deploy();
const UserManagement = await ethers.getContractFactory("UserManagement");
userManagement = await UserManagement.deploy();
const AIPlayerManagement = await ethers.getContractFactory("AIPlayerManagement");
aiPlayerManagement = await AIPlayerManagement.deploy();
const BettingAndPotManagement = await ethers.getContractFactory("BettingAndPotManagement");
bettingAndPotManagement = await BettingAndPotManagement.deploy(
roomId,
houseAccount.address,
cardManagement.address,
roomManagement.address,
userManagement.address,
aiPlayerManagement.address,
minimumBet,
ethers.constants.AddressZero,
ethers.constants.AddressZero,
ethers.utils.formatBytes32String(""),
ethers.utils.parseEther("0.1")
);
// Set up the room in RoomManagement
await roomManagement.createGameRoom("Test Room", minimumBet, 10);
// Register players
await userManagement.connect(player1).registerUser("Player1");
await userManagement.connect(player2).registerUser("Player2");
});
it("should prevent unauthorized access to owner functions", async function() {
await expect(
bettingAndPotManagement.connect(attacker).startGame()
).to.be.revertedWith("Ownable: caller is not the owner");
});
it("should prevent players from betting more than their balance", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
await expect(
bettingAndPotManagement.connect(player1).playerAction(4, minimumBet.mul(2)) // Bet double the minimum
).to.be.revertedWith("Poker Game: Insufficient balance to bet.");
});
it("should ensure that only the current player can make a move", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
// Assuming player1 is the first to act
await expect(
bettingAndPotManagement.connect(player2).playerAction(4, minimumBet)
).to.be.revertedWith("It's not your turn");
});
it("should prevent players from joining a game in progress", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
await expect(
bettingAndPotManagement.connect(attacker).joinGame({ value: minimumBet })
).to.be.revertedWith("Game is not accepting new players");
});
it("should prevent unauthorized withdrawal from house account", async function() {
await bettingAndPotManagement.connect(owner).addFundsToHouse({ value: ethers.utils.parseEther("1") });
await expect(
bettingAndPotManagement.connect(attacker).withdrawFromHouse(attacker.address, ethers.utils.parseEther("0.5"))
).to.be.revertedWith("Not authorized");
});
// Add more security tests as needed
});
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Skia Poker Gas Optimization Tests", function() {
let bettingAndPotManagement, cardManagement, roomManagement, userManagement, aiPlayerManagement;
let owner, player1, player2, houseAccount;
const minimumBet = ethers.utils.parseEther("0.1");
const roomId = 0;
beforeEach(async function() {
[owner, player1, player2, houseAccount] = await ethers.getSigners();
const CardManagement = await ethers.getContractFactory("CardManagement");
cardManagement = await CardManagement.deploy();
const RoomManagement = await ethers.getContractFactory("RoomManagement");
roomManagement = await RoomManagement.deploy();
const UserManagement = await ethers.getContractFactory("UserManagement");
userManagement = await UserManagement.deploy();
const AIPlayerManagement = await ethers.getContractFactory("AIPlayerManagement");
aiPlayerManagement = await AIPlayerManagement.deploy();
const BettingAndPotManagement = await ethers.getContractFactory("BettingAndPotManagement");
bettingAndPotManagement = await BettingAndPotManagement.deploy(
roomId,
houseAccount.address,
cardManagement.address,
roomManagement.address,
userManagement.address,
aiPlayerManagement.address,
minimumBet,
ethers.constants.AddressZero,
ethers.constants.AddressZero,
ethers.utils.formatBytes32String(""),
ethers.utils.parseEther("0.1")
);
// Set up the room in RoomManagement
await roomManagement.createGameRoom("Test Room", minimumBet, 10);
// Register players
await userManagement.connect(player1).registerUser("Player1");
await userManagement.connect(player2).registerUser("Player2");
});
async function measureGas(transaction) {
const tx = await transaction;
const receipt = await tx.wait();
return receipt.gasUsed;
}
it("should optimize gas usage for joining a game", async function() {
const gasUsed = await measureGas(
bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet })
);
console.log(`Gas used for joining a game: ${gasUsed.toString()}`);
expect(gasUsed).to.be.below(200000); // Adjust this threshold based on your requirements
});
it("should optimize gas usage for starting a game", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
const gasUsed = await measureGas(
bettingAndPotManagement.connect(owner).startGame()
);
console.log(`Gas used for starting a game: ${gasUsed.toString()}`);
expect(gasUsed).to.be.below(300000); // Adjust this threshold based on your requirements
});
it("should optimize gas usage for making a bet", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
const gasUsed = await measureGas(
bettingAndPotManagement.connect(player1).playerAction(4, minimumBet) // Bet
);
console.log(`Gas used for making a bet: ${gasUsed.toString()}`);
expect(gasUsed).to.be.below(100000); // Adjust this threshold based on your requirements
});
it("should optimize gas usage for transitioning game states", async function() {
await bettingAndPotManagement.connect(player1).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(player2).joinGame({ value: minimumBet });
await bettingAndPotManagement.connect(owner).startGame();
// Simulate some actions to move to the next state
await bettingAndPotManagement.connect(player1).playerAction(4, minimumBet); // Bet
await bettingAndPotManagement.connect(player2).playerAction(3, minimumBet); // Call
const gasUsed = await measureGas(
bettingAndPotManagement.connect(owner).nextGameState()
);
console.log(`Gas use
[SP-21] Testing Skia Poker Smart Contracts
Summary:
Perform comprehensive testing on the Skia Poker smart contracts to ensure functionality, interactions, and security across all six contracts. The testing plan includes unit, integration, state transition, edge case, security, and gas optimization testing.
Description:
This task focuses on setting up a testing environment for the Skia Poker smart contracts, writing test scripts for critical functions, and performing both unit and integration tests. Additionally, edge case testing, gas optimization, and security reviews will be conducted to ensure robust contract functionality.
The goal is to ensure that all contracts perform as expected, with no security vulnerabilities, and are optimized for gas efficiency.
Acceptance Criteria:
Tasks:
Unit Testing:
Integration Testing:
State Transition Testing:
Edge Case Testing:
Security Testing:
Gas Optimization:
Timeline:
Dependencies:
Priority: High
Assignee: James/@coolman Due Date: Sept 7, 2024, 11:00 AM UTC
Risks and Mitigations:
Testing Guide
For detailed instructions on running and interpreting our test suites, please refer to the Skia Testing Guide in the resources folder.