Spaces:
Sleeping
Sleeping
| # オペコード全組み合わせテスト計画 | |
| ## 概要 | |
| このドキュメントは、全オペコードと条件の組み合わせを体系的にテストするための計画です。 | |
| ゲーム状態(カード、エネルギー、デッキ、捨て札サイズなど)の変数を考慮した包括的なテストマトリックスを定義します。 | |
| --- | |
| ## 1. オペコード分類 | |
| ### 1.1 基本操作オペコード(Core Opcodes) | |
| | オペコード | ID | 説明 | テスト優先度 | | |
| |-----------|-----|------|-------------| | |
| | `O_DRAW` | 10 | カードを引く | 高 | | |
| | `O_ADD_BLADES` | 11 | ブレード追加 | 高 | | |
| | `O_ADD_HEARTS` | 12 | ハート追加 | 高 | | |
| | `O_REDUCE_COST` | 13 | コスト削減 | 中 | | |
| | `O_LOOK_DECK` | 14 | デッキを見る | 高 | | |
| | `O_RECOVER_LIVE` | 15 | ライブ回復 | 高 | | |
| | `O_BOOST_SCORE` | 16 | スコア増加 | 高 | | |
| | `O_RECOVER_MEMBER` | 17 | メンバー回復 | 高 | | |
| | `O_BUFF_POWER` | 18 | パワーバフ | 中 | | |
| | `O_IMMUNITY` | 19 | 免疫付与 | 中 | | |
| | `O_MOVE_MEMBER` | 20 | メンバー移動 | 高 | | |
| | `O_SWAP_CARDS` | 21 | カード交換 | 中 | | |
| | `O_SEARCH_DECK` | 22 | デッキ検索 | 高 | | |
| | `O_ENERGY_CHARGE` | 23 | エネルギーチャージ | 高 | | |
| | `O_SET_BLADES` | 24 | ブレード設定 | 中 | | |
| | `O_SET_HEARTS` | 25 | ハート設定 | 中 | | |
| | `O_FORMATION_CHANGE` | 26 | フォーメーション変更 | 低 | | |
| | `O_NEGATE_EFFECT` | 27 | 効果無効化 | 高 | | |
| | `O_ORDER_DECK` | 28 | デッキ順序変更 | 中 | | |
| | `O_META_RULE` | 29 | メタルール | 中 | | |
| ### 1.2 選択・検索オペコード(Selection Opcodes) | |
| | オペコード | ID | 説明 | テスト優先度 | | |
| |-----------|-----|------|-------------| | |
| | `O_SELECT_MODE` | 30 | モード選択 | 高 | | |
| | `O_MOVE_TO_DECK` | 31 | デッキに移動 | 高 | | |
| | `O_TAP_OPPONENT` | 32 | 相手をタップ | 高 | | |
| | `O_PLACE_UNDER` | 33 | 下に配置 | 中 | | |
| | `O_REVEAL_CARDS` | 40 | カード公開 | 高 | | |
| | `O_LOOK_AND_CHOOSE` | 41 | 見て選ぶ | 高 | | |
| | `O_CHEER_REVEAL` | 42 | チア公開 | 低 | | |
| | `O_ACTIVATE_MEMBER` | 43 | メンバー活性化 | 高 | | |
| | `O_ADD_TO_HAND` | 44 | 手札に追加 | 高 | | |
| | `O_COLOR_SELECT` | 45 | 色選択 | 高 | | |
| | `O_REPLACE_EFFECT` | 46 | 効果置換 | 中 | | |
| | `O_TRIGGER_REMOTE` | 47 | リモートトリガー | 中 | | |
| | `O_REDUCE_HEART_REQ` | 48 | ハート要件削減 | 中 | | |
| | `O_MODIFY_SCORE_RULE` | 49 | スコアルール変更 | 低 | | |
| | `O_ADD_STAGE_ENERGY` | 50 | ステージエネルギー追加 | 中 | | |
| | `O_SET_TAPPED` | 51 | タップ状態設定 | 高 | | |
| | `O_ADD_CONTINUOUS` | 52 | 継続効果追加 | 中 | | |
| | `O_TAP_MEMBER` | 53 | メンバーをタップ | 高 | | |
| ### 1.3 特殊操作オペコード(Special Opcodes) | |
| | オペコード | ID | 説明 | テスト優先度 | | |
| |-----------|-----|------|-------------| | |
| | `O_PLAY_MEMBER_FROM_HAND` | 57 | 手札からプレイ | 高 | | |
| | `O_MOVE_TO_DISCARD` | 58 | 捨て札に移動 | 高 | | |
| | `O_GRANT_ABILITY` | 60 | アビリティ付与 | 中 | | |
| | `O_INCREASE_HEART_COST` | 61 | ハートコスト増加 | 低 | | |
| | `O_REDUCE_YELL_COUNT` | 62 | エール数削減 | 中 | | |
| | `O_PLAY_MEMBER_FROM_DISCARD` | 63 | 捨て札からプレイ | 高 | | |
| | `O_PAY_ENERGY` | 64 | エネルギー支払い | 高 | | |
| | `O_SELECT_MEMBER` | 65 | メンバー選択 | 高 | | |
| | `O_DRAW_UNTIL` | 66 | 指定枚数までドロー | 高 | | |
| | `O_SELECT_PLAYER` | 67 | プレイヤー選択 | 中 | | |
| | `O_SELECT_LIVE` | 68 | ライブ選択 | 高 | | |
| | `O_REVEAL_UNTIL` | 69 | 条件まで公開 | 高 | | |
| | `O_INCREASE_COST` | 70 | コスト増加 | 低 | | |
| | `O_PREVENT_PLAY_TO_SLOT` | 71 | スロットプレイ禁止 | 中 | | |
| | `O_SWAP_AREA` | 72 | エリア交換 | 低 | | |
| | `O_TRANSFORM_HEART` | 73 | ハート変換 | 中 | | |
| | `O_SELECT_CARDS` | 74 | カード選択 | 高 | | |
| | `O_OPPONENT_CHOOSE` | 75 | 相手が選択 | 中 | | |
| | `O_PLAY_LIVE_FROM_DISCARD` | 76 | 捨て札からライブプレイ | 高 | | |
| | `O_REDUCE_LIVE_SET_LIMIT` | 77 | ライブセット制限削減 | 低 | | |
| | `O_PREVENT_ACTIVATE` | 82 | 活性化禁止 | 中 | | |
| | `O_ACTIVATE_ENERGY` | 81 | エネルギー活性化 | 高 | | |
| | `O_PREVENT_SET_TO_SUCCESS_PILE` | 80 | 成功山札への配置禁止 | 低 | | |
| | `O_PREVENT_BATON_TOUCH` | 90 | バトンタッチ禁止 | 中 | | |
| | `O_SET_HEART_COST` | 83 | ハートコスト設定 | 中 | | |
| --- | |
| ## 2. 条件分類 | |
| ### 2.1 カウント条件(Count Conditions) | |
| | 条件 | ID | 説明 | テスト変数 | | |
| |------|-----|------|-----------| | |
| | `C_COUNT_STAGE` | 203 | ステージ枚数 | 0, 1, 2, 3 | | |
| | `C_COUNT_HAND` | 204 | 手札枚数 | 0, 1, 3, 5, 7, 10 | | |
| | `C_COUNT_DISCARD` | 205 | 捨て札枚数 | 0, 1, 3, 5, 10 | | |
| | `C_COUNT_ENERGY` | 213 | エネルギー枚数 | 0, 1, 3, 5 | | |
| | `C_COUNT_SUCCESS_LIVE` | 218 | 成功ライブ数 | 0, 1, 2, 3 | | |
| | `C_COUNT_LIVE_ZONE` | 230 | ライブゾーン枚数 | 0, 1, 2, 3 | | |
| | `C_COUNT_GROUP` | 208 | グループ枚数 | 0, 1, 2, 3 | | |
| | `C_COUNT_HEARTS` | 223 | ハート数 | 0, 1, 5, 10 | | |
| | `C_COUNT_BLADES` | 224 | ブレード数 | 0, 1, 3, 5 | | |
| ### 2.2 状態条件(State Conditions) | |
| | 条件 | ID | 説明 | テスト変数 | | |
| |------|-----|------|-----------| | |
| | `C_TURN_1` | 200 | ターン1かどうか | true, false | | |
| | `C_IS_CENTER` | 206 | センターかどうか | true, false | | |
| | `C_LIFE_LEAD` | 207 | ライフリード | true, false | | |
| | `C_HAS_MEMBER` | 201 | メンバー所持 | card_id | | |
| | `C_HAS_COLOR` | 202 | 色所持 | color_idx | | |
| | `C_HAS_LIVE_CARD` | 214 | ライブカード所持 | true, false | | |
| | `C_HAND_HAS_NO_LIVE` | 217 | 手札にライブなし | true, false | | |
| | `C_DECK_REFRESHED` | 227 | デッキリフレッシュ済み | true, false | | |
| | `C_HAS_MOVED` | 228 | 移動済み | true, false | | |
| | `C_HAND_INCREASED` | 229 | 手札増加済み | true, false | | |
| | `C_BATON` | 231 | バトン状態 | true, false | | |
| ### 2.3 比較条件(Comparison Conditions) | |
| | 条件 | ID | 説明 | テスト変数 | | |
| |------|-----|------|-----------| | |
| | `C_COST_CHECK` | 215 | コスト確認 | threshold, LE/GE | | |
| | `C_RARITY_CHECK` | 216 | レアリティ確認 | rarity | | |
| | `C_SCORE_COMPARE` | 220 | スコア比較 | diff | | |
| | `C_OPPONENT_HAND_DIFF` | 219 | 相手手札差 | diff | | |
| | `C_OPPONENT_ENERGY_DIFF` | 225 | 相手エネルギー差 | diff | | |
| | `C_COST_LEAD` | 240 | コストリード | true, false | | |
| | `C_SCORE_LEAD` | 241 | スコアリード | true, false | | |
| | `C_HEART_LEAD` | 242 | ハートリード | true, false | | |
| | `C_COST_COMPARE` | 246 | コスト比較 | diff | | |
| | `C_BLADE_COMPARE` | 247 | ブレード比較 | diff | | |
| | `C_HEART_COMPARE` | 248 | ハート比較 | diff | | |
| ### 2.4 フィルター条件(Filter Conditions) | |
| | 条件 | ID | 説明 | テスト変数 | | |
| |------|-----|------|-----------| | |
| | `C_GROUP_FILTER` | 209 | グループフィルター | group_id | | |
| | `C_SELF_IS_GROUP` | 211 | 自分のグループ | group_id | | |
| | `C_TYPE_CHECK` | 232 | タイプ確認 | member/live | | |
| | `C_IS_IN_DISCARD` | 233 | 捨て札にいる | true, false | | |
| | `C_AREA_CHECK` | 234 | エリア確認 | area | | |
| | `C_OPPONENT_HAS` | 210 | 相手が所持 | card_id | | |
| | `C_OPPONENT_HAS_WAIT` | 249 | 相手がWAIT状態 | count | | |
| --- | |
| ## 3. ゲーム状態変数 | |
| ### 3.1 プレイヤー状態 | |
| ```rust | |
| struct PlayerStateVariables { | |
| // カードゾーン | |
| hand_size: usize, // 0-10 | |
| deck_size: usize, // 0-50 | |
| discard_size: usize, // 0-20 | |
| energy_size: usize, // 0-10 | |
| live_zone_size: usize, // 0-3 | |
| success_lives_size: usize, // 0-3 | |
| // ステージ | |
| stage: [i32; 3], // card_id or -1 | |
| stage_tapped: [bool; 3], // tap state | |
| // バフ | |
| blade_buffs: [i32; 3], | |
| heart_buffs: [[u8; 7]; 3], | |
| live_score_bonus: i32, | |
| // フラグ | |
| has_moved: bool, | |
| hand_increased: bool, | |
| deck_refreshed: bool, | |
| } | |
| ``` | |
| ### 3.2 グローバル状態 | |
| ```rust | |
| struct GlobalStateVariables { | |
| turn: i32, // 1-20 | |
| current_player: usize, // 0 or 1 | |
| phase: Phase, | |
| modal_answer: i32, // -1, 0, 1, 2 | |
| } | |
| ``` | |
| --- | |
| ## 4. テストマトリックス | |
| ### 4.1 ドロー系オペコードテスト | |
| #### O_DRAW テストマトリックス | |
| | テストID | デッキサイズ | 手札サイズ | ドロー数 | 期待結果 | | |
| |---------|------------|-----------|---------|---------| | |
| | DRAW-01 | 5 | 0 | 1 | hand=1, deck=4 | | |
| | DRAW-02 | 5 | 5 | 3 | hand=8, deck=2 | | |
| | DRAW-03 | 0 | 3 | 1 | デッキリフレッシュ発生 | | |
| | DRAW-04 | 2 | 7 | 3 | hand=9, deck=0, refresh=1 | | |
| | DRAW-05 | 10 | 0 | 10 | hand=10, deck=0 | | |
| #### O_DRAW_UNTIL テストマトリックス | |
| | テストID | デッキサイズ | 現在手札 | 目標枚数 | ドロー数 | 期待結果 | | |
| |---------|------------|---------|---------|---------|---------| | |
| | DUNTIL-01 | 10 | 2 | 5 | 3 | hand=5 | | |
| | DUNTIL-02 | 10 | 7 | 5 | 0 | hand=7(変更なし) | | |
| | DUNTIL-03 | 2 | 3 | 7 | 2 | hand=5, deck=0 | | |
| | DUNTIL-04 | 0 | 3 | 5 | refresh | リフレッシュ後ドロー | | |
| ### 4.2 回復系オペコードテスト | |
| #### O_RECOVER_MEMBER テストマトリックス | |
| | テストID | 捨て札内容 | フィルター | 期待結果 | | |
| |---------|-----------|-----------|---------| | |
| | RECM-01 | [M1, M2, M3] | なし | いずれか1枚回復 | | |
| | RECM-02 | [M1(cost=3), M2(cost=5)] | cost<=4 | M1のみ選択可能 | | |
| | RECM-03 | [L1, L2] | type=member | 選択不可 | | |
| | RECM-04 | [] | なし | 効果なし | | |
| | RECM-05 | [M1(μ's), M2(Aqours)] | group=μ's | M1のみ選択可能 | | |
| #### O_RECOVER_LIVE テストマトリックス | |
| | テストID | 捨て札内容 | フィルター | 期待結果 | | |
| |---------|-----------|-----------|---------| | |
| | RECL-01 | [L1, L2] | なし | いずれか1枚回復 | | |
| | RECL-02 | [L1(μ's), L2(Aqours)] | group=μ's | L1のみ選択可能 | | |
| | RECL-03 | [M1, M2] | type=live | 選択不可 | | |
| | RECL-04 | [L1(hearts=8)] | hearts>=5 | L1選択可能 | | |
| ### 4.3 検索・選択系オペコードテスト | |
| #### O_LOOK_AND_CHOOSE テストマトリックス | |
| | テストID | デッキ内容 | 見る枚数 | 選択枚数 | フィルター | 期待結果 | | |
| |---------|-----------|---------|---------|-----------|---------| | |
| | LAC-01 | [M1, M2, M3, M4, M5] | 3 | 1 | なし | 1枚handへ、2枚discard | | |
| | LAC-02 | [M1(cost=3), M2(cost=5), M3(cost=2)] | 3 | 1 | cost>=4 | M2のみ選択可能 | | |
| | LAC-03 | [L1, M1, M2] | 3 | 1 | type=live | L1のみ選択可能 | | |
| | LAC-04 | [M1, M2] | 5 | 1 | なし | デッキ不足で2枚のみ | | |
| | LAC-05 | [M1(μ's), M2(Aqours), M3(μ's)] | 3 | 2 | group=μ's | M1, M3選択可能 | | |
| #### O_REVEAL_UNTIL テストマトリックス | |
| | テストID | デッキ内容 | 条件 | 期待結果 | | |
| |---------|-----------|------|---------| | |
| | REVU-01 | [M1, M2, L1, M3] | type=live | L1をhandへ、M1,M2をdiscard | | |
| | REVU-02 | [M1, M2, M3] | type=live | 全枚discard、条件不一致 | | |
| | REVU-03 | [M1(cost=2), M2(cost=5), M3] | cost>=4 | M2をhandへ、M1をdiscard | | |
| | REVU-04 | [L1, L2, L3] | type=live | L1をhandへ | | |
| ### 4.4 エネルギー系オペコードテスト | |
| #### O_PAY_ENERGY テストマトリックス | |
| | テストID | エネルギー数 | タップ済み | 支払い数 | 期待結果 | | |
| |---------|------------|-----------|---------|---------| | |
| | PAYE-01 | 3 | 0 | 1 | tapped=1, energy=3 | | |
| | PAYE-02 | 3 | 1 | 2 | tapped=3, energy=3 | | |
| | PAYE-03 | 2 | 0 | 3 | 支払い不可 | | |
| | PAYE-04 | 5 | 2 | 3 | tapped=5 | | |
| | PAYE-05 | 0 | 0 | 1 | 支払い不可 | | |
| #### O_ACTIVATE_ENERGY テストマトリックス | |
| | テストID | エネルギー数 | 活性化数 | 期待結果 | | |
| |---------|------------|---------|---------| | |
| | ACTE-01 | 3 | 2 | tapped=2 | | |
| | ACTE-02 | 3 | 5 | 全枚タップ | | |
| | ACTE-03 | 0 | 1 | 効果なし | | |
| ### 4.5 タップ系オペコードテスト | |
| #### O_TAP_OPPONENT テストマトリックス | |
| | テストID | 相手ステージ | フィルター | タップ数 | 期待結果 | | |
| |---------|------------|-----------|---------|---------| | |
| | TAPO-01 | [M1, M2, M3] | なし | 1 | 1枚タップ | | |
| | TAPO-02 | [M1(cost=2), M2(cost=5)] | cost<=3 | 1 | M1のみタップ可能 | | |
| | TAPO-03 | [M1(tapped), M2] | なし | 1 | M2タップ | | |
| | TAPO-04 | [M1, M2] | tapped=true | 1 | 既にタップ済みは対象外 | | |
| | TAPO-05 | [-1, -1, -1] | なし | 1 | 効果なし | | |
| #### O_SET_TAPPED テストマトリックス | |
| | テストID | 対象 | 現在状態 | 設定値 | 期待結果 | | |
| |---------|------|---------|-------|---------| | |
| | SETT-01 | stage[0] | untapped | 1 | tapped | | |
| | SETT-02 | stage[0] | tapped | 0 | untapped | | |
| | SETT-03 | stage[0] | tapped | 1 | tapped(変更なし) | | |
| ### 4.6 スコア・バフ系オペコードテスト | |
| #### O_BOOST_SCORE テストマトリックス | |
| | テストID | 現在スコア | 増加値 | 期待結果 | | |
| |---------|-----------|-------|---------| | |
| | BOOS-01 | 0 | 3 | score=3 | | |
| | BOOS-02 | 1000 | 5 | score=1005 | | |
| | BOOS-03 | 0 | 0 | score=0 | | |
| #### O_ADD_BLADES テストマトリックス | |
| | テストID | 現在ブレード | 追加数 | 対象 | 期待結果 | | |
| |---------|------------|-------|------|---------| | |
| | ADDB-01 | 0 | 2 | player | blades=2 | | |
| | ADDB-02 | 3 | 1 | member[0] | blade_buffs[0]=1 | | |
| | ADDB-03 | 0 | 0 | player | blades=0 | | |
| #### O_ADD_HEARTS テストマトリックス | |
| | テストID | 現在ハート | 追加数 | 色 | 期待結果 | | |
| |---------|-----------|-------|-----|---------| | |
| | ADDH-01 | [0,0,0,0,0,0,0] | 2 | pink | heart_buffs[0]=2 | | |
| | ADDH-02 | [1,1,0,0,0,0,0] | 1 | blue | heart_buffs[2]=1 | | |
| | ADDH-03 | [0,0,0,0,0,0,0] | 0 | pink | 変化なし | | |
| ### 4.7 条件分岐テスト | |
| #### C_COUNT_HAND 条件テスト | |
| | テストID | 手札枚数 | 閾値 | 比較 | 期待結果 | | |
| |---------|---------|-----|------|---------| | |
| | CCH-01 | 3 | 3 | >= | true | | |
| | CCH-02 | 3 | 4 | >= | false | | |
| | CCH-03 | 0 | 1 | >= | false | | |
| | CCH-04 | 10 | 5 | >= | true | | |
| #### C_COST_CHECK 条件テスト | |
| | テストID | カードコスト | 閾値 | 比較 | 期待結果 | | |
| |---------|------------|-----|------|---------| | |
| | CCOST-01 | 5 | 5 | >= | true | | |
| | CCOST-02 | 5 | 5 | <= | true | | |
| | CCOST-03 | 3 | 5 | >= | false | | |
| | CCOST-04 | 7 | 5 | <= | false | | |
| #### C_LIFE_LEAD 条件テスト | |
| | テストID | P0成功ライブ | P1成功ライブ | 期待結果 | | |
| |---------|------------|------------|---------| | |
| | CLIF-01 | 2 | 1 | true | | |
| | CLIF-02 | 1 | 2 | false | | |
| | CLIF-03 | 1 | 1 | false | | |
| | CLIF-04 | 0 | 0 | false | | |
| --- | |
| ## 5. 複合テストシナリオ | |
| ### 5.1 コスト支払い+効果の複合テスト | |
| ```rust | |
| #[test] | |
| fn test_cost_discard_hand_with_filter() { | |
| // コスト: 手札を3枚捨てる(フィルター: 歩夢/かのん/花帆) | |
| // 効果: スコア+3 | |
| // Setup | |
| let hand = vec![Ayumu, Kanon, Kaho, Other]; | |
| // Expected: 3枚捨ててスコア+3 | |
| } | |
| #[test] | |
| fn test_cost_pay_energy_with_insufficient() { | |
| // コスト: エネルギー3支払い | |
| // 状態: エネルギー2のみ | |
| // Expected: 効果発動なし | |
| } | |
| ``` | |
| ### 5.2 連鎖効果テスト | |
| ```rust | |
| #[test] | |
| fn test_on_leaves_trigger_chain() { | |
| // メンバーがステージを離れる時、OnLeaves効果が発動 | |
| // その効果がさらに別のカードを移動させる | |
| // Setup: stage[0] = CardWithOnLeaves | |
| // Execute: O_MOVE_TO_DISCARD | |
| // Expected: OnLeaves効果が発動 | |
| } | |
| #[test] | |
| fn test_trigger_remote_chain() { | |
| // O_TRIGGER_REMOTEで別のカードのアビリティを発動 | |
| // そのアビリティがさらにO_TRIGGER_REMOTE | |
| // Expected: 連鎖的にアビリティ発動 | |
| } | |
| ``` | |
| ### 5.3 エッジケーステスト | |
| ```rust | |
| #[test] | |
| fn test_empty_zone_operations() { | |
| // 空のゾーンに対する操作 | |
| // - 空のデッキからドロー | |
| // - 空の捨て札から回復 | |
| // - 空のステージでタップ | |
| // Expected: エラーなく処理 | |
| } | |
| #[test] | |
| fn test_full_zone_operations() { | |
| // 満杯のゾーンに対する操作 | |
| // - 手札10枚でドロー | |
| // - ライブゾーン3枚で追加 | |
| // Expected: ルールに従った処理 | |
| } | |
| ``` | |
| --- | |
| ## 6. テスト実装構造 | |
| ### 6.1 テストヘルパー関数 | |
| ```rust | |
| /// ゲーム状態ビルダー | |
| struct GameStateBuilder { | |
| state: GameState, | |
| } | |
| impl GameStateBuilder { | |
| fn new() -> Self; | |
| fn with_hand(mut self, cards: Vec<i32>) -> Self; | |
| fn with_deck(mut self, cards: Vec<i32>) -> Self; | |
| fn with_discard(mut self, cards: Vec<i32>) -> Self; | |
| fn with_energy(mut self, cards: Vec<i32>) -> Self; | |
| fn with_stage(mut self, slot: usize, card_id: i32) -> Self; | |
| fn with_success_lives(mut self, cards: Vec<i32>) -> Self; | |
| fn with_tapped(mut self, slot: usize, tapped: bool) -> Self; | |
| fn build(self) -> GameState; | |
| } | |
| /// アサーションヘルパー | |
| fn assert_hand_size(state: &GameState, player: usize, expected: usize); | |
| fn assert_deck_size(state: &GameState, player: usize, expected: usize); | |
| fn assert_discard_size(state: &GameState, player: usize, expected: usize); | |
| fn assert_score(state: &GameState, player: usize, expected: i32); | |
| fn assert_blades(state: &GameState, player: usize, expected: i32); | |
| fn assert_tapped(state: &GameState, player: usize, slot: usize, expected: bool); | |
| ``` | |
| ### 6.2 テストファイル構成 | |
| ``` | |
| engine_rust_src/src/ | |
| ├── opcode_tests/ | |
| │ ├── mod.rs | |
| │ ├── draw_tests.rs # O_DRAW, O_DRAW_UNTIL | |
| │ ├── recover_tests.rs # O_RECOVER_MEMBER, O_RECOVER_LIVE | |
| │ ├── search_tests.rs # O_LOOK_DECK, O_SEARCH_DECK, O_LOOK_AND_CHOOSE | |
| │ ├── reveal_tests.rs # O_REVEAL_CARDS, O_REVEAL_UNTIL | |
| │ ├── energy_tests.rs # O_PAY_ENERGY, O_ACTIVATE_ENERGY, O_ENERGY_CHARGE | |
| │ ├── tap_tests.rs # O_TAP_OPPONENT, O_SET_TAPPED, O_TAP_MEMBER | |
| │ ├── score_tests.rs # O_BOOST_SCORE, O_SET_SCORE | |
| │ ├── buff_tests.rs # O_ADD_BLADES, O_ADD_HEARTS, O_BUFF_POWER | |
| │ ├── move_tests.rs # O_MOVE_MEMBER, O_MOVE_TO_DECK, O_MOVE_TO_DISCARD | |
| │ ├── select_tests.rs # O_SELECT_MODE, O_SELECT_MEMBER, O_SELECT_CARDS | |
| │ └── condition_tests.rs # 全条件テスト | |
| ├── integration_tests/ | |
| │ ├── chain_effects.rs # 連鎖効果テスト | |
| │ ├── edge_cases.rs # エッジケーステスト | |
| │ └── full_game_flow.rs # ゲームフローテスト | |
| └── test_helpers.rs | |
| ``` | |
| --- | |
| ## 7. テスト実行戦略 | |
| ### 7.1 ユニットテスト | |
| - 各オペコード単体のテスト | |
| - 各条件単体のテスト | |
| - パラメータ化テストでバリエーションをカバー | |
| ### 7.2 統合テスト | |
| - 複数オペコードの組み合わせ | |
| - トリガー連鎖 | |
| - ゲームフェーズ遷移 | |
| ### 7.3 プロパティベーステスト | |
| ```rust | |
| use proptest::prelude::*; | |
| proptest! { | |
| #[test] | |
| fn test_draw_never_exceeds_max( | |
| deck_size in 0usize..50, | |
| hand_size in 0usize..10, | |
| draw_count in 1usize..5 | |
| ) { | |
| // ドロー後の手札が最大値を超えないことを確認 | |
| } | |
| #[test] | |
| fn test_energy_payment_never_negative( | |
| energy in 0usize..10, | |
| tapped in 0usize..10, | |
| payment in 1usize..5 | |
| ) { | |
| // エネルギー支払い後のタップ数が負にならないことを確認 | |
| } | |
| } | |
| ``` | |
| --- | |
| ## 8. 実カードを使用したテスト | |
| ### 8.1 実カードデータの活用 | |
| テストでは `load_real_db()` を使用して実際のカードデータベースを読み込みます: | |
| ```rust | |
| use crate::test_helpers::load_real_db; | |
| fn get_card_id(db: &CardDatabase, card_no: &str) -> i32 { | |
| db.card_no_to_id.get(card_no).copied().expect("Card not found") | |
| } | |
| ``` | |
| ### 8.2 実カードテストケース | |
| #### O_RECOVER_MEMBER テスト(実カード使用) | |
| | テストID | カード | 日本語テキスト | テスト内容 | | |
| |---------|--------|---------------|-----------| | |
| | RECM-R01 | PL!-sd1-001-SD | 登場:自分の控え室からライブカードを1枚手札に加える | discard=[L1], handにL1追加 | | |
| | RECM-R02 | PL!-sd1-002-SD | 起動:控え室からメンバーカードを1枚手札に加える | discard=[M1], handにM1追加 | | |
| | RECM-R03 | PL!-sd1-003-SD | 登場:控え室からコスト4以下のμ'sメンバーを1枚手札に加える | フィルター条件確認 | | |
| #### O_LOOK_AND_CHOOSE テスト(実カード使用) | |
| | テストID | カード | 日本語テキスト | テスト内容 | | |
| |---------|--------|---------------|-----------| | |
| | LAC-R01 | PL!-sd1-004-SD | 登場:デッキ上5枚を見てμ'sライブを1枚手札に加える | フィルター: group=μ's, type=live | | |
| | LAC-R02 | PL!-sd1-005-SD | 登場:デッキ上3枚を見て1枚手札に加え、残りをデッキに戻す | 順序選択テスト | | |
| #### O_PAY_ENERGY テスト(実カード使用) | |
| | テストID | カード | 日本語テキスト | テスト内容 | | |
| |---------|--------|---------------|-----------| | |
| | PAYE-R01 | LL-bp3-001-R+ | ライブ開始時:エネルギー6支払い、ブレード+3 | energy=6, blades+=3 | | |
| | PAYE-R02 | LL-bp3-001-R+ | エネルギー不足時 | energy=3, 効果発動不可 | | |
| #### O_DISCARD_HAND(コスト)テスト(実カード使用) | |
| | テストID | カード | 日本語テキスト | テスト内容 | | |
| |---------|--------|---------------|-----------| | |
| | DISC-R01 | LL-bp1-001-R+ | 手札の「歩夢/かのん/花帆」を3枚捨ててスコア+3 | フィルター条件確認 | | |
| | DISC-R02 | LL-bp1-001-R+ | フィルター不一致 | hand=[Other], 効果発動不可 | | |
| ### 8.3 実カードテストコード例 | |
| ```rust | |
| /// PL!-sd1-001-SD: 高坂 穂乃果 | |
| /// 日本語: 登場:自分の成功ライブカード置き場にカードが2枚以上ある場合、 | |
| /// 自分の控え室からライブカードを1枚手札に加える。 | |
| #[test] | |
| fn test_real_card_pl_sd1_001_honoka() { | |
| let db = load_real_db(); | |
| let card_id = get_card_id(&db, "PL!-sd1-001-SD"); | |
| let mut state = create_test_state(); | |
| state.ui.silent = true; | |
| // Setup: 成功ライブ2枚、控え室にライブカード | |
| state.players[0].success_lives = vec![ | |
| get_card_id(&db, "PL!-sd1-020-SD"), // ライブカード | |
| get_card_id(&db, "PL!-sd1-021-SD"), // ライブカード | |
| ]; | |
| let live_in_discard = get_card_id(&db, "PL!-sd1-022-SD"); | |
| state.players[0].discard = vec![live_in_discard]; | |
| // Execute: 登場時トリガー | |
| let ctx = AbilityContext { | |
| player_id: 0, | |
| source_card_id: card_id, | |
| ..Default::default() | |
| }; | |
| state.trigger_abilities(&db, TriggerType::OnPlay, &ctx); | |
| // Assert: 控え室から手札にライブカードが移動 | |
| assert!(state.players[0].hand.contains(&live_in_discard), | |
| "ライブカードが手札に追加されるべき"); | |
| } | |
| /// LL-bp1-001-R+: 上原歩夢&澁谷かのん&日野下花帆 | |
| /// 日本語: ライブ開始時:手札の「歩夢/かのん/花帆」を3枚捨ててスコア+3 | |
| #[test] | |
| fn test_real_card_ll_bp1_001_ayumu_kanon_kaho() { | |
| let db = load_real_db(); | |
| let card_id = get_card_id(&db, "LL-bp1-001-R+"); | |
| let mut state = create_test_state(); | |
| state.ui.silent = true; | |
| state.phase = Phase::PerformanceP1; | |
| // Setup: 手札に歩夢、かのん、花帆 | |
| let ayumu = find_card_by_char_name(&db, "歩夢"); | |
| let kanon = find_card_by_char_name(&db, "かのん"); | |
| let kaho = find_card_by_char_name(&db, "花帆"); | |
| state.players[0].hand = vec![ayumu, kanon, kaho, 9999]; // 9999は他のカード | |
| // Execute: ライブ開始時トリガー | |
| let ctx = AbilityContext { | |
| player_id: 0, | |
| source_card_id: card_id, | |
| ..Default::default() | |
| }; | |
| state.trigger_abilities(&db, TriggerType::OnLiveStart, &ctx); | |
| // Assert: スコア+3 | |
| assert_eq!(state.players[0].live_score_bonus, 3, | |
| "スコア+3されるべき"); | |
| } | |
| ``` | |
| ### 8.4 実カードID参照テーブル | |
| | カード番号 | card_id | 名前 | 主なオペコード | | |
| |-----------|---------|------|---------------| | |
| | PL!-sd1-001-SD | 1 | 高坂 穂乃果 | O_RECOVER_LIVE, O_ADD_BLADES | | |
| | PL!-sd1-002-SD | 2 | 絢瀬 絵里 | O_RECOVER_MEMBER | | |
| | PL!-sd1-003-SD | 3 | 南 ことり | O_RECOVER_MEMBER, O_ADD_HEARTS | | |
| | PL!-sd1-004-SD | 4 | 園田 海未 | O_LOOK_AND_CHOOSE | | |
| | PL!-sd1-005-SD | 5 | 星空 凛 | O_LOOK_AND_CHOOSE | | |
| | LL-bp1-001-R+ | 9 | 上原歩夢&澁谷かのん&日野下花帆 | O_RECOVER_MEMBER, O_DISCARD_HAND, O_BOOST_SCORE | | |
| --- | |
| ## 9. 優先順位と実装順序 | |
| 1. **Phase 1: 基本オペコード(実カード使用)** (高優先度) | |
| - O_DRAW, O_ADD_BLADES, O_ADD_HEARTS | |
| - O_RECOVER_MEMBER, O_RECOVER_LIVE | |
| - O_PAY_ENERGY, O_ACTIVATE_ENERGY | |
| - 実カード: PL!-sd1-001〜005 | |
| 2. **Phase 2: 選択・検索オペコード(実カード使用)** (高優先度) | |
| - O_LOOK_AND_CHOOSE, O_REVEAL_UNTIL | |
| - O_SELECT_MODE, O_SELECT_MEMBER | |
| - 実カード: PL!-sd1-004, PL!-sd1-005 | |
| 3. **Phase 3: 条件テスト(実カード使用)** (中優先度) | |
| - C_COUNT_*, C_COST_CHECK | |
| - C_LIFE_LEAD, C_HAS_* | |
| - 実カード: LL-bp1-001-R+ | |
| 4. **Phase 4: 複合・統合テスト** (中優先度) | |
| - コスト+効果の組み合わせ | |
| - トリガー連鎖 | |
| 5. **Phase 5: エッジケース** (低優先度) | |
| - 空ゾーン操作 | |
| - 境界値テスト | |