Added Dynamic RAM calculation unit tests

This commit is contained in:
danielyxie 2019-05-10 02:24:50 -07:00
parent db5fdb1fcb
commit 9dd68947f1
9 changed files with 1436 additions and 22 deletions

6
.gitignore vendored

@ -3,6 +3,6 @@ Netburner.txt
/doc/build /doc/build
/node_modules /node_modules
/dist/*.map /dist/*.map
/tests/*.map /test/*.map
/tests/*.bundle.* /test/*.bundle.*
/tests/*.css /test/*.css

@ -76,7 +76,7 @@ export class WorkerScript {
output: string = ""; output: string = "";
/** /**
* Script's RAM usage. Equivalent to underlying script's RAM usage * Script's Static RAM usage. Equivalent to underlying script's RAM usage
*/ */
ramUsage: number = 0; ramUsage: number = 0;

@ -4346,7 +4346,7 @@ function NetscriptFunctions(workerScript) {
if (Player.bitNodeN !== 10 && !SourceFileFlags[10]) { if (Player.bitNodeN !== 10 && !SourceFileFlags[10]) {
throw makeRuntimeRejectMsg(workerScript, "getStats() failed because you do not currently have access to the Sleeve API. This is either because you are not in BitNode-10 or because you do not have Source-File 10"); throw makeRuntimeRejectMsg(workerScript, "getStats() failed because you do not currently have access to the Sleeve API. This is either because you are not in BitNode-10 or because you do not have Source-File 10");
} }
updateDynamicRam("workoutAtGym", getRamCost("sleeve", "getSleeveStats")); updateDynamicRam("getSleeveStats", getRamCost("sleeve", "getSleeveStats"));
if (sleeveNumber >= Player.sleeves.length || sleeveNumber < 0) { if (sleeveNumber >= Player.sleeves.length || sleeveNumber < 0) {
workerScript.log(`ERROR: sleeve.workoutAtGym(${sleeveNumber}) failed because it is an invalid sleeve number.`); workerScript.log(`ERROR: sleeve.workoutAtGym(${sleeveNumber}) failed because it is an invalid sleeve number.`);
return false; return false;

@ -359,21 +359,24 @@ export function hasProgram(programName) {
export function setMoney(money) { export function setMoney(money) {
if (isNaN(money)) { if (isNaN(money)) {
console.log("ERR: NaN passed into Player.setMoney()"); return; console.error("NaN passed into Player.setMoney()");
return;
} }
this.money = money; this.money = new Decimal(money);
} }
export function gainMoney(money) { export function gainMoney(money) {
if (isNaN(money)) { if (isNaN(money)) {
console.log("ERR: NaN passed into Player.gainMoney()"); return; console.error("NaN passed into Player.gainMoney()");
return;
} }
this.money = this.money.plus(money); this.money = this.money.plus(money);
} }
export function loseMoney(money) { export function loseMoney(money) {
if (isNaN(money)) { if (isNaN(money)) {
console.log("ERR: NaN passed into Player.loseMoney()"); return; console.error("NaN passed into Player.loseMoney()");
return;
} }
this.money = this.money.minus(money); this.money = this.money.minus(money);
} }

@ -97,7 +97,7 @@ function prestigeAugmentation() {
} }
if (augmentationExists(AugmentationNames.CashRoot) && if (augmentationExists(AugmentationNames.CashRoot) &&
Augmentations[AugmentationNames.CashRoot].owned) { Augmentations[AugmentationNames.CashRoot].owned) {
Player.setMoney(new Decimal(1000000)); Player.setMoney(1e6);
homeComp.programs.push(Programs.BruteSSHProgram.name); homeComp.programs.push(Programs.BruteSSHProgram.name);
} }

File diff suppressed because it is too large Load Diff

@ -10,7 +10,7 @@ const HacknetNamespaceCost = RamCostConstants.ScriptHacknetNodesRamCost;
describe("Netscript Static RAM Calculation/Generation Tests", function() { describe("Netscript Static RAM Calculation/Generation Tests", function() {
// Tests numeric equality, allowing for floating point imprecision // Tests numeric equality, allowing for floating point imprecision
function testEquality(val, expected) { function testEquality(val, expected) {
expect(val).to.be.within(expected - 10 * Number.EPSILON, expected + 10 * Number.EPSILON); expect(val).to.be.within(expected - 100 * Number.EPSILON, expected + 100 * Number.EPSILON);
} }
/** /**

@ -1,4 +1,11 @@
import { CONSTANTS } from "../src/Constants"; import { CONSTANTS } from "../src/Constants";
import { Player } from "../src/Player";
import {
buyStock,
sellStock,
shortStock,
sellShort,
} from "../src/StockMarket/BuyingAndSelling";
import { Order } from "../src/StockMarket/Order"; import { Order } from "../src/StockMarket/Order";
import { processOrders } from "../src/StockMarket/OrderProcessing"; import { processOrders } from "../src/StockMarket/OrderProcessing";
import { Stock } from "../src/StockMarket/Stock"; import { Stock } from "../src/StockMarket/Stock";
@ -7,6 +14,7 @@ import {
initStockMarket, initStockMarket,
initSymbolToStockMap, initSymbolToStockMap,
loadStockMarket, loadStockMarket,
processStockPrices,
StockMarket, StockMarket,
SymbolToStockMap, SymbolToStockMap,
} from "../src/StockMarket/StockMarket"; } from "../src/StockMarket/StockMarket";
@ -22,8 +30,6 @@ import {
import { OrderTypes } from "../src/StockMarket/data/OrderTypes" import { OrderTypes } from "../src/StockMarket/data/OrderTypes"
import { PositionTypes } from "../src/StockMarket/data/PositionTypes"; import { PositionTypes } from "../src/StockMarket/data/PositionTypes";
//const assert = chai.assert;
//const expect = chai.expect;
import { expect } from "chai"; import { expect } from "chai";
console.log("Beginning Stock Market Tests"); console.log("Beginning Stock Market Tests");
@ -192,7 +198,9 @@ describe("Stock Market Tests", function() {
it("should have properties for managing game cycles", function() { it("should have properties for managing game cycles", function() {
expect(StockMarket).to.have.property("storedCycles"); expect(StockMarket).to.have.property("storedCycles");
expect(StockMarket["storedCycles"]).to.equal(0);
expect(StockMarket).to.have.property("lastUpdate"); expect(StockMarket).to.have.property("lastUpdate");
expect(StockMarket["lastUpdate"]).to.equal(0);
}); });
}); });
@ -206,15 +214,59 @@ describe("Stock Market Tests", function() {
}); });
}); });
// Reset stock market for each test describe("processStockPrices()", function() {
beforeEach(function() { before(function() {
deleteStockMarket(); deleteStockMarket();
initStockMarket(); initStockMarket();
initSymbolToStockMap(); initSymbolToStockMap();
}); });
it("should properly initialize", function() { it("should store cycles until it actually processes", function() {
expect(StockMarket["storedCycles"]).to.equal(0);
processStockPrices(10);
expect(StockMarket["storedCycles"]).to.equal(10);
});
it("should trigger a price update when it has enough cycles", function() {
// Get the initial prices
const initialValues = {};
for (const stockName in StockMarket) {
const stock = StockMarket[stockName];
if (!(stock instanceof Stock)) { continue; }
initialValues[stock.symbol] = {
price: stock.price,
otlkMag: stock.otlkMag,
}
}
// Don't know or care how many exact cycles are required
processStockPrices(1e9);
// Both price and 'otlkMag' should be different
for (const stockName in StockMarket) {
const stock = StockMarket[stockName];
if (!(stock instanceof Stock)) { continue; }
expect(initialValues[stock.symbol].price).to.not.equal(stock.price);
expect(initialValues[stock.symbol].otlkMag).to.not.equal(stock.otlkMag);
}
});
});
});
describe("StockToSymbolMap", function() {
before(function() {
deleteStockMarket();
initStockMarket();
initSymbolToStockMap();
});
it("should map stock symbols to their corresponding Stock Objects", function() {
for (const stockName in StockMarket) {
const stock = StockMarket[stockName];
if (!(stock instanceof Stock)) { continue; }
expect(SymbolToStockMap[stock.symbol]).to.equal(stock);
}
}); });
}); });
@ -637,6 +689,190 @@ describe("Stock Market Tests", function() {
}); });
}); });
describe("Transaction (Buy/Sell) Functions", function() {
const suppressDialogOpt = { suppressDialog: true };
describe("buyStock()", function() {
it("should fail for invalid arguments", function() {
expect(buyStock({}, 1, null, suppressDialogOpt)).to.equal(false);
expect(buyStock(stock, 0, null, suppressDialogOpt)).to.equal(false);
expect(buyStock(stock, -1, null, suppressDialogOpt)).to.equal(false);
expect(buyStock(stock, NaN, null, suppressDialogOpt)).to.equal(false);
});
it("should fail if player doesn't have enough money", function() {
Player.setMoney(0);
expect(buyStock(stock, 1, null, suppressDialogOpt)).to.equal(false);
});
it("should not allow for transactions that exceed the maximum shares", function() {
const maxShares = stock.maxShares;
expect(buyStock(stock, maxShares + 1, null, suppressDialogOpt)).to.equal(false);
});
it("should return true and properly update stock properties for successful transactions", function() {
const shares = 1e3;
const cost = getBuyTransactionCost(stock, shares, PositionTypes.Long);
Player.setMoney(cost);
expect(buyStock(stock, shares, null, suppressDialogOpt)).to.equal(true);
expect(stock.playerShares).to.equal(shares);
expect(stock.playerAvgPx).to.be.above(0);
expect(Player.money.toNumber()).to.equal(0);
});
});
describe("sellStock()", function() {
it("should fail for invalid arguments", function() {
expect(sellStock({}, 1, null, suppressDialogOpt)).to.equal(false);
expect(sellStock(stock, 0, null, suppressDialogOpt)).to.equal(false);
expect(sellStock(stock, -1, null, suppressDialogOpt)).to.equal(false);
expect(sellStock(stock, NaN, null, suppressDialogOpt)).to.equal(false);
});
it("should fail if player doesn't have any shares", function() {
Player.setMoney(0);
expect(sellStock(stock, 1, null, suppressDialogOpt)).to.equal(false);
});
it("should not allow for transactions that exceed the maximum shares", function() {
const maxShares = stock.maxShares;
expect(sellStock(stock, maxShares + 1, null, suppressDialogOpt)).to.equal(false);
});
it("should return true and properly update stock properties for successful transactions", function() {
const shares = 1e3;
stock.playerShares = shares;
stock.playerAvgPx = stock.price;
const gain = getSellTransactionGain(stock, shares, PositionTypes.Long);
Player.setMoney(0);
expect(sellStock(stock, shares, null, suppressDialogOpt)).to.equal(true);
expect(stock.playerShares).to.equal(0);
expect(stock.playerAvgPx).to.equal(0);
expect(Player.money.toNumber()).to.equal(gain);
});
it("should cap the number of sharse sold to however many the player owns", function() {
const attemptedShares = 2e3;
const actualShares = 1e3;
stock.playerShares = actualShares;
stock.playerAvgPx = stock.price;
const gain = getSellTransactionGain(stock, actualShares, PositionTypes.Long);
Player.setMoney(0);
expect(sellStock(stock, attemptedShares, null, suppressDialogOpt)).to.equal(true);
expect(stock.playerShares).to.equal(0);
expect(stock.playerAvgPx).to.equal(0);
expect(Player.money.toNumber()).to.equal(gain);
});
it("should properly update stock properties for partial transactions", function() {
const shares = 1e3;
const origPrice = stock.price;
stock.playerShares = 2 * shares;
stock.playerAvgPx = origPrice;
const gain = getSellTransactionGain(stock, shares, PositionTypes.Long);
Player.setMoney(0);
expect(sellStock(stock, shares, null, suppressDialogOpt)).to.equal(true);
expect(stock.playerShares).to.equal(shares);
expect(stock.playerAvgPx).to.equal(origPrice);
expect(Player.money.toNumber()).to.equal(gain);
});
});
describe("shortStock()", function() {
it("should fail for invalid arguments", function() {
expect(shortStock({}, 1, null, suppressDialogOpt)).to.equal(false);
expect(shortStock(stock, 0, null, suppressDialogOpt)).to.equal(false);
expect(shortStock(stock, -1, null, suppressDialogOpt)).to.equal(false);
expect(shortStock(stock, NaN, null, suppressDialogOpt)).to.equal(false);
});
it("should fail if player doesn't have enough money", function() {
Player.setMoney(0);
expect(shortStock(stock, 1, null, suppressDialogOpt)).to.equal(false);
});
it("should not allow for transactions that exceed the maximum shares", function() {
const maxShares = stock.maxShares;
expect(shortStock(stock, maxShares + 1, null, suppressDialogOpt)).to.equal(false);
});
it("should return true and properly update stock properties for successful transactions", function() {
const shares = 1e3;
const cost = getBuyTransactionCost(stock, shares, PositionTypes.Short);
Player.setMoney(cost);
expect(shortStock(stock, shares, null, suppressDialogOpt)).to.equal(true);
expect(stock.playerShortShares).to.equal(shares);
expect(stock.playerAvgShortPx).to.be.above(0);
expect(Player.money.toNumber()).to.equal(0);
});
});
describe("sellShort()", function() {
it("should fail for invalid arguments", function() {
expect(sellShort({}, 1, null, suppressDialogOpt)).to.equal(false);
expect(sellShort(stock, 0, null, suppressDialogOpt)).to.equal(false);
expect(sellShort(stock, -1, null, suppressDialogOpt)).to.equal(false);
expect(sellShort(stock, NaN, null, suppressDialogOpt)).to.equal(false);
});
it("should fail if player doesn't have any shares", function() {
Player.setMoney(0);
expect(sellShort(stock, 1, null, suppressDialogOpt)).to.equal(false);
});
it("should not allow for transactions that exceed the maximum shares", function() {
const maxShares = stock.maxShares;
expect(sellShort(stock, maxShares + 1, null, suppressDialogOpt)).to.equal(false);
});
it("should return true and properly update stock properties for successful transactions", function() {
const shares = 1e3;
stock.playerShortShares = shares;
stock.playerAvgShortPx = stock.price;
const gain = getSellTransactionGain(stock, shares, PositionTypes.Short);
Player.setMoney(0);
expect(sellShort(stock, shares, null, suppressDialogOpt)).to.equal(true);
expect(stock.playerShortShares).to.equal(0);
expect(stock.playerAvgShortPx).to.equal(0);
expect(Player.money.toNumber()).to.equal(gain);
});
it("should cap the number of sharse sold to however many the player owns", function() {
const attemptedShares = 2e3;
const actualShares = 1e3;
stock.playerShortShares = actualShares;
stock.playerAvgShortPx = stock.price;
const gain = getSellTransactionGain(stock, actualShares, PositionTypes.Short);
Player.setMoney(0);
expect(sellShort(stock, attemptedShares, null, suppressDialogOpt)).to.equal(true);
expect(stock.playerShortShares).to.equal(0);
expect(stock.playerAvgShortPx).to.equal(0);
expect(Player.money.toNumber()).to.equal(gain);
});
it("should properly update stock properties for partial transactions", function() {
const shares = 1e3;
const origPrice = stock.price;
stock.playerShortShares = 2 * shares;
stock.playerAvgShortPx = origPrice;
const gain = getSellTransactionGain(stock, shares, PositionTypes.Short);
Player.setMoney(0);
expect(sellShort(stock, shares, null, suppressDialogOpt)).to.equal(true);
expect(stock.playerShortShares).to.equal(shares);
expect(stock.playerAvgShortPx).to.equal(origPrice);
expect(Player.money.toNumber()).to.equal(gain);
});
});
});
describe("Order Class", function() { describe("Order Class", function() {
it("should throw on invalid arguments", function() { it("should throw on invalid arguments", function() {
function invalid1() { function invalid1() {

@ -1,3 +1,3 @@
// export * from "./Netscript/DynamicRamCalculationTests"; export * from "./Netscript/DynamicRamCalculationTests";
export * from "./Netscript/StaticRamCalculationTests"; export * from "./Netscript/StaticRamCalculationTests";
export * from "./StockMarketTests"; export * from "./StockMarketTests";