import { NetscriptFunctions } from "../../src/NetscriptFunctions";
import { getRamCost, RamCostConstants } from "../../src/Netscript/RamCostGenerator";
import { Environment } from "../../src/Netscript/Environment";
import { RunningScript } from "../../src/Script/RunningScript";
import { Script } from "../../src/Script/Script";
import { SourceFileFlags } from "../../src/SourceFile/SourceFileFlags";

import { expect } from "chai";

console.log("Beginning Netscript Dynamic RAM Calculation/Generation Tests");

console.log("Beginning Netscript Static RAM Calculation/Generation Tests");

const ScriptBaseCost = RamCostConstants.ScriptBaseRamCost;

describe("Netscript Dynamic RAM Calculation/Generation Tests", function() {
    // Creates a mock RunningScript object
    async function createRunningScript(code) {
        const script = new Script();
        script.code = code;
        await script.updateRamUsage([]);

        const runningScript = new RunningScript(script);

        return runningScript;
    }

    // Tests numeric equality, allowing for floating point imprecision
    function testEquality(val, expected) {
        expect(val).to.be.within(expected - 100 * Number.EPSILON, expected + 100 * Number.EPSILON);
    }

    // Runs a Netscript function and properly catches it if it returns promise
    function runPotentiallyAsyncFunction(fn) {
        let res = fn();
        if (res instanceof Promise) {
            res.catch(() => undefined);
        }
    }

    /**
     * Tests that:
     *      1. A function has non-zero RAM cost
     *      2. Running the function properly updates the MockWorkerScript's dynamic RAM calculation
     *      3. Running multiple calls of the function does not result in additional RAM cost
     * @param {string[]} fnDesc - describes the name of the function being tested,
     *                            including the namespace(s). e.g. ["gang", "getMemberNames"]
     */
    async function testNonzeroDynamicRamCost(fnDesc) {
        if (!Array.isArray(fnDesc)) { expect.fail("Non-array passed to testNonzeroDynamicRamCost()"); }
        const expected = getRamCost(...fnDesc);
        expect(expected).to.be.above(0);

        const code = `${fnDesc.join(".")}();`

        const runningScript = await createRunningScript(code);

        // We don't need a real WorkerScript
        const workerScript = {
            args: [],
            code: code,
            dynamicLoadedFns: {},
            dynamicRamUsage: RamCostConstants.ScriptBaseRamCost,
            env: new Environment(null),
            ramUsage: runningScript.ramUsage,
            scriptRef: runningScript,
        }
        workerScript.env.vars = NetscriptFunctions(workerScript);

        // Run the function through the workerscript's args
        const scope = workerScript.env.vars;
        let curr = scope[fnDesc[0]];
        for (let i = 1; i < fnDesc.length; ++i) {
            if (curr == null) {
                expect.fail(`Invalid function specified: [${fnDesc}]`);
            }

            if (typeof curr === "function") {
                break;
            }

            curr = curr[fnDesc[i]];
        }

        if (typeof curr === "function") {
            // We use a try/catch because the function will probably fail since the game isn't
            // actually initialized. Call the fn multiple times to test that repeated calls
            // do not incur extra RAM costs.
            try {
                runPotentiallyAsyncFunction(curr);
                runPotentiallyAsyncFunction(curr);
                runPotentiallyAsyncFunction(curr);
            } catch(e) {}
        } else {
            expect.fail(`Invalid function specified: [${fndesc}]`);
        }

        const fnName = fnDesc[fnDesc.length - 1];
        testEquality(workerScript.dynamicRamUsage - ScriptBaseCost, expected);
        testEquality(workerScript.dynamicRamUsage, runningScript.ramUsage);
        expect(workerScript.dynamicLoadedFns).to.have.property(fnName);
    }

    /**
     * Tests that:
     *      1. A function has zero RAM cost
     *      2. Running the function does NOT update the MockWorkerScript's dynamic RAM calculation
     *      3. Running multiple calls of the function does not result in dynamic RAM calculation
     * @param {string[]} fnDesc - describes the name of the function being tested,
     *                            including the namespace(s). e.g. ["gang", "getMemberNames"]
     */
    async function testZeroDynamicRamCost(fnDesc) {
        if (!Array.isArray(fnDesc)) { expect.fail("Non-array passed to testZeroDynamicRamCost()"); }
        const expected = getRamCost(...fnDesc);
        expect(expected).to.equal(0);

        const code = `${fnDesc.join(".")}();`

        const runningScript = await createRunningScript(code);

        // We don't need a real WorkerScript
        const workerScript = {
            args: [],
            code: code,
            dynamicLoadedFns: {},
            dynamicRamUsage: RamCostConstants.ScriptBaseRamCost,
            env: new Environment(null),
            ramUsage: runningScript.ramUsage,
            scriptRef: runningScript,
        }
        workerScript.env.vars = NetscriptFunctions(workerScript);

        // Run the function through the workerscript's args
        const scope = workerScript.env.vars;
        let curr = scope[fnDesc[0]];
        for (let i = 1; i < fnDesc.length; ++i) {
            if (curr == null) {
                expect.fail(`Invalid function specified: [${fnDesc}]`);
            }

            if (typeof curr === "function") {
                break;
            }

            curr = curr[fnDesc[i]];
        }

        if (typeof curr === "function") {
            // We use a try/catch because the function will probably fail since the game isn't
            // actually initialized. Call the fn multiple times to test that repeated calls
            // do not incur extra RAM costs.
            try {
                runPotentiallyAsyncFunction(curr);
                runPotentiallyAsyncFunction(curr);
                runPotentiallyAsyncFunction(curr);
            } catch(e) {}
        } else {
            expect.fail(`Invalid function specified: [${fndesc}]`);
        }

        testEquality(workerScript.dynamicRamUsage, ScriptBaseCost);
        testEquality(workerScript.dynamicRamUsage, runningScript.ramUsage);
    }

    before(function() {
        for (let i = 0; i < SourceFileFlags.length; ++i) {
            SourceFileFlags[i] = 3;
        }
    });

    describe("Basic Functions", async function() {
        it("hack()", async function() {
            const f = ["hack"];
            await testNonzeroDynamicRamCost(f);
        });

        it("grow()", async function() {
            const f = ["grow"];
            await testNonzeroDynamicRamCost(f);
        });

        it("weaken()", async function() {
            const f = ["weaken"];
            await testNonzeroDynamicRamCost(f);
        });

        it("hackAnalyzeThreads()", async function() {
            const f = ["hackAnalyzeThreads"];
            await testNonzeroDynamicRamCost(f);
        });

        it("hackAnalyzePercent()", async function() {
            const f = ["hackAnalyzePercent"];
            await testNonzeroDynamicRamCost(f);
        });

        it("hackChance()", async function() {
            const f = ["hackChance"];
            await testNonzeroDynamicRamCost(f);
        });

        it("growthAnalyze()", async function() {
            const f = ["growthAnalyze"];
            await testNonzeroDynamicRamCost(f);
        });

        it("sleep()", async function() {
            const f = ["sleep"];
            await testZeroDynamicRamCost(f);
        });

        it("print()", async function() {
            const f = ["print"];
            await testZeroDynamicRamCost(f);
        });

        it("tprint()", async function() {
            const f = ["tprint"];
            await testZeroDynamicRamCost(f);
        });

        it("clearLog()", async function() {
            const f = ["clearLog"];
            await testZeroDynamicRamCost(f);
        });

        it("disableLog()", async function() {
            const f = ["disableLog"];
            await testZeroDynamicRamCost(f);
        });

        it("enableLog()", async function() {
            const f = ["enableLog"];
            await testZeroDynamicRamCost(f);
        });

        it("isLogEnabled()", async function() {
            const f = ["isLogEnabled"];
            await testZeroDynamicRamCost(f);
        });

        it("getScriptLogs()", async function() {
            const f = ["getScriptLogs"];
            await testZeroDynamicRamCost(f);
        });

        it("scan()", async function() {
            const f = ["scan"];
            await testNonzeroDynamicRamCost(f);
        });

        it("nuke()", async function() {
            const f = ["nuke"];
            await testNonzeroDynamicRamCost(f);
        });

        it("brutessh()", async function() {
            const f = ["brutessh"];
            await testNonzeroDynamicRamCost(f);
        });

        it("ftpcrack()", async function() {
            const f = ["ftpcrack"];
            await testNonzeroDynamicRamCost(f);
        });

        it("relaysmtp()", async function() {
            const f = ["relaysmtp"];
            await testNonzeroDynamicRamCost(f);
        });

        it("httpworm()", async function() {
            const f = ["httpworm"];
            await testNonzeroDynamicRamCost(f);
        });

        it("sqlinject()", async function() {
            const f = ["sqlinject"];
            await testNonzeroDynamicRamCost(f);
        });

        it("run()", async function() {
            const f = ["run"];
            await testNonzeroDynamicRamCost(f);
        });

        it("exec()", async function() {
            const f = ["exec"];
            await testNonzeroDynamicRamCost(f);
        });

        it("spawn()", async function() {
            const f = ["spawn"];
            await testNonzeroDynamicRamCost(f);
        });

        it("kill()", async function() {
            const f = ["kill"];
            await testNonzeroDynamicRamCost(f);
        });

        it("killall()", async function() {
            const f = ["killall"];
            await testNonzeroDynamicRamCost(f);
        });

        it("exit()", async function() {
            const f = ["exit"];
            await testZeroDynamicRamCost(f);
        });

        it("scp()", async function() {
            const f = ["scp"];
            await testNonzeroDynamicRamCost(f);
        });

        it("ls()", async function() {
            const f = ["ls"];
            await testNonzeroDynamicRamCost(f);
        });

        it("ps()", async function() {
            const f = ["ps"];
            await testNonzeroDynamicRamCost(f);
        });

        it("hasRootAccess()", async function() {
            const f = ["hasRootAccess"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getHostname()", async function() {
            const f = ["getHostname"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getHackingLevel()", async function() {
            const f = ["getHackingLevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getHackingMultipliers()", async function() {
            const f = ["getHackingMultipliers"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getHacknetMultipliers()", async function() {
            const f = ["getHacknetMultipliers"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerMoneyAvailable()", async function() {
            const f = ["getServerMoneyAvailable"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerMaxMoney()", async function() {
            const f = ["getServerMaxMoney"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerGrowth()", async function() {
            const f = ["getServerGrowth"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerSecurityLevel()", async function() {
            const f = ["getServerSecurityLevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerBaseSecurityLevel()", async function() {
            const f = ["getServerBaseSecurityLevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerMinSecurityLevel()", async function() {
            const f = ["getServerMinSecurityLevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerRequiredHackingLevel()", async function() {
            const f = ["getServerRequiredHackingLevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerNumPortsRequired()", async function() {
            const f = ["getServerNumPortsRequired"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerRam()", async function() {
            const f = ["getServerRam"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerMaxRam()", async function() {
            const f = ["getServerMaxRam"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getServerUsedRam()", async function() {
            const f = ["getServerUsedRam"];
            await testNonzeroDynamicRamCost(f);
        });

        it("serverExists()", async function() {
            const f = ["serverExists"];
            await testNonzeroDynamicRamCost(f);
        });

        it("fileExists()", async function() {
            const f = ["fileExists"];
            await testNonzeroDynamicRamCost(f);
        });

        it("isRunning()", async function() {
            const f = ["isRunning"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getPurchasedServerCost()", async function() {
            const f = ["getPurchasedServerCost"];
            await testNonzeroDynamicRamCost(f);
        });

        it("purchaseServer()", async function() {
            const f = ["purchaseServer"];
            await testNonzeroDynamicRamCost(f);
        });

        it("deleteServer()", async function() {
            const f = ["deleteServer"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getPurchasedServers()", async function() {
            const f = ["getPurchasedServers"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getPurchasedServerLimit()", async function() {
            const f = ["getPurchasedServerLimit"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getPurchasedServerMaxRam()", async function() {
            const f = ["getPurchasedServerMaxRam"];
            await testNonzeroDynamicRamCost(f);
        });

        it("write()", async function() {
            const f = ["write"];
            await testNonzeroDynamicRamCost(f);
        });

        it("tryWrite()", async function() {
            const f = ["tryWrite"];
            await testNonzeroDynamicRamCost(f);
        });

        it("read()", async function() {
            const f = ["read"];
            await testNonzeroDynamicRamCost(f);
        });

        it("peek()", async function() {
            const f = ["peek"];
            await testNonzeroDynamicRamCost(f);
        });

        it("clear()", async function() {
            const f = ["clear"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getPortHandle()", async function() {
            const f = ["getPortHandle"];
            await testNonzeroDynamicRamCost(f);
        });

        it("rm()", async function() {
            const f = ["rm"];
            await testNonzeroDynamicRamCost(f);
        });

        it("scriptRunning()", async function() {
            const f = ["scriptRunning"];
            await testNonzeroDynamicRamCost(f);
        });

        it("scriptKill()", async function() {
            const f = ["scriptKill"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getScriptName()", async function() {
            const f = ["getScriptName"];
            await testZeroDynamicRamCost(f);
        });

        it("getScriptRam()", async function() {
            const f = ["getScriptRam"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getHackTime()", async function() {
            const f = ["getHackTime"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getGrowTime()", async function() {
            const f = ["getGrowTime"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getWeakenTime()", async function() {
            const f = ["getWeakenTime"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getScriptIncome()", async function() {
            const f = ["getScriptIncome"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getScriptExpGain()", async function() {
            const f = ["getScriptExpGain"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getRunningScript()", async function() {
            const f = ["getRunningScript"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getTimeSinceLastAug()", async function() {
            const f = ["getTimeSinceLastAug"];
            await testNonzeroDynamicRamCost(f);
        });

        it("sprintf()", async function() {
            const f = ["sprintf"];
            await testZeroDynamicRamCost(f);
        });

        it("vsprintf()", async function() {
            const f = ["vsprintf"];
            await testZeroDynamicRamCost(f);
        });

        it("nFormat()", async function() {
            const f = ["nFormat"];
            await testZeroDynamicRamCost(f);
        });

        it("prompt()", async function() {
            const f = ["prompt"];
            await testZeroDynamicRamCost(f);
        });

        it("wget()", async function() {
            const f = ["wget"];
            await testZeroDynamicRamCost(f);
        });

        it("getFavorToDonate()", async function() {
            const f = ["getFavorToDonate"];
            await testNonzeroDynamicRamCost(f);
        });
    });

    describe("Advanced Functions", async function() {
        it("getBitNodeMultipliers()", async function() {
            const f = ["getBitNodeMultipliers"];
            await testNonzeroDynamicRamCost(f);
        });
    });

    describe("TIX API", async function() {
        it("getStockSymbols()", async function() {
            const f = ["getStockSymbols"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getStockPrice()", async function() {
            const f = ["getStockPrice"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getStockAskPrice()", async function() {
            const f = ["getStockAskPrice"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getStockBidPrice()", async function() {
            const f = ["getStockBidPrice"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getStockPosition()", async function() {
            const f = ["getStockPosition"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getStockMaxShares()", async function() {
            const f = ["getStockMaxShares"];
            await testNonzeroDynamicRamCost(f);
        });

        it("buyStock()", async function() {
            const f = ["buyStock"];
            await testNonzeroDynamicRamCost(f);
        });

        it("sellStock()", async function() {
            const f = ["sellStock"];
            await testNonzeroDynamicRamCost(f);
        });

        it("shortStock()", async function() {
            const f = ["shortStock"];
            await testNonzeroDynamicRamCost(f);
        });

        it("sellShort()", async function() {
            const f = ["sellShort"];
            await testNonzeroDynamicRamCost(f);
        });

        it("placeOrder()", async function() {
            const f = ["placeOrder"];
            await testNonzeroDynamicRamCost(f);
        });

        it("cancelOrder()", async function() {
            const f = ["cancelOrder"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getOrders()", async function() {
            const f = ["getOrders"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getStockVolatility()", async function() {
            const f = ["getStockVolatility"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getStockForecast()", async function() {
            const f = ["getStockForecast"];
            await testNonzeroDynamicRamCost(f);
        });

        it("purchase4SMarketData()", async function() {
            const f = ["purchase4SMarketData"];
            await testNonzeroDynamicRamCost(f);
        });

        it("purchase4SMarketDataTixApi()", async function() {
            const f = ["purchase4SMarketDataTixApi"];
            await testNonzeroDynamicRamCost(f);
        });
    });

    describe("Singularity Functions", async function() {
        it("universityCourse()", async function() {
            const f = ["universityCourse"];
            await testNonzeroDynamicRamCost(f);
        });

        it("gymWorkout()", async function() {
            const f = ["gymWorkout"];
            await testNonzeroDynamicRamCost(f);
        });

        it("travelToCity()", async function() {
            const f = ["travelToCity"];
            await testNonzeroDynamicRamCost(f);
        });

        it("purchaseTor()", async function() {
            const f = ["purchaseTor"];
            await testNonzeroDynamicRamCost(f);
        });

        it("purchaseProgram()", async function() {
            const f = ["purchaseProgram"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getStats()", async function() {
            const f = ["getStats"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCharacterInformation()", async function() {
            const f = ["getCharacterInformation"];
            await testNonzeroDynamicRamCost(f);
        });

        it("isBusy()", async function() {
            const f = ["isBusy"];
            await testNonzeroDynamicRamCost(f);
        });

        it("stopAction()", async function() {
            const f = ["stopAction"];
            await testNonzeroDynamicRamCost(f);
        });

        it("upgradeHomeRam()", async function() {
            const f = ["upgradeHomeRam"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getUpgradeHomeRamCost()", async function() {
            const f = ["getUpgradeHomeRamCost"];
            await testNonzeroDynamicRamCost(f);
        });

        it("workForCompany()", async function() {
            const f = ["workForCompany"];
            await testNonzeroDynamicRamCost(f);
        });

        it("applyToCompany()", async function() {
            const f = ["applyToCompany"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCompanyRep()", async function() {
            const f = ["getCompanyRep"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCompanyFavor()", async function() {
            const f = ["getCompanyFavor"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCompanyFavorGain()", async function() {
            const f = ["getCompanyFavorGain"];
            await testNonzeroDynamicRamCost(f);
        });

        it("checkFactionInvitations()", async function() {
            const f = ["checkFactionInvitations"];
            await testNonzeroDynamicRamCost(f);
        });

        it("joinFaction()", async function() {
            const f = ["joinFaction"];
            await testNonzeroDynamicRamCost(f);
        });

        it("workForFaction()", async function() {
            const f = ["workForFaction"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getFactionRep()", async function() {
            const f = ["getFactionRep"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getFactionFavor()", async function() {
            const f = ["getFactionFavor"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getFactionFavorGain()", async function() {
            const f = ["getFactionFavorGain"];
            await testNonzeroDynamicRamCost(f);
        });

        it("donateToFaction()", async function() {
            const f = ["donateToFaction"];
            await testNonzeroDynamicRamCost(f);
        });

        it("createProgram()", async function() {
            const f = ["createProgram"];
            await testNonzeroDynamicRamCost(f);
        });

        it("commitCrime()", async function() {
            const f = ["commitCrime"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCrimeChance()", async function() {
            const f = ["getCrimeChance"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getOwnedAugmentations()", async function() {
            const f = ["getOwnedAugmentations"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getOwnedSourceFiles()", async function() {
            const f = ["getOwnedSourceFiles"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getAugmentationsFromFaction()", async function() {
            const f = ["getAugmentationsFromFaction"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getAugmentationPrereq()", async function() {
            const f = ["getAugmentationPrereq"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getAugmentationCost()", async function() {
            const f = ["getAugmentationCost"];
            await testNonzeroDynamicRamCost(f);
        });

        it("purchaseAugmentation()", async function() {
            const f = ["purchaseAugmentation"];
            await testNonzeroDynamicRamCost(f);
        });

        it("installAugmentations()", async function() {
            const f = ["installAugmentations"];
            await testNonzeroDynamicRamCost(f);
        });
    });

    describe("Bladeburner API", async function() {
        it("getContractNames()", async function() {
            const f = ["bladeburner", "getContractNames"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getOperationNames()", async function() {
            const f = ["bladeburner", "getOperationNames"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getBlackOpNames()", async function() {
            const f = ["bladeburner", "getBlackOpNames"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getGeneralActionNames()", async function() {
            const f = ["bladeburner", "getGeneralActionNames"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getSkillNames()", async function() {
            const f = ["bladeburner", "getSkillNames"];
            await testNonzeroDynamicRamCost(f);
        });

        it("startAction()", async function() {
            const f = ["bladeburner", "startAction"];
            await testNonzeroDynamicRamCost(f);
        });

        it("stopBladeburnerAction()", async function() {
            const f = ["bladeburner", "stopBladeburnerAction"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCurrentAction()", async function() {
            const f = ["bladeburner", "getCurrentAction"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getActionTime()", async function() {
            const f = ["bladeburner", "getActionTime"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getActionEstimatedSuccessChance()", async function() {
            const f = ["bladeburner", "getActionEstimatedSuccessChance"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getActionRepGain()", async function() {
            const f = ["bladeburner", "getActionRepGain"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getActionCountRemaining()", async function() {
            const f = ["bladeburner", "getActionCountRemaining"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getActionMaxLevel()", async function() {
            const f = ["bladeburner", "getActionMaxLevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getActionCurrentLevel()", async function() {
            const f = ["bladeburner", "getActionCurrentLevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getActionAutolevel()", async function() {
            const f = ["bladeburner", "getActionAutolevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setActionAutolevel()", async function() {
            const f = ["bladeburner", "setActionAutolevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setActionLevel()", async function() {
            const f = ["bladeburner", "setActionLevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getRank()", async function() {
            const f = ["bladeburner", "getRank"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getBlackOpRank()", async function() {
            const f = ["bladeburner", "getBlackOpRank"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getSkillPoints()", async function() {
            const f = ["bladeburner", "getSkillPoints"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getSkillLevel()", async function() {
            const f = ["bladeburner", "getSkillLevel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getSkillUpgradeCost()", async function() {
            const f = ["bladeburner", "getSkillUpgradeCost"];
            await testNonzeroDynamicRamCost(f);
        });

        it("upgradeSkill()", async function() {
            const f = ["bladeburner", "upgradeSkill"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getTeamSize()", async function() {
            const f = ["bladeburner", "getTeamSize"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setTeamSize()", async function() {
            const f = ["bladeburner", "setTeamSize"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCityEstimatedPopulation()", async function() {
            const f = ["bladeburner", "getCityEstimatedPopulation"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCityEstimatedCommunities()", async function() {
            const f = ["bladeburner", "getCityEstimatedCommunities"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCityChaos()", async function() {
            const f = ["bladeburner", "getCityChaos"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getCity()", async function() {
            const f = ["bladeburner", "getCity"];
            await testNonzeroDynamicRamCost(f);
        });

        it("switchCity()", async function() {
            const f = ["bladeburner", "switchCity"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getStamina()", async function() {
            const f = ["bladeburner", "getStamina"];
            await testNonzeroDynamicRamCost(f);
        });

        it("joinBladeburnerFaction()", async function() {
            const f = ["bladeburner", "joinBladeburnerFaction"];
            await testNonzeroDynamicRamCost(f);
        });

        it("joinBladeburnerDivision()", async function() {
            const f = ["bladeburner", "joinBladeburnerDivision"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getBonusTime()", async function() {
            const f = ["bladeburner", "getBonusTime"];
            await testZeroDynamicRamCost(f);
        });
    });

    describe("Gang API", async function() {
        it("getMemberNames()", async function() {
            const f = ["gang", "getMemberNames"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getGangInformation()", async function() {
            const f = ["gang", "getGangInformation"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getOtherGangInformation()", async function() {
            const f = ["gang", "getOtherGangInformation"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getMemberInformation()", async function() {
            const f = ["gang", "getMemberInformation"];
            await testNonzeroDynamicRamCost(f);
        });

        it("canRecruitMember()", async function() {
            const f = ["gang", "canRecruitMember"];
            await testNonzeroDynamicRamCost(f);
        });

        it("recruitMember()", async function() {
            const f = ["gang", "recruitMember"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getTaskNames()", async function() {
            const f = ["gang", "getTaskNames"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setMemberTask()", async function() {
            const f = ["gang", "setMemberTask"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getEquipmentNames()", async function() {
            const f = ["gang", "getEquipmentNames"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getEquipmentCost()", async function() {
            const f = ["gang", "getEquipmentCost"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getEquipmentType()", async function() {
            const f = ["gang", "getEquipmentType"];
            await testNonzeroDynamicRamCost(f);
        });

        it("purchaseEquipment()", async function() {
            const f = ["gang", "purchaseEquipment"];
            await testNonzeroDynamicRamCost(f);
        });

        it("ascendMember()", async function() {
            const f = ["gang", "ascendMember"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setTerritoryWarfare()", async function() {
            const f = ["gang", "setTerritoryWarfare"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getChanceToWinClash()", async function() {
            const f = ["gang", "getChanceToWinClash"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getBonusTime()", async function() {
            const f = ["gang", "getBonusTime"];
            await testZeroDynamicRamCost(f);
        });
    });

    describe("Coding Contract API", async function() {
        it("attempt()", async function() {
            const f = ["codingcontract", "attempt"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getContractType()", async function() {
            const f = ["codingcontract", "getContractType"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getDescription()", async function() {
            const f = ["codingcontract", "getDescription"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getData()", async function() {
            const f = ["codingcontract", "getData"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getNumTriesRemaining()", async function() {
            const f = ["codingcontract", "getNumTriesRemaining"];
            await testNonzeroDynamicRamCost(f);
        });
    });

    describe("Sleeve API", async function() {
        it("getNumSleeves()", async function() {
            const f = ["sleeve", "getNumSleeves"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getSleeveStats()", async function() {
            const f = ["sleeve", "getSleeveStats"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getInformation()", async function() {
            const f = ["sleeve", "getInformation"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getTask()", async function() {
            const f = ["sleeve", "getTask"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setToShockRecovery()", async function() {
            const f = ["sleeve", "setToShockRecovery"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setToSynchronize()", async function() {
            const f = ["sleeve", "setToSynchronize"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setToCommitCrime()", async function() {
            const f = ["sleeve", "setToCommitCrime"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setToFactionWork()", async function() {
            const f = ["sleeve", "setToFactionWork"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setToCompanyWork()", async function() {
            const f = ["sleeve", "setToCompanyWork"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setToUniversityCourse()", async function() {
            const f = ["sleeve", "setToUniversityCourse"];
            await testNonzeroDynamicRamCost(f);
        });

        it("setToGymWorkout()", async function() {
            const f = ["sleeve", "setToGymWorkout"];
            await testNonzeroDynamicRamCost(f);
        });

        it("travel()", async function() {
            const f = ["sleeve", "travel"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getSleeveAugmentations()", async function() {
            const f = ["sleeve", "getSleeveAugmentations"];
            await testNonzeroDynamicRamCost(f);
        });

        it("getSleevePurchasableAugs()", async function() {
            const f = ["sleeve", "getSleevePurchasableAugs"];
            await testNonzeroDynamicRamCost(f);
        });

        it("purchaseSleeveAug()", async function() {
            const f = ["sleeve", "purchaseSleeveAug"];
            await testNonzeroDynamicRamCost(f);
        });
    });
});