Improve some unrelated tests while we're here.

This commit is contained in:
zkldi
2022-01-19 16:22:28 +00:00
parent 003c41b870
commit d5f03b0d60
5 changed files with 247 additions and 42 deletions
@@ -18,6 +18,7 @@ t.test("#CreateCalculatedData", async (t) => {
const res = await CreateCalculatedData(TestingIIDXSPDryScore, Testing511SPA, 30, logger);
prAssert(
t,
res,
{
ktLampRating: p.equalTo(10),
@@ -34,6 +35,7 @@ t.test("#CreateCalculatedData", async (t) => {
);
prAssert(
t,
gitadoraRes,
{
skill: p.isPositiveNonZero,
@@ -82,6 +84,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
ktLampRating: "?number",
@@ -105,6 +108,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
ktLampRating: "?number",
@@ -127,6 +131,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
VF6: p.nullable(p.isPositive),
@@ -148,6 +153,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
MFCP: p.nullable(p.isPositiveInteger),
@@ -170,6 +176,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
MFCP: "null",
@@ -192,6 +199,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
rating: "?number",
@@ -213,6 +221,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
ktRating: "?number",
@@ -234,6 +243,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
ktRating: "?number",
@@ -255,6 +265,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
sieglinde: "?number",
@@ -276,6 +287,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
sieglinde: "?number",
@@ -297,6 +309,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
skill: "?number",
@@ -318,6 +331,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
skill: "?number",
@@ -339,6 +353,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
VF6: "?number",
@@ -360,6 +375,7 @@ t.test("#CalculateDataForGamePT", (t) => {
);
prAssert(
t,
res,
{
VF6: "?number",
@@ -380,7 +396,7 @@ t.test("#CalculateDataForGamePT", (t) => {
// logger
// );
// prAssert(
// prAssert(t ,
// res,
// {
// jubility: "?number",
@@ -402,7 +418,7 @@ t.test("#CalculateDataForGamePT", (t) => {
// logger
// );
// prAssert(res, {}, "Response should contain nulled keys for popn:9B");
// prAssert(t ,res, {}, "Response should contain nulled keys for popn:9B");
// t.end();
// });
@@ -29,23 +29,73 @@ t.test("#CalculateBPI", (t) => {
}
t.equal(AA_BPI(KAVG_AA), 0, "A score of KAVG should be exactly 0BPI");
isApproximately(AA_BPI(3393), 10.02, "A score with 3393 should be approximately 10.02BPI");
isApproximately(AA_BPI(3481), 20.09, "A score with 3481 should be approximately 20.09BPI");
isApproximately(AA_BPI(3535), 30.01, "A score with 3535 should be approximately 30.01BPI");
isApproximately(AA_BPI(3572), 40.18, "A score with 3572 should be approximately 40.18BPI");
isApproximately(AA_BPI(3597), 50.1, "A score with 3597 should be approximately 50.1BPI");
isApproximately(AA_BPI(3615), 60.12, "A score with 3615 should be approximately 60.12BPI");
isApproximately(AA_BPI(3628), 70.11, "A score with 3628 should be approximately 70.11BPI");
isApproximately(AA_BPI(3638), 80.62, "A score with 3638 should be approximately 80.62BPI");
isApproximately(AA_BPI(3645), 90.59, "A score with 3645 should be approximately 90.59BPI");
isApproximately(
t,
AA_BPI(3393),
10.02,
"A score with 3393 should be approximately 10.02BPI"
);
isApproximately(
t,
AA_BPI(3481),
20.09,
"A score with 3481 should be approximately 20.09BPI"
);
isApproximately(
t,
AA_BPI(3535),
30.01,
"A score with 3535 should be approximately 30.01BPI"
);
isApproximately(
t,
AA_BPI(3572),
40.18,
"A score with 3572 should be approximately 40.18BPI"
);
isApproximately(t, AA_BPI(3597), 50.1, "A score with 3597 should be approximately 50.1BPI");
isApproximately(
t,
AA_BPI(3615),
60.12,
"A score with 3615 should be approximately 60.12BPI"
);
isApproximately(
t,
AA_BPI(3628),
70.11,
"A score with 3628 should be approximately 70.11BPI"
);
isApproximately(
t,
AA_BPI(3638),
80.62,
"A score with 3638 should be approximately 80.62BPI"
);
isApproximately(
t,
AA_BPI(3645),
90.59,
"A score with 3645 should be approximately 90.59BPI"
);
t.equal(AA_BPI(WR_AA), 100, "A score of WR should be exactly 100BPI");
isApproximately(AA_BPI(3041), -5, "A score with 3628 should be approximately -5BPI");
isApproximately(AA_BPI(2886), -9.99, "A score with 3638 should be approximately -9.99BPI");
isApproximately(t, AA_BPI(3041), -5, "A score with 3628 should be approximately -5BPI");
isApproximately(
t,
AA_BPI(2886),
-9.99,
"A score with 3638 should be approximately -9.99BPI"
);
t.equal(AA_BPI(0), -15, "Excessively bad (vs kavg) scores should cap at -15BPI");
isApproximately(AA_BPI(MAX_AA), 244.56, "A score of MAX should be approximately 244.56BPI");
isApproximately(
t,
AA_BPI(MAX_AA),
244.56,
"A score of MAX should be approximately 244.56BPI"
);
t.end();
});
@@ -60,7 +110,7 @@ t.test("#CalculateBPI", (t) => {
return CalculateBPI(KAVG_CL, WR_AFT, yourEx, MAX_CL, COEF_CL);
}
isApproximately(CL_BPI(2307), 79.63);
isApproximately(t, CL_BPI(2307), 79.63);
t.end();
});
@@ -79,19 +129,65 @@ t.test("#CalculateBPI", (t) => {
}
t.equal(AFT_BPI(KAVG_AFT), 0, "A score of KAVG should be exactly 0BPI");
isApproximately(AFT_BPI(2606), 10, "A score with 2606 should be approximately 10BPI");
isApproximately(AFT_BPI(2675), 20.07, "A score with 2675 should be approximately 20.07BPI");
isApproximately(AFT_BPI(2727), 30.18, "A score with 2727 should be approximately 30.18BPI");
isApproximately(AFT_BPI(2767), 40.12, "A score with 2767 should be approximately 40.12BPI");
isApproximately(AFT_BPI(2799), 50.06, "A score with 2799 should be approximately 50.06BPI");
isApproximately(AFT_BPI(2826), 60.43, "A score with 2826 should be approximately 60.43BPI");
isApproximately(AFT_BPI(2847), 70.3, "A score with 2847 should be approximately 70.3BPI");
isApproximately(AFT_BPI(2865), 80.57, "A score with 2865 should be approximately 80.57BPI");
isApproximately(AFT_BPI(2879), 90.18, "A score with 2879 should be approximately 90.18BPI");
isApproximately(t, AFT_BPI(2606), 10, "A score with 2606 should be approximately 10BPI");
isApproximately(
t,
AFT_BPI(2675),
20.07,
"A score with 2675 should be approximately 20.07BPI"
);
isApproximately(
t,
AFT_BPI(2727),
30.18,
"A score with 2727 should be approximately 30.18BPI"
);
isApproximately(
t,
AFT_BPI(2767),
40.12,
"A score with 2767 should be approximately 40.12BPI"
);
isApproximately(
t,
AFT_BPI(2799),
50.06,
"A score with 2799 should be approximately 50.06BPI"
);
isApproximately(
t,
AFT_BPI(2826),
60.43,
"A score with 2826 should be approximately 60.43BPI"
);
isApproximately(
t,
AFT_BPI(2847),
70.3,
"A score with 2847 should be approximately 70.3BPI"
);
isApproximately(
t,
AFT_BPI(2865),
80.57,
"A score with 2865 should be approximately 80.57BPI"
);
isApproximately(
t,
AFT_BPI(2879),
90.18,
"A score with 2879 should be approximately 90.18BPI"
);
t.equal(AFT_BPI(WR_AFT), 100, "A score of WR should be exactly 100BPI");
isApproximately(AFT_BPI(2423), -4.99, "A score with 2423 should be approximately -4.99BPI");
isApproximately(
t,
AFT_BPI(2423),
-4.99,
"A score with 2423 should be approximately -4.99BPI"
);
isApproximately(
t,
AFT_BPI(2354),
-10.04,
"A score with 2354 should be approximately -10.04BPI"
@@ -100,6 +196,7 @@ t.test("#CalculateBPI", (t) => {
t.equal(AFT_BPI(0), -15, "Excessively bad (vs kavg) scores should cap at -15BPI");
isApproximately(
t,
AFT_BPI(MAX_AFT),
431.57,
"A score of MAX should be approximately 431.57BPI"
@@ -1,5 +1,8 @@
import { ChartDocument, Game } from "tachi-common";
import t from "tap";
import { GetGradeFromPercent } from "./score-utils";
import { isApproximately } from "test-utils/asserts";
import { Testing511SPA } from "test-utils/test-data";
import { GenericCalculatePercent, GetGradeFromPercent, ValidatePercent } from "./score-utils";
t.test("#GetGradeForPercent", (t) => {
t.equal(
@@ -31,3 +34,68 @@ t.test("#GetGradeForPercent", (t) => {
t.end();
});
t.test("#GenericCalculatePercent", (t) => {
const f = (game: Game, score: number, equal: number) =>
isApproximately(t, GenericCalculatePercent(game, score), equal);
for (const game of ["iidx", "bms", "pms"] as const) {
isApproximately(t, GenericCalculatePercent(game, 1240, Testing511SPA), 78.88);
isApproximately(t, GenericCalculatePercent(game, 0, Testing511SPA), 0);
}
f("popn", 100_000, 100);
f("popn", 50_000, 50);
f("popn", 0, 0);
f("maimai", 10, 10);
f("maimai", 101.12, 101.12);
for (const game of ["usc", "sdvx"] as const) {
f(game, 10_000_000, 100);
f(game, 5_000_000, 50);
f(game, 9_950_000, 99.5);
f(game, 1_370_000, 13.7);
f(game, 0, 0);
}
for (const game of ["ddr", "museca", "chunithm", "wacca"] as const) {
f(game, 1_000_000, 100);
f(game, 500_000, 50);
f(game, 993_121, 99.3121);
f(game, 1_000, 0.1);
}
t.throws(() => GenericCalculatePercent("unknown_game" as Game, 100), {
message: /Invalid game/u,
});
t.throws(() => GenericCalculatePercent("iidx", 100), {
message: /No Chart passed/u,
});
t.end();
});
t.test("#ValidatePercent", (t) => {
for (const playtype of ["SP", "DP"] as const) {
t.doesNotThrow(() => ValidatePercent("iidx", playtype, 90, Testing511SPA));
t.doesNotThrow(() => ValidatePercent("iidx", playtype, 0, Testing511SPA));
t.doesNotThrow(() => ValidatePercent("iidx", playtype, 100, Testing511SPA));
t.throws(() => ValidatePercent("iidx", playtype, -50, Testing511SPA));
t.throws(() => ValidatePercent("iidx", playtype, 101, Testing511SPA));
}
const m = (maxPercent: number) => ({ data: { maxPercent } } as ChartDocument);
t.doesNotThrow(() => ValidatePercent("maimai", "Single", 90, m(100)));
t.doesNotThrow(() => ValidatePercent("maimai", "Single", 100, m(100)));
t.doesNotThrow(() => ValidatePercent("maimai", "Single", 0, m(100)));
t.doesNotThrow(() => ValidatePercent("maimai", "Single", 110, m(120)));
t.doesNotThrow(() => ValidatePercent("maimai", "Single", 120, m(120)));
t.throws(() => ValidatePercent("maimai", "Single", 130, m(120)), {
message: /expected a number less than 120/u,
});
t.end();
});
@@ -58,23 +58,33 @@ export function GenericCalculatePercent(game: Game, score: number, chart?: Chart
return (score / 10_000_000) * 100;
case "popn":
return (score / 100_000) * 100;
case "gitadora":
case "maimai":
// score in maimai is actually just your percent, since nobody cares about
// money score.
return score;
case "bms":
case "pms":
case "iidx":
if (!chart) {
logger.severe("No Chart passed to GenericCalcPercent but game was iidx/bms.");
logger.severe("No Chart passed to GenericCalcPercent but game was iidx/bms/pms.");
throw new InternalFailure(
"No Chart passed to GenericCalcPercent but game was iidx/bms."
"No Chart passed to GenericCalcPercent but game was iidx/bms/pms."
);
}
// Yeah, we declare it like this so the below return is actually clear.
// eslint-disable-next-line no-case-declarations
const MAX =
(chart as ChartDocument<"iidx:SP" | "bms:7K" | "bms:14K" | "iidx:DP">).data
.notecount * 2;
(
chart as ChartDocument<
| "iidx:SP"
| "bms:7K"
| "bms:14K"
| "pms:Controller"
| "pms:Keyboard"
| "iidx:DP"
>
).data.notecount * 2;
return (100 * score) / MAX;
default:
@@ -100,16 +110,22 @@ export function ValidatePercent(
const mmChart = chart as ChartDocument<"maimai:Single">;
if (percent > mmChart.data.maxPercent) {
throw new InvalidScoreFailure(
`Invalid percent - expected less than ${mmChart.data.maxPercent}.`
`Invalid percent - expected a number less than ${mmChart.data.maxPercent}.`
);
}
} else {
const gptConfig = GetGamePTConfig(game, playtype);
if (percent > gptConfig.percentMax) {
throw new InvalidScoreFailure(
`Invalid percent of ${percent} - expected a value less than ${gptConfig.percentMax}% (${chart.songID} ${chart.playtype} ${chart.difficulty}).`
);
}
}
const gptConfig = GetGamePTConfig(game, playtype);
if (percent > gptConfig.percentMax) {
if (percent < 0) {
throw new InvalidScoreFailure(
`Invalid percent of ${percent} - expected a value less than ${gptConfig.percentMax}% (${chart.songID} ${chart.playtype} ${chart.difficulty}).`
`Invalid percent of ${percent} - Expected a positive number? (${chart.songID} ${chart.playtype} ${chart.difficulty})`
);
}
}
+14 -6
View File
@@ -1,18 +1,26 @@
import { rootLogger } from "lib/logger/logger";
import Prudence, { PrudenceSchema } from "prudence";
import t from "tap";
export function isApproximately(number: number, target: number, message?: string, lenience = 0.01) {
const result = t.ok(Math.abs(number - target) < lenience, message);
export function isApproximately(
t: Tap.Test,
number: number,
target: number,
message?: string,
lenience = 0.01
) {
const result = Math.abs(number - target) < lenience;
if (!result) {
rootLogger.error(`${number} was not close enough to ${target}`);
return t.fail(`${number} was not close enough to ${target}`, {
errmsg: `${number} was not close enough to ${target}`,
});
}
t.pass(message);
// return true;
}
export function prAssert(
t: Tap.Test,
obj: Record<string, unknown> | unknown,
schema: PrudenceSchema,
message = "Unnamed Prudence Assertion"