mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 14:28:36 +02:00
227 lines
9.1 KiB
TypeScript
227 lines
9.1 KiB
TypeScript
import { Player } from "@player";
|
|
import {
|
|
generateContract,
|
|
generateDummyContract,
|
|
generateRandomContract,
|
|
generateRandomContractOnHome,
|
|
getRandomFilename,
|
|
getRandomReward,
|
|
} from "../../../src/CodingContract/ContractGenerator";
|
|
import { CodingContractName, CompanyName, JobField, JobName } from "../../../src/Enums";
|
|
import { GetAllServers } from "../../../src/Server/AllServers";
|
|
import type { BaseServer } from "../../../src/Server/BaseServer";
|
|
import { SpecialServers } from "../../../src/Server/data/SpecialServers";
|
|
import { getNS, initGameEnvironment, setupBasicTestingEnvironment } from "../Utilities";
|
|
import { prestigeSourceFile } from "../../../src/Prestige";
|
|
import { CodingContractRewardType } from "../../../src/CodingContract/Contract";
|
|
import { joinFaction } from "../../../src/Faction/FactionHelpers";
|
|
import { Factions } from "../../../src/Faction/Factions";
|
|
import { Companies } from "../../../src/Company/Companies";
|
|
import { CodingContractTypes } from "../../../src/CodingContract/ContractTypes";
|
|
import { getRecordEntries } from "../../../src/Types/Record";
|
|
|
|
beforeAll(() => {
|
|
initGameEnvironment();
|
|
});
|
|
|
|
beforeEach(() => {
|
|
setupBasicTestingEnvironment();
|
|
assertNumberOfContracts(0, GetAllServers());
|
|
});
|
|
|
|
function assertNumberOfContracts(expected: number, servers: BaseServer[]): void {
|
|
expect(servers.reduce((sum, server) => sum + server.contracts.length, 0)).toStrictEqual(expected);
|
|
}
|
|
|
|
describe("Generator", () => {
|
|
test("generateRandomContract", () => {
|
|
generateRandomContract();
|
|
assertNumberOfContracts(1, GetAllServers());
|
|
});
|
|
test("generateRandomContractOnHome", () => {
|
|
generateRandomContractOnHome();
|
|
assertNumberOfContracts(1, [Player.getHomeComputer()]);
|
|
});
|
|
test("generateDummyContract", () => {
|
|
generateDummyContract(CodingContractName.FindLargestPrimeFactor, Player.getHomeComputer());
|
|
assertNumberOfContracts(1, GetAllServers());
|
|
});
|
|
// generateContract is flexible. All properties in IGenerateContractParams are optional. This test checks the usage in
|
|
// CodingContractsDev.tsx.
|
|
test("generateContract - home", () => {
|
|
generateContract({ problemType: CodingContractName.FindLargestPrimeFactor, server: SpecialServers.Home });
|
|
assertNumberOfContracts(1, [Player.getHomeComputer()]);
|
|
});
|
|
// This test checks the case in which we randomize everything (e.g., problemType, server).
|
|
test("generateContract - random server", () => {
|
|
generateContract({});
|
|
assertNumberOfContracts(1, GetAllServers());
|
|
});
|
|
});
|
|
|
|
describe("getRandomFilename", () => {
|
|
test("Check format and collision", () => {
|
|
const server = Player.getHomeComputer();
|
|
const set = new Set();
|
|
// Contract names contain only alphanumeric chars.
|
|
const regex = /[^a-zA-Z0-9]/g;
|
|
const maxIter = 1000;
|
|
for (let i = 0; i < maxIter; ++i) {
|
|
const filename = getRandomFilename(server);
|
|
if (filename == null) {
|
|
throw new Error("Cannot generate random filename");
|
|
}
|
|
expect(filename).toMatch(regex);
|
|
set.add(filename);
|
|
}
|
|
// getRandomFilename had a bug that made the filenames collide much easier than what we expected. Please check
|
|
// https://github.com/bitburner-official/bitburner-src/pull/2399 for more information.
|
|
// This test is designed to catch that kind of bug. The probability of collision is greater than zero, so this test
|
|
// may give a false positive. However, the probability is very low (0.000008802741646607437), and the error log
|
|
// should point that out immediately.
|
|
expect(set.size).toStrictEqual(maxIter);
|
|
});
|
|
});
|
|
|
|
describe("getRandomReward", () => {
|
|
test("Disable money reward when CodingContractMoney BN multiplier is 0", () => {
|
|
Player.bitNodeN = 8;
|
|
prestigeSourceFile(true);
|
|
for (let i = 0; i < 1000; ++i) {
|
|
expect(getRandomReward().type).not.toStrictEqual(CodingContractRewardType.Money);
|
|
}
|
|
});
|
|
test("Have all valid reward types", () => {
|
|
const rewardTypeCounts = [0, 0, 0, 0];
|
|
for (let i = 0; i < 1000; ++i) {
|
|
++rewardTypeCounts[getRandomReward().type];
|
|
}
|
|
expect(rewardTypeCounts.length).toStrictEqual(4);
|
|
expect(rewardTypeCounts[CodingContractRewardType.FactionReputation]).toBeGreaterThan(0);
|
|
expect(rewardTypeCounts[CodingContractRewardType.FactionReputationAll]).toBeGreaterThan(0);
|
|
expect(rewardTypeCounts[CodingContractRewardType.CompanyReputation]).toBeGreaterThan(0);
|
|
expect(rewardTypeCounts[CodingContractRewardType.Money]).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe("Receive correct reward", () => {
|
|
test("FactionReputation", () => {
|
|
const ns = getNS();
|
|
generateContract({
|
|
problemType: CodingContractName.FindLargestPrimeFactor,
|
|
server: SpecialServers.Home,
|
|
reward: { type: CodingContractRewardType.FactionReputation },
|
|
});
|
|
joinFaction(Factions.CyberSec);
|
|
expect(Factions.CyberSec.playerReputation).toStrictEqual(0);
|
|
const contract = Player.getHomeComputer().contracts[0];
|
|
ns.codingcontract.attempt(contract.getAnswer(), contract.fn);
|
|
expect(Factions.CyberSec.playerReputation).toBeGreaterThan(0);
|
|
});
|
|
test("FactionReputationAll", () => {
|
|
const ns = getNS();
|
|
generateContract({
|
|
problemType: CodingContractName.FindLargestPrimeFactor,
|
|
server: SpecialServers.Home,
|
|
reward: { type: CodingContractRewardType.FactionReputationAll },
|
|
});
|
|
joinFaction(Factions.CyberSec);
|
|
joinFaction(Factions.NiteSec);
|
|
expect(Factions.CyberSec.playerReputation).toStrictEqual(0);
|
|
expect(Factions.NiteSec.playerReputation).toStrictEqual(0);
|
|
const contract = Player.getHomeComputer().contracts[0];
|
|
ns.codingcontract.attempt(contract.getAnswer(), contract.fn);
|
|
expect(Factions.CyberSec.playerReputation).toBeGreaterThan(0);
|
|
expect(Factions.NiteSec.playerReputation).toBeGreaterThan(0);
|
|
});
|
|
test("CompanyReputation", () => {
|
|
const ns = getNS();
|
|
generateContract({
|
|
problemType: CodingContractName.FindLargestPrimeFactor,
|
|
server: SpecialServers.Home,
|
|
reward: { type: CodingContractRewardType.CompanyReputation },
|
|
});
|
|
expect(ns.singularity.applyToCompany(CompanyName.JoesGuns, JobField.employee)).toStrictEqual(JobName.employee);
|
|
expect(Companies[CompanyName.JoesGuns].playerReputation).toStrictEqual(0);
|
|
const contract = Player.getHomeComputer().contracts[0];
|
|
ns.codingcontract.attempt(contract.getAnswer(), contract.fn);
|
|
expect(Companies[CompanyName.JoesGuns].playerReputation).toBeGreaterThan(0);
|
|
});
|
|
test("Money", () => {
|
|
const ns = getNS();
|
|
generateContract({
|
|
problemType: CodingContractName.FindLargestPrimeFactor,
|
|
server: SpecialServers.Home,
|
|
reward: { type: CodingContractRewardType.Money },
|
|
});
|
|
Player.money = 0;
|
|
const contract = Player.getHomeComputer().contracts[0];
|
|
ns.codingcontract.attempt(contract.getAnswer(), contract.fn);
|
|
expect(Player.money).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe("Receive fallback reward", () => {
|
|
test("FactionReputation", () => {
|
|
const ns = getNS();
|
|
generateContract({
|
|
problemType: CodingContractName.FindLargestPrimeFactor,
|
|
server: SpecialServers.Home,
|
|
reward: { type: CodingContractRewardType.FactionReputation },
|
|
});
|
|
expect(Player.factions.length).toStrictEqual(0);
|
|
Player.money = 0;
|
|
const contract = Player.getHomeComputer().contracts[0];
|
|
ns.codingcontract.attempt(contract.getAnswer(), contract.fn);
|
|
expect(Player.money).toBeGreaterThan(0);
|
|
});
|
|
test("FactionReputationAll", () => {
|
|
const ns = getNS();
|
|
generateContract({
|
|
problemType: CodingContractName.FindLargestPrimeFactor,
|
|
server: SpecialServers.Home,
|
|
reward: { type: CodingContractRewardType.FactionReputationAll },
|
|
});
|
|
expect(Player.factions.length).toStrictEqual(0);
|
|
Player.money = 0;
|
|
const contract = Player.getHomeComputer().contracts[0];
|
|
ns.codingcontract.attempt(contract.getAnswer(), contract.fn);
|
|
expect(Player.money).toBeGreaterThan(0);
|
|
});
|
|
test("CompanyReputation", () => {
|
|
const ns = getNS();
|
|
generateContract({
|
|
problemType: CodingContractName.FindLargestPrimeFactor,
|
|
server: SpecialServers.Home,
|
|
reward: { type: CodingContractRewardType.CompanyReputation },
|
|
});
|
|
expect(Object.keys(Player.jobs).length).toStrictEqual(0);
|
|
joinFaction(Factions.CyberSec);
|
|
expect(Factions.CyberSec.playerReputation).toStrictEqual(0);
|
|
const contract = Player.getHomeComputer().contracts[0];
|
|
ns.codingcontract.attempt(contract.getAnswer(), contract.fn);
|
|
expect(Factions.CyberSec.playerReputation).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe("Check getAnswer and solver", () => {
|
|
// These contracts do not give a way to generate the answer.
|
|
const skippedContractTypes = [
|
|
CodingContractName.Proper2ColoringOfAGraph,
|
|
CodingContractName.ShortestPathInAGrid,
|
|
CodingContractName.SquareRoot,
|
|
];
|
|
for (const [name, cct] of getRecordEntries(CodingContractTypes)) {
|
|
if (skippedContractTypes.includes(name)) {
|
|
continue;
|
|
}
|
|
test(name, () => {
|
|
const state = cct.generate();
|
|
const data = cct.getData ? cct.getData(state) : state;
|
|
const answer = cct.getAnswer(data);
|
|
expect(answer).not.toBeNull();
|
|
expect(cct.solver(state, answer)).toStrictEqual(true);
|
|
});
|
|
}
|
|
});
|