Skip to content

Commit 095b393

Browse files
committed
♻️ Refactoring tests and add docs (#1856)
1 parent 511219e commit 095b393

File tree

2 files changed

+134
-45
lines changed

2 files changed

+134
-45
lines changed

src/test/lib/utils/contest_table_provider.test.ts

+25-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,16 @@ vi.mock('$lib/utils/task', () => ({
3333

3434
describe('ContestTableProviderBase and implementations', () => {
3535
const mockTaskResults: TaskResults = taskResultsForContestTableProvider;
36+
3637
const getContestRound = (contestId: string): number => {
37-
return parseInt(contestId.replace('abc', ''), 10);
38+
const roundString = contestId.replace(/^\D+/, '');
39+
const round = parseInt(roundString, 10);
40+
41+
if (isNaN(round)) {
42+
throw new Error(`Invalid contest ID format: ${contestId}`);
43+
}
44+
45+
return round;
3846
};
3947

4048
describe('ABC latest 20 rounds provider', () => {
@@ -52,8 +60,17 @@ describe('ContestTableProviderBase and implementations', () => {
5260
const largeDataset = [...mockTaskResults];
5361
const filtered = provider.filter(largeDataset);
5462
const uniqueContests = new Set(filtered.map((task) => task.contest_id));
55-
5663
expect(uniqueContests.size).toBe(20);
64+
65+
// Verify these are the latest 20 rounds
66+
const contestRounds = Array.from(uniqueContests)
67+
.map((id) => getContestRound(id))
68+
.sort((a, b) => b - a); // Sort in descending order
69+
70+
// Validate if the rounds are sequential and latest
71+
const latestRound = Math.max(...contestRounds);
72+
const expectedRounds = Array.from({ length: 20 }, (_, i) => latestRound - i);
73+
expect(contestRounds).toEqual(expectedRounds);
5774
});
5875

5976
test('expects to generate correct table structure', () => {
@@ -66,6 +83,12 @@ describe('ContestTableProviderBase and implementations', () => {
6683
expect(table.abc378.G).toEqual(
6784
expect.objectContaining({ contest_id: 'abc378', task_id: 'abc378_g' }),
6885
);
86+
87+
expect(table).toHaveProperty('abc397');
88+
expect(table.abc397).toHaveProperty('G');
89+
expect(table.abc397.G).toEqual(
90+
expect.objectContaining({ contest_id: 'abc397', task_id: 'abc397_g' }),
91+
);
6992
});
7093

7194
test('expects to get correct metadata', () => {

src/test/lib/utils/test_cases/contest_table_provider.ts

+109-43
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import type { TaskResult, TaskResults } from '$lib/types/task';
44
// Most fields are empty strings as they're not relevant for these tests.
55
// The updated_at field is set to Unix epoch as we only care about task_table_index
66
// and task_id for header name testing.
7+
8+
/**
9+
* Default task result object used as a template for test data.
10+
* Most fields are initialized as empty strings as they're not relevant for these tests.
11+
* @type {TaskResult}
12+
*/
713
const defaultTaskResult: TaskResult = {
814
is_ac: false,
915
user_id: '',
@@ -19,9 +25,13 @@ const defaultTaskResult: TaskResult = {
1925
updated_at: new Date(0), // Use the Unix epoch as the default value.
2026
};
2127

28+
/** Represents a fully accepted submission status */
2229
const AC = 'ac';
30+
/** Represents a submission that was accepted with reference to the editorial */
2331
const AC_WITH_EDITORIAL = 'ac_with_editorial';
32+
/** Represents a challenge is underway */
2433
const TRYING = 'wa';
34+
/** Represents an unchallenged */
2535
const PENDING = 'ns';
2636

2737
/**
@@ -48,54 +58,110 @@ function createTaskResultWithTaskTableIndex(
4858
};
4959
}
5060

61+
// Define a structure for contest tasks
62+
/**
63+
* Creates task results for a given contest based on provided task configurations.
64+
*
65+
* @param contestId - The unique identifier of the contest
66+
* @param taskConfigs - Array of task configurations with task table indices and status names
67+
* @param taskConfigs.taskTableIndex - The table index identifier for the task
68+
* @param taskConfigs.statusName - The status name to assign to the task
69+
* @returns An array of task results created from the given configurations
70+
*/
71+
const createContestTasks = (
72+
contestId: string,
73+
taskConfigs: Array<{ taskTableIndex: string; statusName: string }>,
74+
) => {
75+
return taskConfigs.map((config) => {
76+
const taskId = `${contestId}_${config.taskTableIndex.toLowerCase()}`;
77+
78+
return createTaskResultWithTaskTableIndex(
79+
contestId,
80+
taskId,
81+
config.taskTableIndex,
82+
config.statusName,
83+
);
84+
});
85+
};
86+
5187
// ABC212 - ABC232: 8 tasks (A, B, C, D, E, F, G and H)
52-
// // Mix of different submission statuses to test various filtering and display scenarios.
53-
const abc212_a = createTaskResultWithTaskTableIndex('abc212', 'abc212_a', 'A', AC);
54-
const abc212_b = createTaskResultWithTaskTableIndex('abc212', 'abc212_b', 'B', AC);
55-
const abc212_f = createTaskResultWithTaskTableIndex('abc212', 'abc212_f', 'F', AC_WITH_EDITORIAL);
56-
const abc212_g = createTaskResultWithTaskTableIndex('abc212', 'abc212_g', 'G', TRYING);
57-
const abc212_h = createTaskResultWithTaskTableIndex('abc212', 'abc212_h', 'H', PENDING);
58-
const abc213_h = createTaskResultWithTaskTableIndex('abc213', 'abc213_h', 'H', PENDING);
59-
const abc232_h = createTaskResultWithTaskTableIndex('abc232', 'abc232_h', 'H', TRYING);
88+
// Mix of different submission statuses to test various filtering and display scenarios.
89+
const [abc212_a, abc212_b, abc212_f, abc212_g, abc212_h] = createContestTasks('abc212', [
90+
{ taskTableIndex: 'A', statusName: AC },
91+
{ taskTableIndex: 'B', statusName: AC },
92+
{ taskTableIndex: 'F', statusName: AC_WITH_EDITORIAL },
93+
{ taskTableIndex: 'G', statusName: TRYING },
94+
{ taskTableIndex: 'H', statusName: PENDING },
95+
]);
96+
const [abc213_h] = createContestTasks('abc213', [{ taskTableIndex: 'H', statusName: PENDING }]);
97+
const [abc232_h] = createContestTasks('abc232', [{ taskTableIndex: 'H', statusName: TRYING }]);
6098

6199
// ABC233 - ABC318: 8 tasks (A, B, C, D, E, F, G and Ex)
62-
const abc233_a = createTaskResultWithTaskTableIndex('abc233', 'abc233_a', 'A', AC);
63-
const abc233_b = createTaskResultWithTaskTableIndex('abc233', 'abc233_b', 'B', TRYING);
64-
const abc233_ex = createTaskResultWithTaskTableIndex('abc233', 'abc233_ex', 'Ex', PENDING);
65-
const abc234_ex = createTaskResultWithTaskTableIndex('abc234', 'abc234_ex', 'Ex', AC);
66-
const abc317_ex = createTaskResultWithTaskTableIndex('abc317', 'abc317_ex', 'Ex', TRYING);
67-
const abc318_ex = createTaskResultWithTaskTableIndex('abc318', 'abc318_ex', 'Ex', PENDING);
100+
const [abc233_a, abc233_b, abc233_ex] = createContestTasks('abc233', [
101+
{ taskTableIndex: 'A', statusName: AC },
102+
{ taskTableIndex: 'B', statusName: TRYING },
103+
{ taskTableIndex: 'Ex', statusName: PENDING },
104+
]);
105+
const [abc234_ex] = createContestTasks('abc234', [{ taskTableIndex: 'Ex', statusName: AC }]);
106+
const [abc317_ex] = createContestTasks('abc317', [{ taskTableIndex: 'Ex', statusName: TRYING }]);
107+
const [abc318_ex] = createContestTasks('abc318', [{ taskTableIndex: 'Ex', statusName: PENDING }]);
68108

69109
// ABC319 - : 7 tasks (A, B, C, D, E, F and G)
70-
const abc319_a = createTaskResultWithTaskTableIndex('abc319', 'abc319_a', 'A', AC);
71-
const abc319_b = createTaskResultWithTaskTableIndex('abc319', 'abc319_b', 'B', AC);
72-
const abc319_c = createTaskResultWithTaskTableIndex('abc319', 'abc319_c', 'C', AC);
73-
const abc319_d = createTaskResultWithTaskTableIndex('abc319', 'abc319_d', 'D', AC);
74-
const abc319_e = createTaskResultWithTaskTableIndex('abc319', 'abc319_e', 'E', AC_WITH_EDITORIAL);
75-
const abc319_f = createTaskResultWithTaskTableIndex('abc319', 'abc319_f', 'F', TRYING);
76-
const abc319_g = createTaskResultWithTaskTableIndex('abc319', 'abc319_g', 'G', PENDING);
77-
const abc376_g = createTaskResultWithTaskTableIndex('abc376', 'abc376_g', 'G', AC);
78-
const abc377_g = createTaskResultWithTaskTableIndex('abc377', 'abc377_g', 'G', AC);
79-
const abc378_g = createTaskResultWithTaskTableIndex('abc378', 'abc378_g', 'G', TRYING);
80-
const abc379_g = createTaskResultWithTaskTableIndex('abc379', 'abc379_g', 'G', PENDING);
81-
const abc380_g = createTaskResultWithTaskTableIndex('abc380', 'abc380_g', 'G', AC);
82-
const abc381_g = createTaskResultWithTaskTableIndex('abc381', 'abc381_g', 'G', AC_WITH_EDITORIAL);
83-
const abc382_g = createTaskResultWithTaskTableIndex('abc382', 'abc382_g', 'G', TRYING);
84-
const abc383_g = createTaskResultWithTaskTableIndex('abc383', 'abc383_g', 'G', AC);
85-
const abc384_g = createTaskResultWithTaskTableIndex('abc384', 'abc384_g', 'G', AC);
86-
const abc385_g = createTaskResultWithTaskTableIndex('abc385', 'abc385_g', 'G', AC);
87-
const abc386_g = createTaskResultWithTaskTableIndex('abc386', 'abc386_g', 'G', AC_WITH_EDITORIAL);
88-
const abc387_g = createTaskResultWithTaskTableIndex('abc387', 'abc387_g', 'G', TRYING);
89-
const abc388_g = createTaskResultWithTaskTableIndex('abc388', 'abc388_g', 'G', TRYING);
90-
const abc389_g = createTaskResultWithTaskTableIndex('abc389', 'abc389_g', 'G', TRYING);
91-
const abc390_g = createTaskResultWithTaskTableIndex('abc390', 'abc390_g', 'G', TRYING);
92-
const abc391_g = createTaskResultWithTaskTableIndex('abc391', 'abc391_g', 'G', TRYING);
93-
const abc392_g = createTaskResultWithTaskTableIndex('abc392', 'abc392_g', 'G', TRYING);
94-
const abc393_g = createTaskResultWithTaskTableIndex('abc393', 'abc393_g', 'G', TRYING);
95-
const abc394_g = createTaskResultWithTaskTableIndex('abc394', 'abc394_g', 'G', TRYING);
96-
const abc395_g = createTaskResultWithTaskTableIndex('abc395', 'abc395_g', 'G', TRYING);
97-
const abc396_g = createTaskResultWithTaskTableIndex('abc396', 'abc396_g', 'G', TRYING);
98-
const abc397_g = createTaskResultWithTaskTableIndex('abc397', 'abc397_g', 'G', TRYING);
110+
const [abc319_a, abc319_b, abc319_c, abc319_d, abc319_e, abc319_f, abc319_g] = createContestTasks(
111+
'abc319',
112+
[
113+
{ taskTableIndex: 'A', statusName: AC },
114+
{ taskTableIndex: 'B', statusName: AC },
115+
{ taskTableIndex: 'C', statusName: AC },
116+
{ taskTableIndex: 'D', statusName: AC },
117+
{ taskTableIndex: 'E', statusName: AC_WITH_EDITORIAL },
118+
{ taskTableIndex: 'F', statusName: TRYING },
119+
{ taskTableIndex: 'G', statusName: PENDING },
120+
],
121+
);
122+
123+
const [
124+
abc376_g,
125+
abc377_g,
126+
abc378_g,
127+
abc379_g,
128+
abc380_g,
129+
abc381_g,
130+
abc382_g,
131+
abc383_g,
132+
abc384_g,
133+
abc385_g,
134+
abc386_g,
135+
abc387_g,
136+
abc388_g,
137+
abc389_g,
138+
abc390_g,
139+
abc391_g,
140+
abc392_g,
141+
abc393_g,
142+
abc394_g,
143+
abc395_g,
144+
abc396_g,
145+
abc397_g,
146+
] = Array.from({ length: 22 }, (_, i) => {
147+
const contestNum = 376 + i;
148+
const contestId = `abc${contestNum}`;
149+
const taskId = `${contestId}_g`;
150+
// Alternating statuses for variety
151+
let statusName;
152+
153+
if (i % 4 === 0) {
154+
statusName = AC;
155+
} else if (i % 4 === 1) {
156+
statusName = AC_WITH_EDITORIAL;
157+
} else if (i % 4 === 2) {
158+
statusName = TRYING;
159+
} else {
160+
statusName = PENDING;
161+
}
162+
163+
return createTaskResultWithTaskTableIndex(contestId, taskId, 'G', statusName);
164+
});
99165

100166
export const taskResultsForContestTableProvider: TaskResults = [
101167
abc212_a,

0 commit comments

Comments
 (0)