Skip to content

Commit c329d6c

Browse files
authored
Merge pull request #2832 from AtCoder-NoviSteps/#2830
feat(table): Add from ABC126 to ABC211 (#2830)
2 parents c536777 + 91e1181 commit c329d6c

File tree

5 files changed

+510
-0
lines changed

5 files changed

+510
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# ABC126ToABC211Provider テスト追加計画
2+
3+
**作成日**: 2025-11-14
4+
5+
**対象ブランチ**: #2830
6+
7+
**優先度**: High
8+
9+
---
10+
11+
## 参照ドキュメント
12+
13+
テストの書き方・スタイルについては、以下を参照:
14+
15+
📖 [`docs/dev-notes/2025-11-03/add_tests_for_contest_table_provider/plan.md`](../../2025-11-03/add_tests_for_contest_table_provider/plan.md)
16+
17+
---
18+
19+
## 実装チェックリスト
20+
21+
### 1. テスト設計 ✅
22+
23+
- [x] フィルタリングテスト(ABC126~211範囲内のみ抽出)
24+
- [x] コンテストタイプ判別テスト(ABC型のみ)
25+
- [x] メタデータ取得テスト
26+
- [x] ディスプレイ設定テスト
27+
- [x] ラウンドラベルフォーマットテスト
28+
- [x] エッジケーステスト(空入力など)
29+
- [x] 混合コンテストタイプ対応テスト
30+
31+
### 2. モックデータ準備
32+
33+
- [x] `src/test/lib/utils/test_cases/contest_table_provider.ts` に ABC126~211 データを追加
34+
- [x] ABC126, ABC150, ABC211 の 3 コンテストでサンプルデータを作成
35+
- [x] task_table_index は A, B, C, D, E, F に対応
36+
37+
### 3. テスト実装
38+
39+
- [x] 既存テスト(`ABC212ToABC318Provider` など)を参考に記述
40+
- [x] `ABC126ToABC211Provider` をテストファイルにインポート
41+
- [x] `describe.each()` に ABC126ToABC211Provider を追加(displayConfig 共通化)
42+
43+
### 4. テスト リファクタリング
44+
45+
- [x] `describe.each()` に ABC126ToABC211 を追加:displayConfig, label format, empty results テストを共通化
46+
- [x] ABC126ToABC211 個別テストから重複テストを削除:5 個削除 → 4 個に削減
47+
48+
### 5. 実装後の検証
49+
50+
- [x] テスト実行: `pnpm test:unit src/test/lib/utils/contest_table_provider.test.ts`**115 テスト全てパス**
51+
- [x] Lint チェック: `pnpm format`**フォーマット完了**
52+
- [x] 全テスト合格確認 → **✅ PASS**
53+
54+
---
55+
56+
## テスト仕様
57+
58+
### 対象プロバイダー
59+
60+
`ABC126ToABC211Provider`
61+
62+
### フィルタ範囲
63+
64+
- **最小**: ABC 126
65+
- **最大**: ABC 211
66+
- **対象数**: 86 コンテスト
67+
68+
### 表示設定
69+
70+
| 項目 ||
71+
| --------------------- | ------------------------------------------------------- |
72+
| `isShownHeader` | `true` |
73+
| `isShownRoundLabel` | `true` |
74+
| `roundLabelWidth` | `'xl:w-16'` |
75+
| `tableBodyCellsWidth` | `'w-1/2 xs:w-1/3 sm:w-1/4 md:w-1/5 lg:w-1/6 px-1 py-1'` |
76+
| `isShownTaskIndex` | `false` |
77+
78+
---
79+
80+
## 実装結果・教訓
81+
82+
### ✅ 実装完了
83+
84+
**実施時間**: 約 5 分(リファクタリング含む)
85+
86+
**実装内容**:
87+
88+
1. モックデータ追加: ABC126, ABC150, ABC211 の 3 コンテスト分(9 タスク)
89+
2. `describe.each()` に ABC126ToABC211Provider を追加
90+
3. ABC126ToABC211 個別テストから重複テストを削除(5→4)
91+
4. テストコード削減: 39 行削除、DRY 原則に従う
92+
93+
### 📚 得られた教訓
94+
95+
1. **パラメータ化テストの活用**: `describe.each()` で同一構造のプロバイダーをシェアすることで、メンテナンス性向上とコード削減が実現。新規プロバイダー追加時は同じ表示設定を持つ場合、`describe.each()` への統合を検討すべき
96+
97+
2. **テスト重複の排除**: 共通テスト(displayConfig, label format, empty results)と固有テスト(フィルタリング範囲)の分離により、テストの意図が明確化され、保守が容易に
98+
99+
3. **プロバイダー設計の統一性**: ABC126~211 と ABC212~318 が同じ displayConfig を持つことは、プロバイダー実装の設計が一貫していることを示す。新規プロバイダー追加時は既存設計との整合性を確認することが重要
100+
101+
---
102+
103+
## 改善提案(実装完了)✅
104+
105+
### `describe.each()` パターンへの統合
106+
107+
**実施内容**:
108+
109+
`ABC126ToABC211Provider``describe.each()` に追加し、displayConfig などの共通テストをシェア。
110+
111+
**変更内容**:
112+
113+
```typescript
114+
// 追加されたパラメータ
115+
{
116+
providerClass: ABC126ToABC211Provider,
117+
label: '126 to 211',
118+
displayConfig: {
119+
roundLabelWidth: 'xl:w-16',
120+
tableBodyCellsWidth: 'w-1/2 xs:w-1/3 sm:w-1/4 md:w-1/5 lg:w-1/6 px-1 py-1',
121+
},
122+
},
123+
```
124+
125+
**ABC126ToABC211 個別テストから削除**:
126+
127+
- `test('expects to get correct display configuration', ...)`
128+
- `test('expects to format contest round label correctly', ...)`
129+
- `test('expects to handle empty task results', ...)`
130+
- `test('expects to generate correct table structure', ...)`
131+
- `test('expects to get contest round IDs correctly', ...)`
132+
133+
**結果**: テストコード 39 行削減、テスト数 115(変わらず)、DRY 原則に従う構造へ改善

prisma/tasks.ts

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3854,6 +3854,41 @@ export const tasks = [
38543854
title: 'A. New Generation ABC',
38553855
grade: 'Q8',
38563856
},
3857+
{
3858+
id: 'abc211_f',
3859+
contest_id: 'abc211',
3860+
problem_index: 'F',
3861+
name: 'Rectilinear Polygons',
3862+
title: 'F. Rectilinear Polygons',
3863+
},
3864+
{
3865+
id: 'abc211_e',
3866+
contest_id: 'abc211',
3867+
problem_index: 'E',
3868+
name: 'Red Polyomino',
3869+
title: 'E. Red Polyomino',
3870+
},
3871+
{
3872+
id: 'abc211_d',
3873+
contest_id: 'abc211',
3874+
problem_index: 'D',
3875+
name: 'Number of Shortest paths',
3876+
title: 'D. Number of Shortest paths',
3877+
},
3878+
{
3879+
id: 'abc211_c',
3880+
contest_id: 'abc211',
3881+
problem_index: 'C',
3882+
name: 'chokudai',
3883+
title: 'C. chokudai',
3884+
},
3885+
{
3886+
id: 'abc211_b',
3887+
contest_id: 'abc211',
3888+
problem_index: 'B',
3889+
name: 'Cycle Hit',
3890+
title: 'B. Cycle Hit',
3891+
},
38573892
{
38583893
id: 'abc211_a',
38593894
contest_id: 'abc211',
@@ -3862,6 +3897,90 @@ export const tasks = [
38623897
title: 'A. Blood Pressure',
38633898
grade: 'Q9',
38643899
},
3900+
{
3901+
id: 'abc210_f',
3902+
contest_id: 'abc210',
3903+
problem_index: 'F',
3904+
name: 'Coprime Solitaire',
3905+
title: 'F. Coprime Solitaire',
3906+
},
3907+
{
3908+
id: 'abc210_e',
3909+
contest_id: 'abc210',
3910+
problem_index: 'E',
3911+
name: 'Ring MST',
3912+
title: 'E. Ring MST',
3913+
},
3914+
{
3915+
id: 'abc210_d',
3916+
contest_id: 'abc210',
3917+
problem_index: 'D',
3918+
name: 'National Railway',
3919+
title: 'D. National Railway',
3920+
},
3921+
{
3922+
id: 'abc210_c',
3923+
contest_id: 'abc210',
3924+
problem_index: 'C',
3925+
name: 'Colorful Candies',
3926+
title: 'C. Colorful Candies',
3927+
},
3928+
{
3929+
id: 'abc210_b',
3930+
contest_id: 'abc210',
3931+
problem_index: 'B',
3932+
name: 'Bouzu Mekuri',
3933+
title: 'B. Bouzu Mekuri',
3934+
},
3935+
{
3936+
id: 'abc210_a',
3937+
contest_id: 'abc210',
3938+
problem_index: 'A',
3939+
name: 'Cabbages',
3940+
title: 'A. Cabbages',
3941+
},
3942+
{
3943+
id: 'abc209_f',
3944+
contest_id: 'abc209',
3945+
problem_index: 'F',
3946+
name: 'Deforestation',
3947+
title: 'F. Deforestation',
3948+
},
3949+
{
3950+
id: 'abc209_e',
3951+
contest_id: 'abc209',
3952+
problem_index: 'E',
3953+
name: 'Shiritori',
3954+
title: 'E. Shiritori',
3955+
},
3956+
{
3957+
id: 'abc209_d',
3958+
contest_id: 'abc209',
3959+
problem_index: 'D',
3960+
name: 'Collision',
3961+
title: 'D. Collision',
3962+
},
3963+
{
3964+
id: 'abc209_c',
3965+
contest_id: 'abc209',
3966+
problem_index: 'C',
3967+
name: 'Not Equal',
3968+
title: 'C. Not Equal',
3969+
},
3970+
{
3971+
id: 'abc209_b',
3972+
contest_id: 'abc209',
3973+
problem_index: 'B',
3974+
name: 'Can you buy them all?',
3975+
title: 'B. Can you buy them all?',
3976+
},
3977+
{
3978+
id: 'abc209_a',
3979+
contest_id: 'abc209',
3980+
problem_index: 'A',
3981+
name: 'Counting',
3982+
title: 'A. Counting',
3983+
},
38653984
{
38663985
id: 'abc205_a',
38673986
contest_id: 'abc205',
@@ -4060,6 +4179,132 @@ export const tasks = [
40604179
name: 'ModSum',
40614180
title: 'D. ModSum',
40624181
},
4182+
{
4183+
id: 'abc128_f',
4184+
contest_id: 'abc128',
4185+
problem_index: 'F',
4186+
name: 'Frog Jump',
4187+
title: 'F. Frog Jump',
4188+
},
4189+
{
4190+
id: 'abc128_e',
4191+
contest_id: 'abc128',
4192+
problem_index: 'E',
4193+
name: 'Roadwork',
4194+
title: 'E. Roadwork',
4195+
},
4196+
{
4197+
id: 'abc128_d',
4198+
contest_id: 'abc128',
4199+
problem_index: 'D',
4200+
name: 'equeue',
4201+
title: 'D. equeue',
4202+
},
4203+
{
4204+
id: 'abc128_c',
4205+
contest_id: 'abc128',
4206+
problem_index: 'C',
4207+
name: 'Switches',
4208+
title: 'C. Switches',
4209+
},
4210+
{
4211+
id: 'abc128_b',
4212+
contest_id: 'abc128',
4213+
problem_index: 'B',
4214+
name: 'Guidebook',
4215+
title: 'B. Guidebook',
4216+
},
4217+
{
4218+
id: 'abc128_a',
4219+
contest_id: 'abc128',
4220+
problem_index: 'A',
4221+
name: 'Apple Pie',
4222+
title: 'A. Apple Pie',
4223+
},
4224+
{
4225+
id: 'abc127_f',
4226+
contest_id: 'abc127',
4227+
problem_index: 'F',
4228+
name: 'Absolute Minima',
4229+
title: 'F. Absolute Minima',
4230+
},
4231+
{
4232+
id: 'abc127_e',
4233+
contest_id: 'abc127',
4234+
problem_index: 'E',
4235+
name: 'Cell Distance',
4236+
title: 'E. Cell Distance',
4237+
},
4238+
{
4239+
id: 'abc127_d',
4240+
contest_id: 'abc127',
4241+
problem_index: 'D',
4242+
name: 'Integer Cards',
4243+
title: 'D. Integer Cards',
4244+
},
4245+
{
4246+
id: 'abc127_c',
4247+
contest_id: 'abc127',
4248+
problem_index: 'C',
4249+
name: 'Prison',
4250+
title: 'C. Prison',
4251+
},
4252+
{
4253+
id: 'abc127_b',
4254+
contest_id: 'abc127',
4255+
problem_index: 'B',
4256+
name: 'Algae',
4257+
title: 'B. Algae',
4258+
},
4259+
{
4260+
id: 'abc127_a',
4261+
contest_id: 'abc127',
4262+
problem_index: 'A',
4263+
name: 'Ferris Wheel',
4264+
title: 'A. Ferris Wheel',
4265+
},
4266+
{
4267+
id: 'abc126_f',
4268+
contest_id: 'abc126',
4269+
problem_index: 'F',
4270+
name: 'XOR Matching',
4271+
title: 'F. XOR Matching',
4272+
},
4273+
{
4274+
id: 'abc126_e',
4275+
contest_id: 'abc126',
4276+
problem_index: 'E',
4277+
name: '1 or 2',
4278+
title: 'E. 1 or 2',
4279+
},
4280+
{
4281+
id: 'abc126_d',
4282+
contest_id: 'abc126',
4283+
problem_index: 'D',
4284+
name: 'Even Relation',
4285+
title: 'D. Even Relation',
4286+
},
4287+
{
4288+
id: 'abc126_c',
4289+
contest_id: 'abc126',
4290+
problem_index: 'C',
4291+
name: 'Dice and Coin',
4292+
title: 'C. Dice and Coin',
4293+
},
4294+
{
4295+
id: 'abc126_b',
4296+
contest_id: 'abc126',
4297+
problem_index: 'B',
4298+
name: 'YYMM or MMYY',
4299+
title: 'B. YYMM or MMYY',
4300+
},
4301+
{
4302+
id: 'abc126_a',
4303+
contest_id: 'abc126',
4304+
problem_index: 'A',
4305+
name: 'Changing a Character',
4306+
title: 'A. Changing a Character',
4307+
},
40634308
{
40644309
id: 'abc123_d',
40654310
contest_id: 'abc123',

0 commit comments

Comments
 (0)