mirror of
https://github.com/arkorty/B.Tech-Project-III.git
synced 2026-04-19 12:41:48 +00:00
init
This commit is contained in:
243
dmtp/server/test/TaskEscrow.test.js
Normal file
243
dmtp/server/test/TaskEscrow.test.js
Normal file
@@ -0,0 +1,243 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const hardhat_network_helpers_1 = require("@nomicfoundation/hardhat-network-helpers");
|
||||
const chai_1 = require("chai");
|
||||
const hardhat_1 = require("hardhat");
|
||||
describe("TaskEscrow", function () {
|
||||
let taskEscrow;
|
||||
let cUSDMock;
|
||||
let owner;
|
||||
let requester;
|
||||
let worker;
|
||||
const PAYMENT_AMOUNT = hardhat_1.ethers.parseEther("10"); // 10 cUSD
|
||||
const DURATION_DAYS = 7;
|
||||
beforeEach(async function () {
|
||||
[owner, requester, worker] = await hardhat_1.ethers.getSigners();
|
||||
// Deploy mock cUSD token
|
||||
const MockERC20 = await hardhat_1.ethers.getContractFactory("MockERC20");
|
||||
cUSDMock = await MockERC20.deploy("Celo Dollar", "cUSD");
|
||||
await cUSDMock.waitForDeployment();
|
||||
// Deploy TaskEscrow
|
||||
const TaskEscrow = await hardhat_1.ethers.getContractFactory("TaskEscrow");
|
||||
taskEscrow = await TaskEscrow.deploy(await cUSDMock.getAddress());
|
||||
await taskEscrow.waitForDeployment();
|
||||
// Mint cUSD to requester
|
||||
await cUSDMock.mint(requester.address, hardhat_1.ethers.parseEther("1000"));
|
||||
});
|
||||
describe("Deployment", function () {
|
||||
it("Should set the correct owner", async function () {
|
||||
(0, chai_1.expect)(await taskEscrow.owner()).to.equal(owner.address);
|
||||
});
|
||||
it("Should set the correct cUSD address", async function () {
|
||||
(0, chai_1.expect)(await taskEscrow.cUSD()).to.equal(await cUSDMock.getAddress());
|
||||
});
|
||||
it("Should initialize with zero platform fees", async function () {
|
||||
(0, chai_1.expect)(await taskEscrow.platformFeesAccumulated()).to.equal(0);
|
||||
});
|
||||
});
|
||||
describe("Create Task", function () {
|
||||
it("Should create a task successfully", async function () {
|
||||
// Approve and create task
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).createTask(PAYMENT_AMOUNT, DURATION_DAYS))
|
||||
.to.emit(taskEscrow, "TaskCreated")
|
||||
.withArgs(1, requester.address, PAYMENT_AMOUNT, (await hardhat_network_helpers_1.time.latest()) + DURATION_DAYS * 24 * 60 * 60);
|
||||
const task = await taskEscrow.getTask(1);
|
||||
(0, chai_1.expect)(task.requester).to.equal(requester.address);
|
||||
(0, chai_1.expect)(task.paymentAmount).to.equal(PAYMENT_AMOUNT);
|
||||
(0, chai_1.expect)(task.status).to.equal(0); // Open
|
||||
});
|
||||
it("Should fail with zero payment amount", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).createTask(0, DURATION_DAYS)).to.be.revertedWith("Payment must be > 0");
|
||||
});
|
||||
it("Should fail with invalid duration", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).createTask(PAYMENT_AMOUNT, 0)).to.be.revertedWith("Invalid duration");
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).createTask(PAYMENT_AMOUNT, 91)).to.be.revertedWith("Invalid duration");
|
||||
});
|
||||
it("Should transfer cUSD to contract", async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
(0, chai_1.expect)(await cUSDMock.balanceOf(await taskEscrow.getAddress())).to.equal(PAYMENT_AMOUNT);
|
||||
});
|
||||
});
|
||||
describe("Assign Worker", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
});
|
||||
it("Should assign worker successfully", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).assignWorker(1, worker.address))
|
||||
.to.emit(taskEscrow, "WorkerAssigned")
|
||||
.withArgs(1, worker.address);
|
||||
const task = await taskEscrow.getTask(1);
|
||||
(0, chai_1.expect)(task.worker).to.equal(worker.address);
|
||||
(0, chai_1.expect)(task.status).to.equal(1); // InProgress
|
||||
});
|
||||
it("Should fail if not requester", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(worker).assignWorker(1, worker.address)).to.be.revertedWith("Not task requester");
|
||||
});
|
||||
it("Should fail with invalid worker address", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).assignWorker(1, hardhat_1.ethers.ZeroAddress)).to.be.revertedWith("Invalid worker address");
|
||||
});
|
||||
it("Should fail if requester tries to be worker", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).assignWorker(1, requester.address)).to.be.revertedWith("Requester cannot be worker");
|
||||
});
|
||||
});
|
||||
describe("Approve Submission", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
await taskEscrow.connect(requester).assignWorker(1, worker.address);
|
||||
});
|
||||
it("Should approve and release payment", async function () {
|
||||
const workerBalanceBefore = await cUSDMock.balanceOf(worker.address);
|
||||
await taskEscrow.connect(owner).approveSubmission(1);
|
||||
const workerBalanceAfter = await cUSDMock.balanceOf(worker.address);
|
||||
const expectedWorkerPayment = (PAYMENT_AMOUNT * 9500n) / 10000n; // 95%
|
||||
(0, chai_1.expect)(workerBalanceAfter - workerBalanceBefore).to.equal(expectedWorkerPayment);
|
||||
const task = await taskEscrow.getTask(1);
|
||||
(0, chai_1.expect)(task.status).to.equal(2); // Completed
|
||||
});
|
||||
it("Should accumulate platform fees", async function () {
|
||||
await taskEscrow.connect(owner).approveSubmission(1);
|
||||
const expectedFee = (PAYMENT_AMOUNT * 500n) / 10000n; // 5%
|
||||
(0, chai_1.expect)(await taskEscrow.platformFeesAccumulated()).to.equal(expectedFee);
|
||||
});
|
||||
it("Should fail if not owner", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).approveSubmission(1))
|
||||
.to.be.revertedWithCustomError(taskEscrow, "OwnableUnauthorizedAccount")
|
||||
.withArgs(requester.address);
|
||||
});
|
||||
it("Should fail if task not in progress", async function () {
|
||||
await taskEscrow.connect(owner).approveSubmission(1);
|
||||
await (0, chai_1.expect)(taskEscrow.connect(owner).approveSubmission(1)).to.be.revertedWith("Task not in progress");
|
||||
});
|
||||
});
|
||||
describe("Reject Submission", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
await taskEscrow.connect(requester).assignWorker(1, worker.address);
|
||||
});
|
||||
it("Should reject and refund requester", async function () {
|
||||
const requesterBalanceBefore = await cUSDMock.balanceOf(requester.address);
|
||||
await taskEscrow.connect(owner).rejectSubmission(1);
|
||||
const requesterBalanceAfter = await cUSDMock.balanceOf(requester.address);
|
||||
(0, chai_1.expect)(requesterBalanceAfter - requesterBalanceBefore).to.equal(PAYMENT_AMOUNT);
|
||||
const task = await taskEscrow.getTask(1);
|
||||
(0, chai_1.expect)(task.status).to.equal(3); // Cancelled
|
||||
});
|
||||
it("Should fail if not owner", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).rejectSubmission(1)).to.be.revertedWithCustomError(taskEscrow, "OwnableUnauthorizedAccount")
|
||||
.withArgs(requester.address);
|
||||
});
|
||||
});
|
||||
describe("Cancel Task", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
});
|
||||
it("Should allow requester to cancel open task", async function () {
|
||||
const requesterBalanceBefore = await cUSDMock.balanceOf(requester.address);
|
||||
await taskEscrow.connect(requester).cancelTask(1);
|
||||
const requesterBalanceAfter = await cUSDMock.balanceOf(requester.address);
|
||||
(0, chai_1.expect)(requesterBalanceAfter - requesterBalanceBefore).to.equal(PAYMENT_AMOUNT);
|
||||
const task = await taskEscrow.getTask(1);
|
||||
(0, chai_1.expect)(task.status).to.equal(3); // Cancelled
|
||||
});
|
||||
it("Should fail if not requester", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(worker).cancelTask(1)).to.be.revertedWith("Not task requester");
|
||||
});
|
||||
});
|
||||
describe("Expired Task", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
});
|
||||
it("Should allow claiming expired task", async function () {
|
||||
// Fast forward time
|
||||
await hardhat_network_helpers_1.time.increase(DURATION_DAYS * 24 * 60 * 60 + 1);
|
||||
const requesterBalanceBefore = await cUSDMock.balanceOf(requester.address);
|
||||
await taskEscrow.connect(requester).claimExpiredTask(1);
|
||||
const requesterBalanceAfter = await cUSDMock.balanceOf(requester.address);
|
||||
(0, chai_1.expect)(requesterBalanceAfter - requesterBalanceBefore).to.equal(PAYMENT_AMOUNT);
|
||||
const task = await taskEscrow.getTask(1);
|
||||
(0, chai_1.expect)(task.status).to.equal(4); // Expired
|
||||
});
|
||||
it("Should fail if task not expired", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).claimExpiredTask(1)).to.be.revertedWith("Task not expired yet");
|
||||
});
|
||||
});
|
||||
describe("Withdraw Platform Fees", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
await taskEscrow.connect(requester).assignWorker(1, worker.address);
|
||||
await taskEscrow.connect(owner).approveSubmission(1);
|
||||
});
|
||||
it("Should allow owner to withdraw fees", async function () {
|
||||
const ownerBalanceBefore = await cUSDMock.balanceOf(owner.address);
|
||||
const expectedFee = (PAYMENT_AMOUNT * 500n) / 10000n;
|
||||
await taskEscrow.connect(owner).withdrawPlatformFees();
|
||||
const ownerBalanceAfter = await cUSDMock.balanceOf(owner.address);
|
||||
(0, chai_1.expect)(ownerBalanceAfter - ownerBalanceBefore).to.equal(expectedFee);
|
||||
(0, chai_1.expect)(await taskEscrow.platformFeesAccumulated()).to.equal(0);
|
||||
});
|
||||
it("Should fail if no fees to withdraw", async function () {
|
||||
await taskEscrow.connect(owner).withdrawPlatformFees();
|
||||
await (0, chai_1.expect)(taskEscrow.connect(owner).withdrawPlatformFees()).to.be.revertedWith("No fees to withdraw");
|
||||
});
|
||||
it("Should fail if not owner", async function () {
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).withdrawPlatformFees()).to.be.revertedWithCustomError(taskEscrow, "OwnableUnauthorizedAccount")
|
||||
.withArgs(requester.address);
|
||||
});
|
||||
});
|
||||
describe("Pause Functionality", function () {
|
||||
it("Should allow owner to pause", async function () {
|
||||
await taskEscrow.connect(owner).pause();
|
||||
(0, chai_1.expect)(await taskEscrow.paused()).to.be.true;
|
||||
});
|
||||
it("Should prevent task creation when paused", async function () {
|
||||
await taskEscrow.connect(owner).pause();
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await (0, chai_1.expect)(taskEscrow.connect(requester).createTask(PAYMENT_AMOUNT, DURATION_DAYS)).to.be.revertedWithCustomError(taskEscrow, "EnforcedPause");
|
||||
});
|
||||
it("Should allow owner to unpause", async function () {
|
||||
await taskEscrow.connect(owner).pause();
|
||||
await taskEscrow.connect(owner).unpause();
|
||||
(0, chai_1.expect)(await taskEscrow.paused()).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
359
dmtp/server/test/TaskEscrow.test.ts
Normal file
359
dmtp/server/test/TaskEscrow.test.ts
Normal file
@@ -0,0 +1,359 @@
|
||||
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers";
|
||||
import { time } from "@nomicfoundation/hardhat-network-helpers";
|
||||
import { expect } from "chai";
|
||||
import { ethers } from "hardhat";
|
||||
import { TaskEscrow } from "../typechain-types";
|
||||
|
||||
describe("TaskEscrow", function () {
|
||||
let taskEscrow: TaskEscrow;
|
||||
let cUSDMock: any;
|
||||
let owner: SignerWithAddress;
|
||||
let requester: SignerWithAddress;
|
||||
let worker: SignerWithAddress;
|
||||
|
||||
const PAYMENT_AMOUNT = ethers.parseEther("10"); // 10 cUSD
|
||||
const DURATION_DAYS = 7;
|
||||
|
||||
beforeEach(async function () {
|
||||
[owner, requester, worker] = await ethers.getSigners();
|
||||
|
||||
// Deploy mock cUSD token
|
||||
const MockERC20 = await ethers.getContractFactory("MockERC20");
|
||||
cUSDMock = await MockERC20.deploy("Celo Dollar", "cUSD");
|
||||
await cUSDMock.waitForDeployment();
|
||||
|
||||
// Deploy TaskEscrow
|
||||
const TaskEscrow = await ethers.getContractFactory("TaskEscrow");
|
||||
taskEscrow = await TaskEscrow.deploy(await cUSDMock.getAddress());
|
||||
await taskEscrow.waitForDeployment();
|
||||
|
||||
// Mint cUSD to requester
|
||||
await cUSDMock.mint(requester.address, ethers.parseEther("1000"));
|
||||
});
|
||||
|
||||
describe("Deployment", function () {
|
||||
it("Should set the correct owner", async function () {
|
||||
expect(await taskEscrow.owner()).to.equal(owner.address);
|
||||
});
|
||||
|
||||
it("Should set the correct cUSD address", async function () {
|
||||
expect(await taskEscrow.cUSD()).to.equal(await cUSDMock.getAddress());
|
||||
});
|
||||
|
||||
it("Should initialize with zero platform fees", async function () {
|
||||
expect(await taskEscrow.platformFeesAccumulated()).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Create Task", function () {
|
||||
it("Should create a task successfully", async function () {
|
||||
// Approve and create task
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
|
||||
await expect(
|
||||
taskEscrow.connect(requester).createTask(PAYMENT_AMOUNT, DURATION_DAYS)
|
||||
)
|
||||
.to.emit(taskEscrow, "TaskCreated")
|
||||
.withArgs(
|
||||
1,
|
||||
requester.address,
|
||||
PAYMENT_AMOUNT,
|
||||
(await time.latest()) + DURATION_DAYS * 24 * 60 * 60
|
||||
);
|
||||
|
||||
const task = await taskEscrow.getTask(1);
|
||||
expect(task.requester).to.equal(requester.address);
|
||||
expect(task.paymentAmount).to.equal(PAYMENT_AMOUNT);
|
||||
expect(task.status).to.equal(0); // Open
|
||||
});
|
||||
|
||||
it("Should fail with zero payment amount", async function () {
|
||||
await expect(
|
||||
taskEscrow.connect(requester).createTask(0, DURATION_DAYS)
|
||||
).to.be.revertedWith("Payment must be > 0");
|
||||
});
|
||||
|
||||
it("Should fail with invalid duration", async function () {
|
||||
await expect(
|
||||
taskEscrow.connect(requester).createTask(PAYMENT_AMOUNT, 0)
|
||||
).to.be.revertedWith("Invalid duration");
|
||||
|
||||
await expect(
|
||||
taskEscrow.connect(requester).createTask(PAYMENT_AMOUNT, 91)
|
||||
).to.be.revertedWith("Invalid duration");
|
||||
});
|
||||
|
||||
it("Should transfer cUSD to contract", async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
|
||||
expect(await cUSDMock.balanceOf(await taskEscrow.getAddress())).to.equal(
|
||||
PAYMENT_AMOUNT
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Assign Worker", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
});
|
||||
|
||||
it("Should assign worker successfully", async function () {
|
||||
await expect(
|
||||
taskEscrow.connect(requester).assignWorker(1, worker.address)
|
||||
)
|
||||
.to.emit(taskEscrow, "WorkerAssigned")
|
||||
.withArgs(1, worker.address);
|
||||
|
||||
const task = await taskEscrow.getTask(1);
|
||||
expect(task.worker).to.equal(worker.address);
|
||||
expect(task.status).to.equal(1); // InProgress
|
||||
});
|
||||
|
||||
it("Should fail if not requester", async function () {
|
||||
await expect(
|
||||
taskEscrow.connect(worker).assignWorker(1, worker.address)
|
||||
).to.be.revertedWith("Not task requester");
|
||||
});
|
||||
|
||||
it("Should fail with invalid worker address", async function () {
|
||||
await expect(
|
||||
taskEscrow.connect(requester).assignWorker(1, ethers.ZeroAddress)
|
||||
).to.be.revertedWith("Invalid worker address");
|
||||
});
|
||||
|
||||
it("Should fail if requester tries to be worker", async function () {
|
||||
await expect(
|
||||
taskEscrow.connect(requester).assignWorker(1, requester.address)
|
||||
).to.be.revertedWith("Requester cannot be worker");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Approve Submission", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
await taskEscrow.connect(requester).assignWorker(1, worker.address);
|
||||
});
|
||||
|
||||
it("Should approve and release payment", async function () {
|
||||
const workerBalanceBefore = await cUSDMock.balanceOf(worker.address);
|
||||
|
||||
await taskEscrow.connect(owner).approveSubmission(1);
|
||||
|
||||
const workerBalanceAfter = await cUSDMock.balanceOf(worker.address);
|
||||
const expectedWorkerPayment = (PAYMENT_AMOUNT * 9500n) / 10000n; // 95%
|
||||
|
||||
expect(workerBalanceAfter - workerBalanceBefore).to.equal(
|
||||
expectedWorkerPayment
|
||||
);
|
||||
|
||||
const task = await taskEscrow.getTask(1);
|
||||
expect(task.status).to.equal(2); // Completed
|
||||
});
|
||||
|
||||
it("Should accumulate platform fees", async function () {
|
||||
await taskEscrow.connect(owner).approveSubmission(1);
|
||||
|
||||
const expectedFee = (PAYMENT_AMOUNT * 500n) / 10000n; // 5%
|
||||
expect(await taskEscrow.platformFeesAccumulated()).to.equal(expectedFee);
|
||||
});
|
||||
|
||||
it("Should fail if not owner", async function () {
|
||||
await expect(taskEscrow.connect(requester).approveSubmission(1))
|
||||
.to.be.revertedWithCustomError(taskEscrow, "OwnableUnauthorizedAccount")
|
||||
.withArgs(requester.address);
|
||||
});
|
||||
|
||||
it("Should fail if task not in progress", async function () {
|
||||
await taskEscrow.connect(owner).approveSubmission(1);
|
||||
|
||||
await expect(
|
||||
taskEscrow.connect(owner).approveSubmission(1)
|
||||
).to.be.revertedWith("Task not in progress");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Reject Submission", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
await taskEscrow.connect(requester).assignWorker(1, worker.address);
|
||||
});
|
||||
|
||||
it("Should reject and refund requester", async function () {
|
||||
const requesterBalanceBefore = await cUSDMock.balanceOf(
|
||||
requester.address
|
||||
);
|
||||
|
||||
await taskEscrow.connect(owner).rejectSubmission(1);
|
||||
|
||||
const requesterBalanceAfter = await cUSDMock.balanceOf(requester.address);
|
||||
expect(requesterBalanceAfter - requesterBalanceBefore).to.equal(
|
||||
PAYMENT_AMOUNT
|
||||
);
|
||||
|
||||
const task = await taskEscrow.getTask(1);
|
||||
expect(task.status).to.equal(3); // Cancelled
|
||||
});
|
||||
|
||||
it("Should fail if not owner", async function () {
|
||||
await expect(
|
||||
taskEscrow.connect(requester).rejectSubmission(1)
|
||||
).to.be.revertedWithCustomError(taskEscrow, "OwnableUnauthorizedAccount")
|
||||
.withArgs(requester.address);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Cancel Task", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
});
|
||||
|
||||
it("Should allow requester to cancel open task", async function () {
|
||||
const requesterBalanceBefore = await cUSDMock.balanceOf(
|
||||
requester.address
|
||||
);
|
||||
|
||||
await taskEscrow.connect(requester).cancelTask(1);
|
||||
|
||||
const requesterBalanceAfter = await cUSDMock.balanceOf(requester.address);
|
||||
expect(requesterBalanceAfter - requesterBalanceBefore).to.equal(
|
||||
PAYMENT_AMOUNT
|
||||
);
|
||||
|
||||
const task = await taskEscrow.getTask(1);
|
||||
expect(task.status).to.equal(3); // Cancelled
|
||||
});
|
||||
|
||||
it("Should fail if not requester", async function () {
|
||||
await expect(taskEscrow.connect(worker).cancelTask(1)).to.be.revertedWith(
|
||||
"Not task requester"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Expired Task", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
});
|
||||
|
||||
it("Should allow claiming expired task", async function () {
|
||||
// Fast forward time
|
||||
await time.increase(DURATION_DAYS * 24 * 60 * 60 + 1);
|
||||
|
||||
const requesterBalanceBefore = await cUSDMock.balanceOf(
|
||||
requester.address
|
||||
);
|
||||
|
||||
await taskEscrow.connect(requester).claimExpiredTask(1);
|
||||
|
||||
const requesterBalanceAfter = await cUSDMock.balanceOf(requester.address);
|
||||
expect(requesterBalanceAfter - requesterBalanceBefore).to.equal(
|
||||
PAYMENT_AMOUNT
|
||||
);
|
||||
|
||||
const task = await taskEscrow.getTask(1);
|
||||
expect(task.status).to.equal(4); // Expired
|
||||
});
|
||||
|
||||
it("Should fail if task not expired", async function () {
|
||||
await expect(
|
||||
taskEscrow.connect(requester).claimExpiredTask(1)
|
||||
).to.be.revertedWith("Task not expired yet");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Withdraw Platform Fees", function () {
|
||||
beforeEach(async function () {
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
await taskEscrow
|
||||
.connect(requester)
|
||||
.createTask(PAYMENT_AMOUNT, DURATION_DAYS);
|
||||
await taskEscrow.connect(requester).assignWorker(1, worker.address);
|
||||
await taskEscrow.connect(owner).approveSubmission(1);
|
||||
});
|
||||
|
||||
it("Should allow owner to withdraw fees", async function () {
|
||||
const ownerBalanceBefore = await cUSDMock.balanceOf(owner.address);
|
||||
const expectedFee = (PAYMENT_AMOUNT * 500n) / 10000n;
|
||||
|
||||
await taskEscrow.connect(owner).withdrawPlatformFees();
|
||||
|
||||
const ownerBalanceAfter = await cUSDMock.balanceOf(owner.address);
|
||||
expect(ownerBalanceAfter - ownerBalanceBefore).to.equal(expectedFee);
|
||||
expect(await taskEscrow.platformFeesAccumulated()).to.equal(0);
|
||||
});
|
||||
|
||||
it("Should fail if no fees to withdraw", async function () {
|
||||
await taskEscrow.connect(owner).withdrawPlatformFees();
|
||||
|
||||
await expect(
|
||||
taskEscrow.connect(owner).withdrawPlatformFees()
|
||||
).to.be.revertedWith("No fees to withdraw");
|
||||
});
|
||||
|
||||
it("Should fail if not owner", async function () {
|
||||
await expect(
|
||||
taskEscrow.connect(requester).withdrawPlatformFees()
|
||||
).to.be.revertedWithCustomError(taskEscrow, "OwnableUnauthorizedAccount")
|
||||
.withArgs(requester.address);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Pause Functionality", function () {
|
||||
it("Should allow owner to pause", async function () {
|
||||
await taskEscrow.connect(owner).pause();
|
||||
expect(await taskEscrow.paused()).to.be.true;
|
||||
});
|
||||
|
||||
it("Should prevent task creation when paused", async function () {
|
||||
await taskEscrow.connect(owner).pause();
|
||||
|
||||
await cUSDMock
|
||||
.connect(requester)
|
||||
.approve(await taskEscrow.getAddress(), PAYMENT_AMOUNT);
|
||||
|
||||
await expect(
|
||||
taskEscrow.connect(requester).createTask(PAYMENT_AMOUNT, DURATION_DAYS)
|
||||
).to.be.revertedWithCustomError(taskEscrow, "EnforcedPause");
|
||||
});
|
||||
|
||||
it("Should allow owner to unpause", async function () {
|
||||
await taskEscrow.connect(owner).pause();
|
||||
await taskEscrow.connect(owner).unpause();
|
||||
expect(await taskEscrow.paused()).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
100
dmtp/server/test/ai-verification.test.js
Normal file
100
dmtp/server/test/ai-verification.test.js
Normal file
@@ -0,0 +1,100 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const chai_1 = require("chai");
|
||||
const ai_verification_service_1 = require("../src/services/ai-verification.service");
|
||||
describe('AIVerificationService', function () {
|
||||
this.timeout(30000); // Increase timeout for API calls
|
||||
let aiService;
|
||||
before(() => {
|
||||
aiService = new ai_verification_service_1.AIVerificationService();
|
||||
});
|
||||
describe('Text Verification', function () {
|
||||
it('should verify a valid text submission', async function () {
|
||||
const input = {
|
||||
submissionText: 'The sky is blue because of Rayleigh scattering of sunlight.',
|
||||
verificationCriteria: 'Answer must explain why the sky is blue with scientific reasoning.',
|
||||
taskType: 'text_verification',
|
||||
};
|
||||
const result = await aiService.verifyTextTask(input);
|
||||
(0, chai_1.expect)(result).to.have.property('approved');
|
||||
(0, chai_1.expect)(result).to.have.property('score');
|
||||
(0, chai_1.expect)(result).to.have.property('reasoning');
|
||||
(0, chai_1.expect)(result.score).to.be.a('number');
|
||||
(0, chai_1.expect)(result.score).to.be.greaterThan(0);
|
||||
(0, chai_1.expect)(result.score).to.be.lessThanOrEqual(100);
|
||||
});
|
||||
it('should reject invalid text submission', async function () {
|
||||
const input = {
|
||||
submissionText: 'I like pizza',
|
||||
verificationCriteria: 'Answer must explain photosynthesis in plants.',
|
||||
taskType: 'text_verification',
|
||||
};
|
||||
const result = await aiService.verifyTextTask(input);
|
||||
(0, chai_1.expect)(result.approved).to.be.false;
|
||||
(0, chai_1.expect)(result.score).to.be.lessThan(50);
|
||||
});
|
||||
it('should cache repeated verification requests', async function () {
|
||||
const input = {
|
||||
submissionText: 'Test caching',
|
||||
verificationCriteria: 'Must contain the word test',
|
||||
taskType: 'text_verification',
|
||||
};
|
||||
const result1 = await aiService.verifyTextTask(input);
|
||||
const result2 = await aiService.verifyTextTask(input);
|
||||
(0, chai_1.expect)(result1.timestamp).to.equal(result2.timestamp);
|
||||
});
|
||||
});
|
||||
describe('Survey Verification', function () {
|
||||
it('should verify survey submissions', async function () {
|
||||
const answers = {
|
||||
question1: 'Answer 1',
|
||||
question2: 'Answer 2',
|
||||
question3: 'Answer 3',
|
||||
};
|
||||
const result = await aiService.verifySurveySubmission(answers, 'Must contain answers for question1, question2, and question3');
|
||||
(0, chai_1.expect)(result).to.have.property('approved');
|
||||
(0, chai_1.expect)(result).to.have.property('score');
|
||||
});
|
||||
});
|
||||
describe('Content Moderation', function () {
|
||||
it('should detect inappropriate content', async function () {
|
||||
const result = await aiService.verifyContentModeration('This is spam spam spam', 'Flag content that appears to be spam or repetitive');
|
||||
(0, chai_1.expect)(result).to.have.property('approved');
|
||||
(0, chai_1.expect)(result).to.have.property('score');
|
||||
});
|
||||
it('should approve clean content', async function () {
|
||||
const result = await aiService.verifyContentModeration('This is a helpful and constructive comment.', 'Flag harmful, abusive, or spam content');
|
||||
(0, chai_1.expect)(result.approved).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('Health Status', function () {
|
||||
it('should return service health status', async function () {
|
||||
const health = await aiService.getHealthStatus();
|
||||
(0, chai_1.expect)(health).to.have.property('status');
|
||||
(0, chai_1.expect)(health).to.have.property('rateLimit');
|
||||
(0, chai_1.expect)(health).to.have.property('cache');
|
||||
(0, chai_1.expect)(health.status).to.equal('healthy');
|
||||
});
|
||||
});
|
||||
describe('Batch Verification', function () {
|
||||
it('should batch verify multiple submissions', async function () {
|
||||
const submissions = [
|
||||
{
|
||||
submissionText: 'Valid answer 1',
|
||||
verificationCriteria: 'Must be a valid answer',
|
||||
},
|
||||
{
|
||||
submissionText: 'Valid answer 2',
|
||||
verificationCriteria: 'Must be a valid answer',
|
||||
},
|
||||
];
|
||||
const results = await aiService.batchVerify(submissions);
|
||||
(0, chai_1.expect)(results).to.be.an('array');
|
||||
(0, chai_1.expect)(results).to.have.lengthOf(2);
|
||||
results.forEach((result) => {
|
||||
(0, chai_1.expect)(result).to.have.property('approved');
|
||||
(0, chai_1.expect)(result).to.have.property('score');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
132
dmtp/server/test/ai-verification.test.ts
Normal file
132
dmtp/server/test/ai-verification.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { expect } from 'chai';
|
||||
import { AIVerificationService } from '../src/services/ai-verification.service';
|
||||
import { TextVerificationInput } from '../src/types/ai.types';
|
||||
|
||||
describe('AIVerificationService', function () {
|
||||
this.timeout(30000); // Increase timeout for API calls
|
||||
|
||||
let aiService: AIVerificationService;
|
||||
|
||||
before(() => {
|
||||
aiService = new AIVerificationService();
|
||||
});
|
||||
|
||||
describe('Text Verification', function () {
|
||||
it('should verify a valid text submission', async function () {
|
||||
const input: TextVerificationInput = {
|
||||
submissionText: 'The sky is blue because of Rayleigh scattering of sunlight.',
|
||||
verificationCriteria: 'Answer must explain why the sky is blue with scientific reasoning.',
|
||||
taskType: 'text_verification',
|
||||
};
|
||||
|
||||
const result = await aiService.verifyTextTask(input);
|
||||
|
||||
expect(result).to.have.property('approved');
|
||||
expect(result).to.have.property('score');
|
||||
expect(result).to.have.property('reasoning');
|
||||
expect(result.score).to.be.a('number');
|
||||
expect(result.score).to.be.greaterThan(0);
|
||||
expect(result.score).to.be.lessThanOrEqual(100);
|
||||
});
|
||||
|
||||
it('should reject invalid text submission', async function () {
|
||||
const input: TextVerificationInput = {
|
||||
submissionText: 'I like pizza',
|
||||
verificationCriteria: 'Answer must explain photosynthesis in plants.',
|
||||
taskType: 'text_verification',
|
||||
};
|
||||
|
||||
const result = await aiService.verifyTextTask(input);
|
||||
|
||||
expect(result.approved).to.be.false;
|
||||
expect(result.score).to.be.lessThan(50);
|
||||
});
|
||||
|
||||
it('should cache repeated verification requests', async function () {
|
||||
const input: TextVerificationInput = {
|
||||
submissionText: 'Test caching',
|
||||
verificationCriteria: 'Must contain the word test',
|
||||
taskType: 'text_verification',
|
||||
};
|
||||
|
||||
const result1 = await aiService.verifyTextTask(input);
|
||||
const result2 = await aiService.verifyTextTask(input);
|
||||
|
||||
expect(result1.timestamp).to.equal(result2.timestamp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Survey Verification', function () {
|
||||
it('should verify survey submissions', async function () {
|
||||
const answers = {
|
||||
question1: 'Answer 1',
|
||||
question2: 'Answer 2',
|
||||
question3: 'Answer 3',
|
||||
};
|
||||
|
||||
const result = await aiService.verifySurveySubmission(
|
||||
answers,
|
||||
'Must contain answers for question1, question2, and question3'
|
||||
);
|
||||
|
||||
expect(result).to.have.property('approved');
|
||||
expect(result).to.have.property('score');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Content Moderation', function () {
|
||||
it('should detect inappropriate content', async function () {
|
||||
const result = await aiService.verifyContentModeration(
|
||||
'This is spam spam spam',
|
||||
'Flag content that appears to be spam or repetitive'
|
||||
);
|
||||
|
||||
expect(result).to.have.property('approved');
|
||||
expect(result).to.have.property('score');
|
||||
});
|
||||
|
||||
it('should approve clean content', async function () {
|
||||
const result = await aiService.verifyContentModeration(
|
||||
'This is a helpful and constructive comment.',
|
||||
'Flag harmful, abusive, or spam content'
|
||||
);
|
||||
|
||||
expect(result.approved).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Health Status', function () {
|
||||
it('should return service health status', async function () {
|
||||
const health = await aiService.getHealthStatus();
|
||||
|
||||
expect(health).to.have.property('status');
|
||||
expect(health).to.have.property('rateLimit');
|
||||
expect(health).to.have.property('cache');
|
||||
expect(health.status).to.equal('healthy');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Batch Verification', function () {
|
||||
it('should batch verify multiple submissions', async function () {
|
||||
const submissions: TextVerificationInput[] = [
|
||||
{
|
||||
submissionText: 'Valid answer 1',
|
||||
verificationCriteria: 'Must be a valid answer',
|
||||
},
|
||||
{
|
||||
submissionText: 'Valid answer 2',
|
||||
verificationCriteria: 'Must be a valid answer',
|
||||
},
|
||||
];
|
||||
|
||||
const results = await aiService.batchVerify(submissions);
|
||||
|
||||
expect(results).to.be.an('array');
|
||||
expect(results).to.have.lengthOf(2);
|
||||
results.forEach((result) => {
|
||||
expect(result).to.have.property('approved');
|
||||
expect(result).to.have.property('score');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
173
dmtp/server/test/content-moderation.test.js
Normal file
173
dmtp/server/test/content-moderation.test.js
Normal file
@@ -0,0 +1,173 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const chai_1 = require("chai");
|
||||
const content_moderation_service_1 = require("../src/services/content-moderation.service");
|
||||
const moderation_types_1 = require("../src/types/moderation.types");
|
||||
describe('ContentModerationService', function () {
|
||||
this.timeout(60000); // Increase timeout for API calls
|
||||
describe('Safe Content', function () {
|
||||
it('should approve clean, normal content', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'This is a helpful and constructive comment about the task.',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.false;
|
||||
(0, chai_1.expect)(result.action).to.equal(moderation_types_1.ModerationAction.APPROVE);
|
||||
});
|
||||
it('should approve simple responses', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'Yes',
|
||||
});
|
||||
(0, chai_1.expect)(result.action).to.equal(moderation_types_1.ModerationAction.APPROVE);
|
||||
});
|
||||
});
|
||||
describe('Spam Detection', function () {
|
||||
it('should detect repetitive spam content', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'Buy now! Click here! Limited time offer! Buy now! Act fast!',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
(0, chai_1.expect)(result.categories.spam.detected).to.be.true;
|
||||
});
|
||||
it('should detect bot-generated nonsense', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'asdfghjkl qwertyuiop zxcvbnm asdfghjkl qwertyuiop',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
});
|
||||
it('should detect character repetition spam', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'aaaaaaaaaaaaaaaaaa',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
(0, chai_1.expect)(result.categories.spam.detected).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('Toxic Content Detection', function () {
|
||||
it('should detect offensive language', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'You are stupid and worthless, idiot!',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
(0, chai_1.expect)(result.categories.toxic.detected).to.be.true;
|
||||
});
|
||||
it('should detect aggressive language', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'I hate you so much, you are the worst person ever.',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
(0, chai_1.expect)(result.categories.toxic.detected).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('Hate Speech Detection', function () {
|
||||
it('should detect discriminatory content', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'All [ethnic group] are criminals and should be deported.',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
(0, chai_1.expect)(result.categories.hate_speech.detected).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('Fraud Detection', function () {
|
||||
it('should detect fake data attempts', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'Random answer random answer random answer to get paid quickly.',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
});
|
||||
it('should detect copy-paste attempts', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum.',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('Inappropriate Content Detection', function () {
|
||||
it('should detect sexual content', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'Explicit sexual content here [inappropriate text]',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
(0, chai_1.expect)(result.categories.inappropriate.detected).to.be.true;
|
||||
});
|
||||
it('should detect violent content', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'Detailed description of violence and harm to others.',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
});
|
||||
});
|
||||
describe('Edge Cases', function () {
|
||||
it('should handle sarcasm appropriately', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'Oh great, another wonderful task. How amazing!',
|
||||
context: {
|
||||
taskType: 'survey',
|
||||
},
|
||||
});
|
||||
// Sarcasm might be flagged but should not be auto-rejected
|
||||
if (result.flagged) {
|
||||
(0, chai_1.expect)(result.action).to.not.equal(moderation_types_1.ModerationAction.AUTO_REJECT);
|
||||
}
|
||||
});
|
||||
it('should handle educational content about sensitive topics', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'This historical article discusses discrimination in the 1960s.',
|
||||
});
|
||||
// Educational content should be approved or flagged for review, not auto-rejected
|
||||
(0, chai_1.expect)(result.action).to.not.equal(moderation_types_1.ModerationAction.AUTO_REJECT);
|
||||
});
|
||||
it('should handle quotes and citations', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'As quoted in the article: "controversial statement here"',
|
||||
});
|
||||
// Quotes should be evaluated in context
|
||||
(0, chai_1.expect)(result).to.have.property('action');
|
||||
});
|
||||
it('should handle empty content', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: '',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
});
|
||||
it('should handle very long content', async function () {
|
||||
const longContent = 'This is a test. '.repeat(100);
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: longContent,
|
||||
});
|
||||
(0, chai_1.expect)(result).to.have.property('action');
|
||||
});
|
||||
});
|
||||
describe('Blocklist Functionality', function () {
|
||||
it('should instantly reject blocklisted pharmaceutical spam', async function () {
|
||||
const result = await content_moderation_service_1.contentModerationService.moderateSubmission({
|
||||
content: 'Buy cheap viagra online now!',
|
||||
});
|
||||
(0, chai_1.expect)(result.flagged).to.be.true;
|
||||
(0, chai_1.expect)(result.action).to.equal(moderation_types_1.ModerationAction.AUTO_REJECT);
|
||||
});
|
||||
});
|
||||
describe('Batch Moderation', function () {
|
||||
it('should moderate multiple submissions', async function () {
|
||||
const inputs = [
|
||||
{ content: 'This is safe content' },
|
||||
{ content: 'This is spam spam spam spam' },
|
||||
{ content: 'Another safe comment' },
|
||||
];
|
||||
const results = await content_moderation_service_1.contentModerationService.batchModerate(inputs);
|
||||
(0, chai_1.expect)(results).to.have.lengthOf(3);
|
||||
(0, chai_1.expect)(results[0].action).to.equal(moderation_types_1.ModerationAction.APPROVE);
|
||||
(0, chai_1.expect)(results[1].flagged).to.be.true;
|
||||
(0, chai_1.expect)(results[2].action).to.equal(moderation_types_1.ModerationAction.APPROVE);
|
||||
});
|
||||
});
|
||||
describe('Statistics', function () {
|
||||
it('should return moderation statistics', function () {
|
||||
const stats = content_moderation_service_1.contentModerationService.getStats();
|
||||
(0, chai_1.expect)(stats).to.have.property('total');
|
||||
(0, chai_1.expect)(stats).to.have.property('approved');
|
||||
(0, chai_1.expect)(stats).to.have.property('flagged');
|
||||
(0, chai_1.expect)(stats).to.have.property('rejected');
|
||||
(0, chai_1.expect)(stats).to.have.property('byCategory');
|
||||
});
|
||||
});
|
||||
});
|
||||
214
dmtp/server/test/content-moderation.test.ts
Normal file
214
dmtp/server/test/content-moderation.test.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
import { expect } from 'chai';
|
||||
import { contentModerationService } from '../src/services/content-moderation.service';
|
||||
import { ModerationAction } from '../src/types/moderation.types';
|
||||
|
||||
describe('ContentModerationService', function () {
|
||||
this.timeout(60000); // Increase timeout for API calls
|
||||
|
||||
describe('Safe Content', function () {
|
||||
it('should approve clean, normal content', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'This is a helpful and constructive comment about the task.',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.false;
|
||||
expect(result.action).to.equal(ModerationAction.APPROVE);
|
||||
});
|
||||
|
||||
it('should approve simple responses', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'Yes',
|
||||
});
|
||||
|
||||
expect(result.action).to.equal(ModerationAction.APPROVE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Spam Detection', function () {
|
||||
it('should detect repetitive spam content', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'Buy now! Click here! Limited time offer! Buy now! Act fast!',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
expect(result.categories.spam.detected).to.be.true;
|
||||
});
|
||||
|
||||
it('should detect bot-generated nonsense', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'asdfghjkl qwertyuiop zxcvbnm asdfghjkl qwertyuiop',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
});
|
||||
|
||||
it('should detect character repetition spam', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'aaaaaaaaaaaaaaaaaa',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
expect(result.categories.spam.detected).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Toxic Content Detection', function () {
|
||||
it('should detect offensive language', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'You are stupid and worthless, idiot!',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
expect(result.categories.toxic.detected).to.be.true;
|
||||
});
|
||||
|
||||
it('should detect aggressive language', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'I hate you so much, you are the worst person ever.',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
expect(result.categories.toxic.detected).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Hate Speech Detection', function () {
|
||||
it('should detect discriminatory content', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'All [ethnic group] are criminals and should be deported.',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
expect(result.categories.hate_speech.detected).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Fraud Detection', function () {
|
||||
it('should detect fake data attempts', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'Random answer random answer random answer to get paid quickly.',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
});
|
||||
|
||||
it('should detect copy-paste attempts', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum.',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Inappropriate Content Detection', function () {
|
||||
it('should detect sexual content', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'Explicit sexual content here [inappropriate text]',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
expect(result.categories.inappropriate.detected).to.be.true;
|
||||
});
|
||||
|
||||
it('should detect violent content', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'Detailed description of violence and harm to others.',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge Cases', function () {
|
||||
it('should handle sarcasm appropriately', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'Oh great, another wonderful task. How amazing!',
|
||||
context: {
|
||||
taskType: 'survey',
|
||||
},
|
||||
});
|
||||
|
||||
// Sarcasm might be flagged but should not be auto-rejected
|
||||
if (result.flagged) {
|
||||
expect(result.action).to.not.equal(ModerationAction.AUTO_REJECT);
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle educational content about sensitive topics', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'This historical article discusses discrimination in the 1960s.',
|
||||
});
|
||||
|
||||
// Educational content should be approved or flagged for review, not auto-rejected
|
||||
expect(result.action).to.not.equal(ModerationAction.AUTO_REJECT);
|
||||
});
|
||||
|
||||
it('should handle quotes and citations', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'As quoted in the article: "controversial statement here"',
|
||||
});
|
||||
|
||||
// Quotes should be evaluated in context
|
||||
expect(result).to.have.property('action');
|
||||
});
|
||||
|
||||
it('should handle empty content', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: '',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
});
|
||||
|
||||
it('should handle very long content', async function () {
|
||||
const longContent = 'This is a test. '.repeat(100);
|
||||
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: longContent,
|
||||
});
|
||||
|
||||
expect(result).to.have.property('action');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Blocklist Functionality', function () {
|
||||
it('should instantly reject blocklisted pharmaceutical spam', async function () {
|
||||
const result = await contentModerationService.moderateSubmission({
|
||||
content: 'Buy cheap viagra online now!',
|
||||
});
|
||||
|
||||
expect(result.flagged).to.be.true;
|
||||
expect(result.action).to.equal(ModerationAction.AUTO_REJECT);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Batch Moderation', function () {
|
||||
it('should moderate multiple submissions', async function () {
|
||||
const inputs = [
|
||||
{ content: 'This is safe content' },
|
||||
{ content: 'This is spam spam spam spam' },
|
||||
{ content: 'Another safe comment' },
|
||||
];
|
||||
|
||||
const results = await contentModerationService.batchModerate(inputs);
|
||||
|
||||
expect(results).to.have.lengthOf(3);
|
||||
expect(results[0].action).to.equal(ModerationAction.APPROVE);
|
||||
expect(results[1].flagged).to.be.true;
|
||||
expect(results[2].action).to.equal(ModerationAction.APPROVE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Statistics', function () {
|
||||
it('should return moderation statistics', function () {
|
||||
const stats = contentModerationService.getStats();
|
||||
|
||||
expect(stats).to.have.property('total');
|
||||
expect(stats).to.have.property('approved');
|
||||
expect(stats).to.have.property('flagged');
|
||||
expect(stats).to.have.property('rejected');
|
||||
expect(stats).to.have.property('byCategory');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user