beatoraja submit-course tests

This commit is contained in:
zkldi
2021-05-28 11:34:15 +01:00
parent 65f810db09
commit 68b7ce0b96
4 changed files with 299 additions and 12 deletions
@@ -178,7 +178,7 @@ t.test("#KtchiPBScoreToBeatorajaFormat", (t) => {
await db.scores.remove({ scoreID: "mock_lampPB" });
t.rejects(() => KtchiPBScoreToBeatorajaFormat(pbScore, gazerChart, 2), {
message: /User's PB on.*has no lampPB/u,
message: /User 1's PB on.*has no lampPB/u,
} as any);
t.end();
@@ -199,4 +199,277 @@ t.test("POST /ir/beatoraja/submit-score", (t) => {
t.end();
});
const courseScore = {
course: {
name: "GENOSIDE 2018 段位認定 発狂皆伝",
charts: [
{
md5: "cfad3baadce9e02c45021963453d7c94",
},
{
md5: "77d23be22b2370925c573d922276bce0",
},
{
md5: "188a99f74ab71804f2e360dcf484545c",
},
{
md5: "c46a81cb184f5a804c119930d6eba748",
},
],
constraint: ["MIRROR", "GAUGE_LR2", "LN"],
trophy: [{}, {}],
lntype: 0,
},
score: {
sha256: "",
lntype: 0,
player: "unknown",
clear: "Clear",
date: 0,
epg: 1334,
lpg: 788,
egr: 1634,
lgr: 382,
egd: 239,
lgd: 142,
ebd: 34,
lbd: 8,
epr: 0,
lpr: 93,
ems: 63,
lms: 74,
maxcombo: 225,
notes: 6005,
passnotes: 4654,
minbp: 1623,
option: 0,
assist: 0,
gauge: 0,
deviceType: "BM_CONTROLLER",
judgeAlgorithm: "Combo",
rule: "Beatoraja_7",
exscore: 6260,
},
};
t.test("POST /ir/beatoraja/submit-course", (t) => {
t.beforeEach(ResetDBState);
t.test("Should accept a valid clear", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(courseScore);
t.equal(res.status, 200);
t.equal(res.body.success, true);
t.equal(res.body.description, "Successfully updated class.");
t.end();
});
t.test("Should silently reject a fail", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(deepmerge(courseScore, { score: { clear: "Failed" } }));
t.equal(res.status, 200);
t.equal(res.body.success, true);
t.equal(res.body.description, "Class not updated.");
t.end();
});
t.test("Should reject scores with no charts", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(deepmerge(courseScore, { course: { charts: [] } }, { arrayMerge: (d, s) => s }));
t.equal(res.status, 400);
t.equal(res.body.success, false);
t.equal(res.body.description, "Invalid Course Submission.");
t.end();
});
t.test("Should reject scores with invalid chart documents", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(deepmerge(courseScore, { course: { charts: [1, 2, 3, 4] } }));
t.equal(res.status, 400);
t.equal(res.body.success, false);
t.equal(res.body.description, "Invalid Course Submission.");
t.end();
});
t.test("Should reject scores with too many chart documents", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(courseScore, {
course: { charts: [{ md5: "a" }, { md5: "a" }, { md5: "a" }, { md5: "a" }] },
})
);
t.equal(res.status, 400);
t.equal(res.body.success, false);
t.equal(res.body.description, "Invalid Course Submission.");
t.end();
});
t.test("Should reject scores not on LN mode", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(courseScore, {
score: {
lntype: 1,
},
})
);
t.equal(res.status, 400);
t.equal(res.body.success, false);
t.equal(res.body.description, "LN mode is the only supported mode for dans.");
t.end();
});
t.test("Should reject too few constraints", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
courseScore,
{
course: {
constraint: ["GAUGE_LR2"],
},
},
{ arrayMerge: (d, s) => s }
)
);
t.equal(res.status, 400);
t.equal(res.body.success, false);
t.equal(res.body.description, "Invalid Constraints.");
t.end();
});
t.test("Should reject non-array constraints", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
courseScore,
{
course: {
constraint: "foo",
},
},
{ arrayMerge: (d, s) => s }
)
);
t.equal(res.status, 400);
t.equal(res.body.success, false);
t.equal(res.body.description, "Invalid Constraints.");
t.end();
});
t.test("Should reject too many constraints", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
courseScore,
{
course: {
constraint: ["a", "b", "c", "d"],
},
},
{ arrayMerge: (d, s) => s }
)
);
t.equal(res.status, 400);
t.equal(res.body.success, false);
t.equal(res.body.description, "Invalid Constraints.");
t.end();
});
t.test("Should reject invalid constraints", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
courseScore,
{
course: {
constraint: ["foo", "bar"],
},
},
{ arrayMerge: (d, s) => s }
)
);
t.equal(res.status, 400);
t.equal(res.body.success, false);
t.equal(res.body.description, "Invalid Constraints.");
t.end();
});
t.test("Should reject invalid constraints for 3", async (t) => {
const res = await mockApi
.post("/ir/beatoraja/submit-course")
.set("X-KtchiIR-Version", "2.0.0")
.set("Authorization", "Bearer token")
.send(
deepmerge(
courseScore,
{
course: {
constraint: ["GAUGE_LR2", "MIRROR", "CHEAT_MODE"],
},
},
{ arrayMerge: (d, s) => s }
)
);
t.equal(res.status, 400);
t.equal(res.body.success, false);
t.equal(res.body.description, "Invalid Constraints.");
t.end();
});
t.end();
});
t.teardown(CloseAllConnections);
+16 -11
View File
@@ -141,7 +141,12 @@ router.post("/submit-score", async (req, res) => {
router.post("/submit-course", async (req, res) => {
const charts = req.body.course?.charts;
if (!charts || !Array.isArray(charts) || charts.length !== 4) {
if (
!charts ||
!Array.isArray(charts) ||
charts.length !== 4 ||
!charts.every((e) => e && typeof e === "object" && typeof e.md5 === "string")
) {
return res.status(400).json({
success: false,
description: `Invalid Course Submission.`,
@@ -166,8 +171,8 @@ router.post("/submit-course", async (req, res) => {
// Constraints are a bit complicated.
// We only want to accept dans with the following
// beatoraja constraints - ["MIRROR","LR2_GAUGE"] or
// ["MIRROR", "LR2_GAUGE", "LN"].
// beatoraja constraints - ["MIRROR","GAUGE_LR2"] or
// ["MIRROR", "GAUGE_LR2", "LN"].
const constraint = req.body.course.constraint;
if (
@@ -177,16 +182,16 @@ router.post("/submit-course", async (req, res) => {
) {
return res.status(400).json({
success: false,
description: `Invalid constraints.`,
description: `Invalid Constraints.`,
});
}
// If there are two constraints, check that they are
// MIRROR and LR2_GAUGE.
if (!constraint.includes("MIRROR") || !constraint.includes("LR2_GAUGE")) {
// MIRROR and GAUGE_LR2.
if (!constraint.includes("MIRROR") || !constraint.includes("GAUGE_LR2")) {
return res.status(400).json({
success: false,
description: `Invalid constraints.`,
description: `Invalid Constraints.`,
});
}
@@ -202,7 +207,7 @@ router.post("/submit-course", async (req, res) => {
}
// Combine the md5s into one string in their order.
const combinedMD5s = charts.map((e) => e.md5).join();
const combinedMD5s = charts.map((e) => e.md5).join("");
const course = await db["bms-course-lookup"].findOne({
md5sums: combinedMD5s,
@@ -225,10 +230,10 @@ router.post("/submit-course", async (req, res) => {
course.value
);
if (result) {
if (result === false) {
return res.status(200).json({
success: true,
description: "Successfully updated class.",
description: "Class not updated.",
body: {
set: course.set,
value: course.value,
@@ -238,7 +243,7 @@ router.post("/submit-course", async (req, res) => {
return res.status(200).json({
success: true,
description: "Class not updated.",
description: "Successfully updated class.",
body: {
set: course.set,
value: course.value,
@@ -0,0 +1,9 @@
[
{
"title": "GENOSIDE 2018 段位認定 Overjoy",
"md5sums": "cfad3baadce9e02c45021963453d7c9477d23be22b2370925c573d922276bce0188a99f74ab71804f2e360dcf484545cc46a81cb184f5a804c119930d6eba748",
"set": "genocideDan",
"playtype": "7K",
"value": 22
}
]