mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-04-21 21:06:01 +02:00
205 lines
6.5 KiB
JavaScript
205 lines
6.5 KiB
JavaScript
const { expect } = require("chai");
|
|
|
|
/**
|
|
* Tests for Conference.toJSON() price calculation logic.
|
|
*
|
|
* Replicates the pricing algorithm from src/core/Conference.ts to test
|
|
* the math in isolation without needing MongoDB.
|
|
*/
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Replicated price calculation from Conference.toJSON()
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function calculatePrice(plan, repositories, endDate) {
|
|
const pricePerHourPerRepo = plan.pricePerRepository / 30;
|
|
let price = 0;
|
|
const today = new Date() > endDate ? endDate : new Date();
|
|
|
|
repositories.forEach((r) => {
|
|
const removeDate =
|
|
r.removeDate && r.removeDate < today ? r.removeDate : today;
|
|
price +=
|
|
(Math.max(removeDate.getTime() - r.addDate.getTime(), 0) /
|
|
1000 /
|
|
60 /
|
|
60 /
|
|
24) *
|
|
pricePerHourPerRepo;
|
|
});
|
|
return price;
|
|
}
|
|
|
|
function countActiveRepos(repositories) {
|
|
return repositories.filter((r) => !r.removeDate).length;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Tests
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("Conference price calculation", function () {
|
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
|
|
describe("basic pricing", function () {
|
|
it("returns 0 for no repositories", function () {
|
|
const price = calculatePrice(
|
|
{ pricePerRepository: 3 },
|
|
[],
|
|
new Date(Date.now() + 30 * DAY_MS)
|
|
);
|
|
expect(price).to.equal(0);
|
|
});
|
|
|
|
it("returns 0 for free plan", function () {
|
|
const addDate = new Date(Date.now() - 10 * DAY_MS);
|
|
const price = calculatePrice(
|
|
{ pricePerRepository: 0 },
|
|
[{ addDate }],
|
|
new Date(Date.now() + 30 * DAY_MS)
|
|
);
|
|
expect(price).to.equal(0);
|
|
});
|
|
|
|
it("calculates price for one repo over 10 days", function () {
|
|
const now = new Date();
|
|
const addDate = new Date(now.getTime() - 10 * DAY_MS);
|
|
const endDate = new Date(now.getTime() + 20 * DAY_MS);
|
|
const price = calculatePrice(
|
|
{ pricePerRepository: 3 },
|
|
[{ addDate }],
|
|
endDate
|
|
);
|
|
// pricePerHourPerRepo = 3/30 = 0.1 per day
|
|
// duration ≈ 10 days
|
|
// price ≈ 10 * 0.1 = 1.0
|
|
expect(price).to.be.closeTo(1.0, 0.01);
|
|
});
|
|
|
|
it("calculates price for multiple repos", function () {
|
|
const now = new Date();
|
|
const addDate1 = new Date(now.getTime() - 10 * DAY_MS);
|
|
const addDate2 = new Date(now.getTime() - 5 * DAY_MS);
|
|
const endDate = new Date(now.getTime() + 20 * DAY_MS);
|
|
const price = calculatePrice(
|
|
{ pricePerRepository: 3 },
|
|
[{ addDate: addDate1 }, { addDate: addDate2 }],
|
|
endDate
|
|
);
|
|
// repo1: 10 days * 0.1 = 1.0
|
|
// repo2: 5 days * 0.1 = 0.5
|
|
// total ≈ 1.5
|
|
expect(price).to.be.closeTo(1.5, 0.01);
|
|
});
|
|
});
|
|
|
|
describe("removed repositories", function () {
|
|
it("uses removeDate as end for removed repos", function () {
|
|
const now = new Date();
|
|
const addDate = new Date(now.getTime() - 10 * DAY_MS);
|
|
const removeDate = new Date(now.getTime() - 5 * DAY_MS);
|
|
const endDate = new Date(now.getTime() + 20 * DAY_MS);
|
|
const price = calculatePrice(
|
|
{ pricePerRepository: 3 },
|
|
[{ addDate, removeDate }],
|
|
endDate
|
|
);
|
|
// Only charged for 5 days (add to remove), not 10
|
|
// 5 * 0.1 = 0.5
|
|
expect(price).to.be.closeTo(0.5, 0.01);
|
|
});
|
|
|
|
it("uses today if removeDate is in the future", function () {
|
|
const now = new Date();
|
|
const addDate = new Date(now.getTime() - 10 * DAY_MS);
|
|
const removeDate = new Date(now.getTime() + 5 * DAY_MS); // future
|
|
const endDate = new Date(now.getTime() + 20 * DAY_MS);
|
|
const price = calculatePrice(
|
|
{ pricePerRepository: 3 },
|
|
[{ addDate, removeDate }],
|
|
endDate
|
|
);
|
|
// removeDate is in the future, so today is used instead
|
|
// ≈ 10 days * 0.1 = 1.0
|
|
expect(price).to.be.closeTo(1.0, 0.01);
|
|
});
|
|
});
|
|
|
|
describe("expired conference", function () {
|
|
it("caps at endDate when conference is expired", function () {
|
|
const endDate = new Date(Date.now() - 5 * DAY_MS); // 5 days ago
|
|
const addDate = new Date(endDate.getTime() - 10 * DAY_MS); // 15 days ago
|
|
const price = calculatePrice(
|
|
{ pricePerRepository: 3 },
|
|
[{ addDate }],
|
|
endDate
|
|
);
|
|
// Conference ended 5 days ago, repo was added 10 days before that
|
|
// Only charged for 10 days (add to end)
|
|
// 10 * 0.1 = 1.0
|
|
expect(price).to.be.closeTo(1.0, 0.01);
|
|
});
|
|
});
|
|
|
|
describe("edge cases", function () {
|
|
it("handles zero-duration repository (add and remove same time)", function () {
|
|
const now = new Date();
|
|
const addDate = new Date(now.getTime() - 5 * DAY_MS);
|
|
const removeDate = addDate; // same time
|
|
const endDate = new Date(now.getTime() + 20 * DAY_MS);
|
|
const price = calculatePrice(
|
|
{ pricePerRepository: 3 },
|
|
[{ addDate, removeDate }],
|
|
endDate
|
|
);
|
|
expect(price).to.equal(0);
|
|
});
|
|
|
|
it("handles removeDate before addDate via Math.max", function () {
|
|
const now = new Date();
|
|
const addDate = new Date(now.getTime() - 5 * DAY_MS);
|
|
const removeDate = new Date(now.getTime() - 10 * DAY_MS); // before addDate
|
|
const endDate = new Date(now.getTime() + 20 * DAY_MS);
|
|
const price = calculatePrice(
|
|
{ pricePerRepository: 3 },
|
|
[{ addDate, removeDate }],
|
|
endDate
|
|
);
|
|
// Math.max ensures negative duration becomes 0
|
|
expect(price).to.equal(0);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Conference active repository count", function () {
|
|
it("counts repos without removeDate", function () {
|
|
const repos = [
|
|
{ addDate: new Date() },
|
|
{ addDate: new Date(), removeDate: new Date() },
|
|
{ addDate: new Date() },
|
|
];
|
|
expect(countActiveRepos(repos)).to.equal(2);
|
|
});
|
|
|
|
it("returns 0 when all repos are removed", function () {
|
|
const repos = [
|
|
{ addDate: new Date(), removeDate: new Date() },
|
|
{ addDate: new Date(), removeDate: new Date() },
|
|
];
|
|
expect(countActiveRepos(repos)).to.equal(0);
|
|
});
|
|
|
|
it("returns 0 for empty list", function () {
|
|
expect(countActiveRepos([])).to.equal(0);
|
|
});
|
|
|
|
it("counts all repos when none are removed", function () {
|
|
const repos = [
|
|
{ addDate: new Date() },
|
|
{ addDate: new Date() },
|
|
{ addDate: new Date() },
|
|
];
|
|
expect(countActiveRepos(repos)).to.equal(3);
|
|
});
|
|
});
|