Skip to content

Commit 2f78a43

Browse files
authored
Merge pull request #2403 from AtCoder-NoviSteps/#2402
:chore: Fix order (#2402)
2 parents 8b1f8cd + fd1235e commit 2f78a43

File tree

3 files changed

+174
-188
lines changed

3 files changed

+174
-188
lines changed

src/lib/utils/contest_table_provider.ts

Lines changed: 39 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,35 @@ function parseContestRound(contestId: string, prefix: string): number {
210210
return parseInt(withoutPrefix, 10);
211211
}
212212

213+
export class Typical90Provider extends ContestTableProviderBase {
214+
protected setFilterCondition(): (taskResult: TaskResult) => boolean {
215+
return (taskResult: TaskResult) => {
216+
return classifyContest(taskResult.contest_id) === this.contestType;
217+
};
218+
}
219+
220+
getMetadata(): ContestTableMetaData {
221+
return {
222+
title: '競プロ典型 90 問',
223+
abbreviationName: 'typical90',
224+
};
225+
}
226+
227+
getDisplayConfig(): ContestTableDisplayConfig {
228+
return {
229+
isShownHeader: false,
230+
isShownRoundLabel: false,
231+
roundLabelWidth: '', // No specific width for the round label in Typical90
232+
tableBodyCellsWidth: 'w-1/2 xl:w-1/3 px-1 py-2',
233+
isShownTaskIndex: true,
234+
};
235+
}
236+
237+
getContestRoundLabel(contestId: string): string {
238+
return '';
239+
}
240+
}
241+
213242
export class EDPCProvider extends ContestTableProviderBase {
214243
protected setFilterCondition(): (taskResult: TaskResult) => boolean {
215244
return (taskResult: TaskResult) => {
@@ -312,39 +341,6 @@ export class JOIFirstQualRoundProvider extends ContestTableProviderBase {
312341
}
313342
}
314343

315-
export class Typical90Provider extends ContestTableProviderBase {
316-
protected setFilterCondition(): (taskResult: TaskResult) => boolean {
317-
return (taskResult: TaskResult) => {
318-
if (classifyContest(taskResult.contest_id) !== this.contestType) {
319-
return false;
320-
}
321-
322-
return taskResult.contest_id === 'typical90';
323-
};
324-
}
325-
326-
getMetadata(): ContestTableMetaData {
327-
return {
328-
title: '競プロ典型 90 問',
329-
abbreviationName: 'typical90',
330-
};
331-
}
332-
333-
getDisplayConfig(): ContestTableDisplayConfig {
334-
return {
335-
isShownHeader: false,
336-
isShownRoundLabel: false,
337-
roundLabelWidth: '', // No specific width for the round label in Typical90
338-
tableBodyCellsWidth: 'w-1/2 xl:w-1/3 px-1 py-2',
339-
isShownTaskIndex: true,
340-
};
341-
}
342-
343-
getContestRoundLabel(contestId: string): string {
344-
return '';
345-
}
346-
}
347-
348344
/**
349345
* A class that manages individual provider groups
350346
* Manages multiple ContestTableProviders as a single group,
@@ -479,6 +475,15 @@ export const prepareContestProviderPresets = () => {
479475
ariaLabel: 'Filter contests from ABC 212 to ABC 318',
480476
}).addProvider(ContestType.ABC, new ABC212ToABC318Provider(ContestType.ABC)),
481477

478+
/**
479+
* Single group for Typical 90 Problems
480+
*/
481+
Typical90: () =>
482+
new ContestTableProviderGroup(`競プロ典型 90 問`, {
483+
buttonLabel: '競プロ典型 90 問',
484+
ariaLabel: 'Filter Typical 90 Problems',
485+
}).addProvider(ContestType.TYPICAL90, new Typical90Provider(ContestType.TYPICAL90)),
486+
482487
/**
483488
* DP group (EDPC and TDPC)
484489
*/
@@ -496,25 +501,16 @@ export const prepareContestProviderPresets = () => {
496501
buttonLabel: 'JOI 一次予選',
497502
ariaLabel: 'Filter JOI First Qualifying Round',
498503
}).addProvider(ContestType.JOI, new JOIFirstQualRoundProvider(ContestType.JOI)),
499-
500-
/**
501-
* Single group for Typical 90 Problems
502-
*/
503-
Typical90: () =>
504-
new ContestTableProviderGroup(`競プロ典型 90 問`, {
505-
buttonLabel: '競プロ典型 90 問',
506-
ariaLabel: 'Filter Typical 90 Problems',
507-
}).addProvider(ContestType.TYPICAL90, new Typical90Provider(ContestType.TYPICAL90)),
508504
};
509505
};
510506

