Skip to content

Commit 212b8d3

Browse files
fehmerMiodec
andauthored
refactor: make funbox settings an array (@fehmer) (#6487)
change funbox from "hash separated values" to array. --------- Co-authored-by: Miodec <jack@monkeytype.com>
1 parent b36bc9f commit 212b8d3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+497
-471
lines changed

backend/__tests__/api/controllers/result.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ describe("result controller test", () => {
626626
...result,
627627
difficulty: "normal",
628628
language: "english",
629-
funbox: "none",
629+
funbox: [],
630630
lazyMode: false,
631631
punctuation: false,
632632
numbers: false,
@@ -707,7 +707,7 @@ describe("result controller test", () => {
707707
chartData: { wpm: [1, 2, 3], raw: [50, 55, 56], err: [0, 2, 0] },
708708
consistency: 23.5,
709709
difficulty: "normal",
710-
funbox: "none",
710+
funbox: [],
711711
hash: "hash",
712712
incompleteTestSeconds: 2,
713713
incompleteTests: [{ acc: 75, seconds: 10 }],
@@ -831,7 +831,7 @@ describe("result controller test", () => {
831831
chartData: { wpm: [1, 2, 3], raw: [50, 55, 56], err: [0, 2, 0] },
832832
consistency: 23.5,
833833
difficulty: "normal",
834-
funbox: "none",
834+
funbox: [],
835835
hash: "hash",
836836
incompleteTestSeconds: 2,
837837
incompleteTests: [{ acc: 75, seconds: 10 }],

backend/__tests__/dal/result.spec.ts

Lines changed: 129 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@ import { ObjectId } from "mongodb";
33
import * as UserDal from "../../src/dal/user";
44
import { DBResult } from "../../src/utils/result";
55

6-
let uid: string = "";
6+
let uid: string;
77
const timestamp = Date.now() - 60000;
88

99
async function createDummyData(
1010
uid: string,
1111
count: number,
12-
timestamp: number,
13-
tag?: string
12+
modify?: Partial<DBResult>
1413
): Promise<void> {
1514
const dummyUser: UserDal.DBUser = {
1615
_id: new ObjectId(),
@@ -28,51 +27,53 @@ async function createDummyData(
2827
};
2928

3029
vi.spyOn(UserDal, "getUser").mockResolvedValue(dummyUser);
31-
const tags: string[] = [];
32-
if (tag !== undefined) tags.push(tag);
30+
3331
for (let i = 0; i < count; i++) {
3432
await ResultDal.addResult(uid, {
35-
_id: new ObjectId(),
36-
wpm: i,
37-
rawWpm: i,
38-
charStats: [0, 0, 0, 0],
39-
acc: 0,
40-
mode: "time",
41-
mode2: "10" as never,
42-
quoteLength: 1,
43-
timestamp,
44-
restartCount: 0,
45-
incompleteTestSeconds: 0,
46-
incompleteTests: [],
47-
testDuration: 10,
48-
afkDuration: 0,
49-
tags,
50-
consistency: 100,
51-
keyConsistency: 100,
52-
chartData: { wpm: [], raw: [], err: [] },
53-
uid,
54-
keySpacingStats: { average: 0, sd: 0 },
55-
keyDurationStats: { average: 0, sd: 0 },
56-
difficulty: "normal",
57-
language: "english",
58-
isPb: false,
59-
name: "Test",
60-
} as DBResult);
33+
...{
34+
_id: new ObjectId(),
35+
wpm: i,
36+
rawWpm: i,
37+
charStats: [0, 0, 0, 0],
38+
acc: 0,
39+
mode: "time",
40+
mode2: "10" as never,
41+
quoteLength: 1,
42+
timestamp,
43+
restartCount: 0,
44+
incompleteTestSeconds: 0,
45+
incompleteTests: [],
46+
testDuration: 10,
47+
afkDuration: 0,
48+
tags: [],
49+
consistency: 100,
50+
keyConsistency: 100,
51+
chartData: { wpm: [], raw: [], err: [] },
52+
uid,
53+
keySpacingStats: { average: 0, sd: 0 },
54+
keyDurationStats: { average: 0, sd: 0 },
55+
difficulty: "normal",
56+
language: "english",
57+
isPb: false,
58+
name: "Test",
59+
funbox: ["58008", "read_ahead"],
60+
},
61+
...modify,
62+
});
6163
}
6264
}
6365
describe("ResultDal", () => {
66+
beforeEach(() => {
67+
uid = new ObjectId().toHexString();
68+
});
69+
afterEach(async () => {
70+
if (uid) await ResultDal.deleteAll(uid);
71+
});
6472
describe("getResults", () => {
65-
beforeEach(() => {
66-
uid = new ObjectId().toHexString();
67-
});
68-
afterEach(async () => {
69-
if (uid) await ResultDal.deleteAll(uid);
70-
});
71-
7273
it("should read lastest 10 results ordered by timestamp", async () => {
7374
//GIVEN
74-
await createDummyData(uid, 10, timestamp - 2000, "old");
75-
await createDummyData(uid, 20, timestamp, "current");
75+
await createDummyData(uid, 10, { timestamp: timestamp - 2000 });
76+
await createDummyData(uid, 20, { tags: ["current"] });
7677

7778
//WHEN
7879
const results = await ResultDal.getResults(uid, { limit: 10 });
@@ -88,8 +89,8 @@ describe("ResultDal", () => {
8889
});
8990
it("should read all if not limited", async () => {
9091
//GIVEN
91-
await createDummyData(uid, 10, timestamp - 2000, "old");
92-
await createDummyData(uid, 20, timestamp, "current");
92+
await createDummyData(uid, 10, { timestamp: timestamp - 2000 });
93+
await createDummyData(uid, 20);
9394

9495
//WHEN
9596
const results = await ResultDal.getResults(uid, {});
@@ -99,8 +100,8 @@ describe("ResultDal", () => {
99100
});
100101
it("should read results onOrAfterTimestamp", async () => {
101102
//GIVEN
102-
await createDummyData(uid, 10, timestamp - 2000, "old");
103-
await createDummyData(uid, 20, timestamp, "current");
103+
await createDummyData(uid, 10, { timestamp: timestamp - 2000 });
104+
await createDummyData(uid, 20, { tags: ["current"] });
104105

105106
//WHEN
106107
const results = await ResultDal.getResults(uid, {
@@ -115,8 +116,11 @@ describe("ResultDal", () => {
115116
});
116117
it("should read next 10 results", async () => {
117118
//GIVEN
118-
await createDummyData(uid, 10, timestamp - 2000, "old");
119-
await createDummyData(uid, 20, timestamp, "current");
119+
await createDummyData(uid, 10, {
120+
timestamp: timestamp - 2000,
121+
tags: ["old"],
122+
});
123+
await createDummyData(uid, 20);
120124

121125
//WHEN
122126
const results = await ResultDal.getResults(uid, {
@@ -130,5 +134,84 @@ describe("ResultDal", () => {
130134
expect(it.tags).toContain("old");
131135
});
132136
});
137+
it("should convert legacy values", async () => {
138+
//GIVEN
139+
await createDummyData(uid, 1, { funbox: "58008#read_ahead" as any });
140+
141+
//WHEN
142+
const results = await ResultDal.getResults(uid);
143+
144+
//THEN
145+
expect(results[0]?.funbox).toEqual(["58008", "read_ahead"]);
146+
});
147+
});
148+
describe("getResult", () => {
149+
it("should convert legacy values", async () => {
150+
//GIVEN
151+
await createDummyData(uid, 1, { funbox: "58008#read_ahead" as any });
152+
const resultId = (await ResultDal.getLastResult(uid))._id.toHexString();
153+
154+
//WHEN
155+
const result = await ResultDal.getResult(uid, resultId);
156+
157+
//THEN
158+
expect(result?.funbox).toEqual(["58008", "read_ahead"]);
159+
});
160+
});
161+
describe("getLastResult", () => {
162+
it("should convert legacy values", async () => {
163+
//GIVEN
164+
await createDummyData(uid, 1, { funbox: "58008#read_ahead" as any });
165+
166+
//WHEN
167+
const result = await ResultDal.getLastResult(uid);
168+
169+
//THEN
170+
expect(result?.funbox).toEqual(["58008", "read_ahead"]);
171+
});
172+
});
173+
describe("getResultByTimestamp", () => {
174+
it("should convert legacy values", async () => {
175+
//GIVEN
176+
await createDummyData(uid, 1, { funbox: "58008#read_ahead" as any });
177+
178+
//WHEN
179+
const result = await ResultDal.getResultByTimestamp(uid, timestamp);
180+
181+
//THEN
182+
expect(result?.funbox).toEqual(["58008", "read_ahead"]);
183+
});
184+
});
185+
describe("converts legacy values", () => {
186+
it("should convert funbox as string", async () => {
187+
//GIVEN
188+
await createDummyData(uid, 1, { funbox: "58008#read_ahead" as any });
189+
190+
//WHEN
191+
const read = await ResultDal.getLastResult(uid);
192+
193+
//THEN
194+
expect(read.funbox).toEqual(["58008", "read_ahead"]);
195+
});
196+
it("should convert funbox 'none'", async () => {
197+
//GIVEN
198+
await createDummyData(uid, 1, { funbox: "none" as any });
199+
200+
//WHEN
201+
const read = await ResultDal.getLastResult(uid);
202+
203+
//THEN
204+
expect(read.funbox).toEqual([]);
205+
});
206+
it("should not convert funbox as array", async () => {
207+
//GIVEN
208+
await createDummyData(uid, 1, { funbox: ["58008", "read_ahead"] });
209+
210+
//WHEN
211+
const read = await ResultDal.getLastResult(uid);
212+
213+
//THEN
214+
expect(read.funbox).toEqual(["58008", "read_ahead"]);
215+
});
133216
});
134217
});

backend/__tests__/utils/pb.spec.ts

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,33 @@ import _ from "lodash";
22
import * as pb from "../../src/utils/pb";
33
import { Mode, PersonalBests } from "@monkeytype/contracts/schemas/shared";
44
import { Result } from "@monkeytype/contracts/schemas/results";
5+
import { FunboxName } from "@monkeytype/contracts/schemas/configs";
56

67
describe("Pb Utils", () => {
78
it("funboxCatGetPb", () => {
8-
const testCases = [
9-
{
10-
funbox: "plus_one",
11-
expected: true,
12-
},
13-
{
14-
funbox: "none",
15-
expected: true,
16-
},
17-
{
18-
funbox: "nausea#plus_one",
19-
expected: true,
20-
},
21-
{
22-
funbox: "arrows",
23-
expected: false,
24-
},
25-
];
9+
const testCases: { funbox: FunboxName[] | undefined; expected: boolean }[] =
10+
[
11+
{
12+
funbox: ["plus_one"],
13+
expected: true,
14+
},
15+
{
16+
funbox: [],
17+
expected: true,
18+
},
19+
{
20+
funbox: undefined,
21+
expected: true,
22+
},
23+
{
24+
funbox: ["nausea", "plus_one"],
25+
expected: true,
26+
},
27+
{
28+
funbox: ["arrows"],
29+
expected: false,
30+
},
31+
];
2632

2733
_.each(testCases, (testCase) => {
2834
const { funbox, expected } = testCase;

backend/src/api/controllers/result.ts

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,7 @@ import {
5858
getStartOfDayTimestamp,
5959
} from "@monkeytype/util/date-and-time";
6060
import { MonkeyRequest } from "../types";
61-
import {
62-
getFunbox,
63-
checkCompatibility,
64-
stringToFunboxNames,
65-
} from "@monkeytype/funbox";
61+
import { getFunbox, checkCompatibility } from "@monkeytype/funbox";
6662
import { tryCatch } from "@monkeytype/util/trycatch";
6763

6864
try {
@@ -175,8 +171,8 @@ export async function updateTags(
175171
if (!(result.language ?? "")) {
176172
result.language = "english";
177173
}
178-
if (!(result.funbox ?? "")) {
179-
result.funbox = "none";
174+
if (result.funbox === undefined) {
175+
result.funbox = [];
180176
}
181177
if (!result.lazyMode) {
182178
result.lazyMode = false;
@@ -242,16 +238,11 @@ export async function addResult(
242238
Logger.warning("Object hash check is disabled, skipping hash check");
243239
}
244240

245-
if (completedEvent.funbox) {
246-
const funboxes = completedEvent.funbox.split("#");
247-
if (funboxes.length !== _.uniq(funboxes).length) {
248-
throw new MonkeyError(400, "Duplicate funboxes");
249-
}
241+
if (completedEvent.funbox.length !== _.uniq(completedEvent.funbox).length) {
242+
throw new MonkeyError(400, "Duplicate funboxes");
250243
}
251244

252-
const funboxNames = stringToFunboxNames(completedEvent.funbox ?? "");
253-
254-
if (!checkCompatibility(funboxNames)) {
245+
if (!checkCompatibility(completedEvent.funbox)) {
255246
throw new MonkeyError(400, "Impossible funbox combination");
256247
}
257248

@@ -732,15 +723,12 @@ async function calculateXp(
732723
}
733724
}
734725

735-
if (funboxBonusConfiguration > 0 && resultFunboxes !== "none") {
736-
const funboxModifier = _.sumBy(
737-
stringToFunboxNames(resultFunboxes),
738-
(funboxName) => {
739-
const funbox = getFunbox(funboxName);
740-
const difficultyLevel = funbox?.difficultyLevel ?? 0;
741-
return Math.max(difficultyLevel * funboxBonusConfiguration, 0);
742-
}
743-
);
726+
if (funboxBonusConfiguration > 0 && resultFunboxes.length !== 0) {
727+
const funboxModifier = _.sumBy(resultFunboxes, (funboxName) => {
728+
const funbox = getFunbox(funboxName);
729+
const difficultyLevel = funbox?.difficultyLevel ?? 0;
730+
return Math.max(difficultyLevel * funboxBonusConfiguration, 0);
731+
});
744732
if (funboxModifier > 0) {
745733
modifier += funboxModifier;
746734
breakdown.funbox = Math.round(baseXp * funboxModifier);

0 commit comments

Comments
 (0)