Files
anonymous_github/test/conference.test.js
T

164 lines
5.0 KiB
JavaScript

const { expect } = require("chai");
/**
* Tests for Conference logic bugs.
*
* The key bug was that Conference._repositories was initialized as []
* (truthy), so repositories() always returned the empty array without
* querying the database. The fix initializes it as null.
*/
describe("Conference._repositories initialization", function () {
it("empty array [] is truthy (demonstrates the root cause)", function () {
// This is why `if (this._repositories) return this._repositories;`
// was always short-circuiting - an empty array is truthy in JS
expect([]).to.not.be.null;
expect([]).to.not.be.undefined;
// In a boolean context, [] is truthy:
expect(!![]).to.be.true;
});
it("null is falsy (the fix)", function () {
// After the fix, _repositories starts as null so the DB query runs
expect(!!null).to.be.false;
});
it("simulates the fixed repositories() cache behavior", function () {
// Simulate the Conference class behavior
class FakeConference {
constructor() {
this._repositories = null; // fixed: was []
}
repositories() {
if (this._repositories) return this._repositories;
// In real code this would query the DB
this._repositories = [{ id: "repo1" }, { id: "repo2" }];
return this._repositories;
}
}
const conf = new FakeConference();
const repos = conf.repositories();
expect(repos).to.have.length(2);
expect(repos[0].id).to.equal("repo1");
// Second call uses the cache
const repos2 = conf.repositories();
expect(repos2).to.equal(repos); // same reference
});
it("demonstrates the old buggy behavior (always returned empty array)", function () {
class BuggyConference {
constructor() {
this._repositories = []; // old buggy initialization
}
repositories() {
if (this._repositories) return this._repositories;
// This line was NEVER reached because [] is truthy
this._repositories = [{ id: "repo1" }];
return this._repositories;
}
}
const conf = new BuggyConference();
const repos = conf.repositories();
// The bug: always returns empty array, DB query never runs
expect(repos).to.have.length(0);
});
});
describe("PullRequest.check() async expiration", function () {
it("async check() allows awaiting expire()", async function () {
// Simulates the fix: check() is now async so expire() can be awaited
let expired = false;
const fakePR = {
status: "ready",
options: {
expirationMode: "date",
expirationDate: new Date(Date.now() - 1000), // in the past
},
async expire() {
expired = true;
this.status = "expired";
},
async check() {
if (
this.options.expirationMode !== "never" &&
this.status === "ready" &&
this.options.expirationDate
) {
if (this.options.expirationDate <= new Date()) {
await this.expire();
}
}
},
};
await fakePR.check();
expect(expired).to.be.true;
expect(fakePR.status).to.equal("expired");
});
});
describe("Admin MongoDB query safety", function () {
function escapeRegex(str) {
return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
it("escapes regex special characters in search input", function () {
const malicious = ".*";
const escaped = escapeRegex(malicious);
expect(escaped).to.equal("\\.\\*");
});
it("escapes parentheses that could cause ReDoS", function () {
const input = "((((((((((a]))))))))";
const escaped = escapeRegex(input);
// Escaped string should be safe to compile as regex
expect(() => new RegExp(escaped)).to.not.throw();
});
it("preserves alphanumeric characters", function () {
const input = "normalSearch123";
expect(escapeRegex(input)).to.equal("normalSearch123");
});
it("escapes dots so they match literally", function () {
const input = "file.txt";
const escaped = escapeRegex(input);
const regex = new RegExp(escaped);
expect(regex.test("file.txt")).to.be.true;
expect(regex.test("fileXtxt")).to.be.false;
});
describe("empty $or guard", function () {
it("empty $or array would fail in MongoDB", function () {
// MongoDB requires $or to have at least one expression
// The fix: only add { $or: status } when status.length > 0
const status = [];
const query = [];
// Fixed logic:
if (status.length > 0) {
query.push({ $or: status });
}
// When no filters are selected, query should be empty
// (no $or clause at all)
expect(query).to.have.length(0);
});
it("adds $or when status filters are present", function () {
const status = [{ status: "ready" }, { status: "error" }];
const query = [];
if (status.length > 0) {
query.push({ $or: status });
}
expect(query).to.have.length(1);
expect(query[0].$or).to.have.length(2);
});
});
});