511507
export const contestTableProviderGroups = {
512508
abcLatest20Rounds: prepareContestProviderPresets().ABCLatest20Rounds(),
513509
abc319Onwards: prepareContestProviderPresets().ABC319Onwards(),
514510
fromAbc212ToAbc318: prepareContestProviderPresets().ABC212ToABC318(),
511+
typical90: prepareContestProviderPresets().Typical90(),
515512
dps: prepareContestProviderPresets().dps(), // Dynamic Programming (DP) Contests
516513
joiFirstQualRound: prepareContestProviderPresets().JOIFirstQualRound(),
517-
typical90: prepareContestProviderPresets().Typical90(),
518514
};
519515

520516
export type ContestTableProviderGroups = keyof typeof contestTableProviderGroups;

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

Lines changed: 116 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,121 @@ describe('ContestTableProviderBase and implementations', () => {
236236
});
237237
});
238238

239+
describe('Typical90 provider', () => {
240+
test('expects to filter tasks to include only typical90 contest', () => {
241+
const provider = new Typical90Provider(ContestType.TYPICAL90);
242+
const mixedTaskResults = [
243+
...mockTaskResults,
244+
{ contest_id: 'abc123', task_id: 'abc123_a', task_table_index: 'A' },
245+
{ contest_id: 'dp', task_id: 'dp_a', task_table_index: 'A' },
246+
];
247+
const filtered = provider.filter(mixedTaskResults as TaskResults);
248+
249+
expect(filtered?.every((task) => task.contest_id === 'typical90')).toBe(true);
250+
expect(filtered?.length).toBe(filtered.length);
251+
expect(filtered).not.toContainEqual(expect.objectContaining({ contest_id: 'abc123' }));
252+
expect(filtered).not.toContainEqual(expect.objectContaining({ contest_id: 'dp' }));
253+
});
254+
255+
test('expects to get correct metadata', () => {
256+
const provider = new Typical90Provider(ContestType.TYPICAL90);
257+
const metadata = provider.getMetadata();
258+
259+
expect(metadata.title).toBe('競プロ典型 90 問');
260+
expect(metadata.abbreviationName).toBe('typical90');
261+
});
262+
263+
test('expects to get correct display configuration', () => {
264+
const provider = new Typical90Provider(ContestType.TYPICAL90);
265+
const displayConfig = provider.getDisplayConfig();
266+
267+
expect(displayConfig.isShownHeader).toBe(false);
268+
expect(displayConfig.isShownRoundLabel).toBe(false);
269+
expect(displayConfig.roundLabelWidth).toBe('');
270+
expect(displayConfig.tableBodyCellsWidth).toBe('w-1/2 xl:w-1/3 px-1 py-2');
271+
expect(displayConfig.isShownTaskIndex).toBe(true);
272+
});
273+
274+
test('expects to format contest round label correctly', () => {
275+
const provider = new Typical90Provider(ContestType.TYPICAL90);
276+
const label = provider.getContestRoundLabel('typical90');
277+
278+
expect(label).toBe('');
279+
});
280+
281+
test('expects to generate correct table structure', () => {
282+
const provider = new Typical90Provider(ContestType.TYPICAL90);
283+
const filtered = provider.filter(mockTaskResults as TaskResults);
284+
const table = provider.generateTable(filtered);
285+
286+
expect(table).toHaveProperty('typical90');
287+
expect(table.typical90).toHaveProperty('001');
288+
expect(table.typical90).toHaveProperty('002');
289+
expect(table.typical90).toHaveProperty('003');
290+
expect(table.typical90).toHaveProperty('010');
291+
expect(table.typical90).toHaveProperty('089');
292+
expect(table.typical90).toHaveProperty('090');
293+
expect(table.typical90['001']).toEqual(
294+
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_a' }),
295+
);
296+
expect(table.typical90['002']).toEqual(
297+
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_b' }),
298+
);
299+
expect(table.typical90['003']).toEqual(
300+
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_c' }),
301+
);
302+
expect(table.typical90['010']).toEqual(
303+
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_j' }),
304+
);
305+
expect(table.typical90['089']).toEqual(
306+
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_ck' }),
307+
);
308+
expect(table.typical90['090']).toEqual(
309+
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_cl' }),
310+
);
311+
});
312+
313+
test('expects to get contest round IDs correctly', () => {
314+
const provider = new Typical90Provider(ContestType.TYPICAL90);
315+
const filtered = provider.filter(mockTaskResults as TaskResults);
316+
const roundIds = provider.getContestRoundIds(filtered as TaskResults);
317+
318+
expect(roundIds).toEqual(['typical90']);
319+
});
320+
321+
test('expects to get header IDs for tasks correctly', () => {
322+
const provider = new Typical90Provider(ContestType.TYPICAL90);
323+
const taskResults = [
324+
...mockTaskResults,
325+
{ contest_id: 'typical90', task_id: 'typical90_d', task_table_index: '004' },
326+
{ contest_id: 'typical90', task_id: 'typical90_e', task_table_index: '005' },
327+
];
328+
const filtered = provider.filter(taskResults as TaskResults);
329+
const headerIds = provider.getHeaderIdsForTask(filtered as TaskResults);
330+
331+
expect(headerIds).toEqual(['001', '002', '003', '004', '005', '010', '089', '090']);
332+
});
333+
334+
test('expects to handle empty task results', () => {
335+
const provider = new Typical90Provider(ContestType.TYPICAL90);
336+
const filtered = provider.filter([] as TaskResults);
337+
338+
expect(filtered).toEqual([] as TaskResults);
339+
});
340+
341+
test('expects to handle task results with different contest types', () => {
342+
const provider = new Typical90Provider(ContestType.TYPICAL90);
343+
const mockMixedTasks = [
344+
{ contest_id: 'abc123', task_id: 'abc123_a', task_table_index: 'A' },
345+
{ contest_id: 'dp', task_id: 'dp_a', task_table_index: 'A' },
346+
{ contest_id: 'tdpc', task_id: 'tdpc_a', task_table_index: 'A' },
347+
];
348+
const filtered = provider.filter(mockMixedTasks as TaskResults);
349+
350+
expect(filtered).toEqual([]);
351+
});
352+
});
353+
239354
describe('EDPC provider', () => {
240355
test('expects to get correct metadata', () => {
241356
const provider = new EDPCProvider(ContestType.EDPC);
@@ -414,148 +529,6 @@ describe('ContestTableProviderBase and implementations', () => {
414529
});
415530
});
416531

417-
describe('Typical90 provider', () => {
418-
test('expects to filter tasks to include only typical90 contest', () => {
419-
const provider = new Typical90Provider(ContestType.TYPICAL90);
420-
const mockTypical90Tasks = [
421-
{ contest_id: 'typical90', task_id: 'typical90_a', task_table_index: '001' },
422-
{ contest_id: 'typical90', task_id: 'typical90_b', task_table_index: '002' },
423-
{ contest_id: 'typical90', task_id: 'typical90_j', task_table_index: '010' },
424-
{ contest_id: 'typical90', task_id: 'typical90_ck', task_table_index: '089' },
425-
{ contest_id: 'typical90', task_id: 'typical90_cl', task_table_index: '090' },
426-
{ contest_id: 'abc123', task_id: 'abc123_a', task_table_index: 'A' },
427-
{ contest_id: 'dp', task_id: 'dp_a', task_table_index: 'A' },
428-
];
429-
430-
const filtered = provider.filter(mockTypical90Tasks as any);
431-
432-
expect(filtered?.every((task) => task.contest_id === 'typical90')).toBe(true);
433-
expect(filtered?.length).toBe(5);
434-
expect(filtered).not.toContainEqual(expect.objectContaining({ contest_id: 'abc123' }));
435-
expect(filtered).not.toContainEqual(expect.objectContaining({ contest_id: 'dp' }));
436-
});
437-
438-
test('expects to get correct metadata', () => {
439-
const provider = new Typical90Provider(ContestType.TYPICAL90);
440-
const metadata = provider.getMetadata();
441-
442-
expect(metadata.title).toBe('競プロ典型 90 問');
443-
expect(metadata.abbreviationName).toBe('typical90');
444-
});
445-
446-
test('expects to get correct display configuration', () => {
447-
const provider = new Typical90Provider(ContestType.TYPICAL90);
448-
const displayConfig = provider.getDisplayConfig();
449-
450-
expect(displayConfig.isShownHeader).toBe(false);
451-
expect(displayConfig.isShownRoundLabel).toBe(false);
452-
expect(displayConfig.roundLabelWidth).toBe('');
453-
expect(displayConfig.tableBodyCellsWidth).toBe('w-1/2 xl:w-1/3 px-1 py-2');
454-
expect(displayConfig.isShownTaskIndex).toBe(true);
455-
});
456-
457-
test('expects to format contest round label correctly', () => {
458-
const provider = new Typical90Provider(ContestType.TYPICAL90);
459-
const label = provider.getContestRoundLabel('typical90');
460-
461-
expect(label).toBe('');
462-
});
463-
464-
test('expects to generate correct table structure', () => {
465-
const provider = new Typical90Provider(ContestType.TYPICAL90);
466-
const mockTypical90Tasks = [
467-
{ contest_id: 'typical90', task_id: 'typical90_a', task_table_index: '001' },
468-
{ contest_id: 'typical90', task_id: 'typical90_b', task_table_index: '002' },
469-
{ contest_id: 'typical90', task_id: 'typical90_c', task_table_index: '003' },
470-
{ contest_id: 'typical90', task_id: 'typical90_j', task_table_index: '010' },
471-
{ contest_id: 'typical90', task_id: 'typical90_ck', task_table_index: '089' },
472-
{ contest_id: 'typical90', task_id: 'typical90_cl', task_table_index: '090' },
473-
];
474-
475-
const table = provider.generateTable(mockTypical90Tasks as any);
476-
477-
expect(table).toHaveProperty('typical90');
478-
expect(table.typical90).toHaveProperty('001');
479-
expect(table.typical90).toHaveProperty('002');
480-
expect(table.typical90).toHaveProperty('003');
481-
expect(table.typical90).toHaveProperty('010');
482-
expect(table.typical90).toHaveProperty('089');
483-
expect(table.typical90).toHaveProperty('090');
484-
expect(table.typical90['001']).toEqual(
485-
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_a' }),
486-
);
487-
expect(table.typical90['002']).toEqual(
488-
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_b' }),
489-
);
490-
expect(table.typical90['003']).toEqual(
491-
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_c' }),
492-
);
493-
expect(table.typical90['010']).toEqual(
494-
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_j' }),
495-
);
496-
expect(table.typical90['089']).toEqual(
497-
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_ck' }),
498-
);
499-
expect(table.typical90['090']).toEqual(
500-
expect.objectContaining({ contest_id: 'typical90', task_id: 'typical90_cl' }),
501-
);
502-
});
503-
504-
test('expects to get contest round IDs correctly', () => {
505-
const provider = new Typical90Provider(ContestType.TYPICAL90);
506-
const mockTypical90Tasks = [
507-
{ contest_id: 'typical90', task_id: 'typical90_a', task_table_index: '001' },
508-
{ contest_id: 'typical90', task_id: 'typical90_b', task_table_index: '002' },
509-
{ contest_id: 'typical90', task_id: 'typical90_c', task_table_index: '003' },
510-
{ contest_id: 'typical90', task_id: 'typical90_j', task_table_index: '010' },
511-
{ contest_id: 'typical90', task_id: 'typical90_ck', task_table_index: '089' },
512-
{ contest_id: 'typical90', task_id: 'typical90_cl', task_table_index: '090' },
513-
];
514-
515-
const roundIds = provider.getContestRoundIds(mockTypical90Tasks as any);
516-
517-
expect(roundIds).toEqual(['typical90']);
518-
});
519-
520-
test('expects to get header IDs for tasks correctly', () => {
521-
const provider = new Typical90Provider(ContestType.TYPICAL90);
522-
const mockTypical90Tasks = [
523-
{ contest_id: 'typical90', task_id: 'typical90_a', task_table_index: '001' },
524-
{ contest_id: 'typical90', task_id: 'typical90_b', task_table_index: '002' },
525-
{ contest_id: 'typical90', task_id: 'typical90_c', task_table_index: '003' },
526-
{ contest_id: 'typical90', task_id: 'typical90_d', task_table_index: '004' },
527-
{ contest_id: 'typical90', task_id: 'typical90_e', task_table_index: '005' },
528-
{ contest_id: 'typical90', task_id: 'typical90_j', task_table_index: '010' },
529-
{ contest_id: 'typical90', task_id: 'typical90_ck', task_table_index: '089' },
530-
{ contest_id: 'typical90', task_id: 'typical90_cl', task_table_index: '090' },
531-
];
532-
533-
const headerIds = provider.getHeaderIdsForTask(mockTypical90Tasks as any);
534-
535-
expect(headerIds).toEqual(['001', '002', '003', '004', '005', '010', '089', '090']);
536-
});
537-
538-
test('expects to handle empty task results', () => {
539-
const provider = new Typical90Provider(ContestType.TYPICAL90);
540-
const filtered = provider.filter([]);
541-
542-
expect(filtered).toEqual([]);
543-
});
544-
545-
test('expects to handle task results with different contest types', () => {
546-
const provider = new Typical90Provider(ContestType.TYPICAL90);
547-
const mockMixedTasks = [
548-
{ contest_id: 'abc123', task_id: 'abc123_a', task_table_index: 'A' },
549-
{ contest_id: 'dp', task_id: 'dp_a', task_table_index: 'A' },
550-
{ contest_id: 'tdpc', task_id: 'tdpc_a', task_table_index: 'A' },
551-
];
552-
553-
const filtered = provider.filter(mockMixedTasks as any);
554-
555-
expect(filtered).toEqual([]);
556-
});
557-
});
558-
559532
describe('Common provider functionality', () => {
560533
test('expects to get contest round IDs correctly', () => {
561534
const provider = new ABCLatest20RoundsProvider(ContestType.ABC);
@@ -749,8 +722,8 @@ describe('prepareContestProviderPresets', () => {
749722
expect(typeof presets.ABCLatest20Rounds).toBe('function');
750723
expect(typeof presets.ABC319Onwards).toBe('function');
751724
expect(typeof presets.ABC212ToABC318).toBe('function');
752-
expect(typeof presets.dps).toBe('function');
753725
expect(typeof presets.Typical90).toBe('function');
726+
expect(typeof presets.dps).toBe('function');
754727
});
755728

756729
test('expects each preset to create independent instances', () => {

0 commit comments

Comments
 (0)