ir/usc tests

This commit is contained in:
zkldi
2021-05-27 18:52:17 +01:00
parent 0d20a90df0
commit 80beae4056
6 changed files with 251 additions and 16 deletions
+23 -12
View File
@@ -22,15 +22,18 @@
"plugin:import/errors"
],
"rules": {
"prettier/prettier": ["error", {
"printWidth": 100,
"tabWidth": 4,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"endOfLine": "auto"
}],
"prettier/prettier": [
"error",
{
"printWidth": 100,
"tabWidth": 4,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"endOfLine": "auto"
}
],
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"require-await": "warn",
@@ -42,7 +45,10 @@
"no-eval": "error",
"no-var": "error",
"no-new-object": "error",
"quote-props": ["error", "as-needed"],
"quote-props": [
"error",
"as-needed"
],
"no-array-constructor": "error",
"prefer-template": "error",
"prefer-promise-reject-errors": "error",
@@ -73,9 +79,14 @@
"no-throw-literal": "error",
"no-unmodified-loop-condition": "error",
"no-unused-expressions": "error",
// "no-unused-vars": [
// "warn",
// {
// "match": "logger"
// }
// ],
"no-useless-call": "error",
"no-useless-return": "error",
"require-unicode-regexp": "error",
"require-unicode-regexp": "error"
}
}
@@ -0,0 +1,125 @@
import t from "tap";
import db, { CloseMongoConnection } from "../../../../../external/mongo/db";
import { ConverterIRUSC, DeriveLamp, DeriveNoteMod } from "./converter";
import d from "deepmerge";
import { uscChart, uscScore } from "../../../../../test-utils/test-data";
import CreateLogCtx from "../../../../logger/logger";
import ResetDBState from "../../../../../test-utils/reset-db-state";
import { USCClientScore } from "../../../../../server/router/ir/usc/usc";
const logger = CreateLogCtx(__filename);
t.test("#DeriveLamp", (t) => {
t.equal(DeriveLamp(uscScore, logger), "EXCESSIVE CLEAR");
t.equal(DeriveLamp(d(uscScore, { options: { gaugeType: 0 }, gauge: 50 }), logger), "FAILED");
t.equal(DeriveLamp(d(uscScore, { options: { gaugeType: 0 }, gauge: 70 }), logger), "CLEAR");
t.equal(
DeriveLamp(d(uscScore, { options: { gaugeType: 1 }, gauge: 0.1 }), logger),
"EXCESSIVE CLEAR"
);
t.equal(DeriveLamp(d(uscScore, { options: { gaugeType: 1 }, gauge: 0 }), logger), "FAILED");
t.equal(
DeriveLamp(
d(uscScore, { score: 10_000_000, options: { gaugeType: 1 }, gauge: 0.1 }),
logger
),
"PERFECT ULTIMATE CHAIN"
);
// error: 0 should not take priority over score 10million
t.equal(
DeriveLamp(
d(uscScore, {
score: 10_000_000,
options: { gaugeType: 1 },
gauge: 0.1,
error: 0,
}),
logger
),
"PERFECT ULTIMATE CHAIN"
);
t.equal(
DeriveLamp(
d(uscScore, {
score: 9_000_000,
options: { gaugeType: 0 },
gauge: 15,
error: 0,
}),
logger
),
"ULTIMATE CHAIN"
);
t.throws(() => DeriveLamp(d(uscScore, { options: { gaugeType: 2 } }), logger));
t.end();
});
t.test("#DeriveNoteMod", (t) => {
t.equal(DeriveNoteMod(uscScore), "MIRROR");
t.equal(DeriveNoteMod(d(uscScore, { options: { random: true } })), "MIR-RAN");
t.equal(DeriveNoteMod(d(uscScore, { options: { random: false, mirror: false } })), "NORMAL");
t.equal(DeriveNoteMod(d(uscScore, { options: { random: true, mirror: false } })), "RANDOM");
t.end();
});
const dm = (p: Partial<USCClientScore> | any) =>
ConverterIRUSC(d(uscScore, p), { chart: uscChart }, "ir/usc", logger);
t.test("#ConverterIRUSC", (t) => {
t.beforeEach(ResetDBState);
t.test("Should convert a score", async (t) => {
const res = await dm({});
t.hasStrict(res, {
song: {
id: 1,
},
chart: {
chartID: uscChart.chartID,
},
dryScore: {},
} as any);
t.end();
});
t.test("Should reject scores with invalid hit windows", (t) => {
t.rejects(dm({ windows: { perfect: 0 } }));
t.rejects(dm({ windows: { good: 0 } }));
t.rejects(dm({ windows: { hold: 0 } }));
t.rejects(dm({ windows: { miss: 0 } }));
t.rejects(dm({ windows: { slam: 0 } }));
t.end();
});
t.test("Should reject scores with invalid autoflags", (t) => {
t.rejects(dm({ options: { autoFlags: 1 } }));
t.end();
});
t.test("Should throw an InternalFailure on song-chart desync", async (t) => {
await db.songs.usc.remove({});
t.rejects(dm({}));
t.end();
});
t.end();
});
t.teardown(CloseMongoConnection);
@@ -5,7 +5,7 @@ import { InternalFailure, InvalidScoreFailure } from "../../../framework/common/
import { GenericGetGradeAndPercent } from "../../../framework/common/score-utils";
import { IRUSCContext } from "./types";
import { Lamps } from "kamaitachi-common";
import uuid from "uuid";
import { v4 as UUIDv4 } from "uuid";
import { ConverterFunction } from "../../common/types";
import { DryScore } from "../../../framework/common/types";
import {
@@ -16,7 +16,10 @@ import {
USC_DEFAULT_SLAM,
} from "../../../../constants/usc-ir";
function DeriveNoteMod(data: USCClientScore): "NORMAL" | "MIRROR" | "RANDOM" | "MIR-RAN" {
/**
* Interprets the "note mod" used based on the USC score.
*/
export function DeriveNoteMod(data: USCClientScore): "NORMAL" | "MIRROR" | "RANDOM" | "MIR-RAN" {
if (data.options.mirror && data.options.random) {
return "MIR-RAN";
} else if (data.options.mirror) {
@@ -28,7 +31,10 @@ function DeriveNoteMod(data: USCClientScore): "NORMAL" | "MIRROR" | "RANDOM" | "
return "NORMAL";
}
function DeriveLamp(scoreDoc: USCClientScore, logger: KtLogger): Lamps["usc:Single"] {
/**
* Determines the lamp of a USC score.
*/
export function DeriveLamp(scoreDoc: USCClientScore, logger: KtLogger): Lamps["usc:Single"] {
if (scoreDoc.score === 10_000_000) {
return "PERFECT ULTIMATE CHAIN";
} else if (scoreDoc.error === 0) {
@@ -98,7 +104,7 @@ export const ConverterIRUSC: ConverterFunction<USCClientScore, IRUSCContext> = a
scoreMeta: {
gaugeMod: data.options.gaugeOpt === 0 ? "NORMAL" : "HARD",
noteMod: DeriveNoteMod(data),
replayID: uuid.v4(),
replayID: UUIDv4(),
},
};
@@ -0,0 +1,31 @@
import t from "tap";
import { CloseMongoConnection } from "../../../../../external/mongo/db";
import { uscChart, uscScore } from "../../../../../test-utils/test-data";
import CreateLogCtx from "../../../../logger/logger";
import { ParseIRUSC } from "./parser";
const logger = CreateLogCtx(__filename);
t.test("#ParseIRUSC", (t) => {
t.test("Should validate and convert a score into an iterable", (t) => {
const res = ParseIRUSC(
({ score: uscScore } as unknown) as Record<string, unknown>,
uscChart,
logger
);
t.hasStrict(res, {
game: "usc",
context: {
chart: uscChart,
},
iterable: [uscScore],
} as any);
t.end();
});
t.end();
});
t.teardown(CloseMongoConnection);
@@ -0,0 +1,13 @@
[
{
"title": "ALBIDA Powerless Mix",
"artist": "無力P",
"id": 1,
"firstVersion": null,
"alt-titles": [],
"search-titles": [],
"data": {
"sdvxEquiv": null
}
}
]
+49
View File
@@ -11,8 +11,16 @@ import {
} from "kamaitachi-common";
import path from "path";
import db from "../external/mongo/db";
import {
USC_DEFAULT_HOLD,
USC_DEFAULT_MISS,
USC_DEFAULT_NEAR,
USC_DEFAULT_PERFECT,
USC_DEFAULT_SLAM,
} from "../lib/constants/usc-ir";
import { DryScore } from "../lib/score-import/framework/common/types";
import { BarbatosScore } from "../lib/score-import/import-types/ir/barbatos/types";
import { USCClientScore } from "../server/router/ir/usc/usc";
const file = (name: string) => path.join(__dirname, "/test-data", name);
@@ -184,3 +192,44 @@ export const barbScore: BarbatosScore = {
score: 9_000_000,
song_id: 1,
};
export const uscChart: ChartDocument<"usc:Single"> = {
rgcID: null,
chartID: "USC_CHART_ID",
difficulty: "NOV",
songID: 1,
playtype: "Single",
levelNum: 1,
level: "1",
flags: {
CUSTOM: true,
},
data: {
hashSHA256: "USC_CHART_HASH",
},
isPrimary: true,
versions: [],
};
export const uscScore: USCClientScore = {
crit: 100,
error: 5,
near: 50,
gauge: 80,
options: {
autoFlags: 0,
gaugeOpt: 0,
gaugeType: 1,
mirror: true,
random: false,
},
score: 9_000_000,
timestamp: 0,
windows: {
good: USC_DEFAULT_NEAR,
perfect: USC_DEFAULT_PERFECT,
hold: USC_DEFAULT_HOLD,
miss: USC_DEFAULT_MISS,
slam: USC_DEFAULT_SLAM,
},
};