This commit is contained in:
2025-12-10 01:35:09 +09:00
parent 5b1ce14ed4
commit 8f72b9a812
20 changed files with 547 additions and 181 deletions
+98
View File
@@ -0,0 +1,98 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart'; // Import SharedPreferences
import 'package:game_test/providers/battle_provider.dart';
import 'package:game_test/providers/shop_provider.dart';
import 'package:game_test/game/models.dart';
import 'package:game_test/game/enums.dart';
import 'package:game_test/game/data/item_table.dart';
void main() {
group('BattleProvider Armor Reset Test', () {
late BattleProvider battleProvider;
late ShopProvider shopProvider;
setUp(() {
// Fix Binding has not yet been initialized error
TestWidgetsFlutterBinding.ensureInitialized();
// Mock SharedPreferences
SharedPreferences.setMockInitialValues({});
// Mock ItemTable data to prevent RangeError in initializeBattle
// initializeBattle accesses indices up to 5 for weapons and 3 for shields
ItemTable.weapons = List.generate(
10,
(index) => ItemTemplate(
id: "weapon_$index",
name: "Weapon $index",
description: "Test Weapon",
atkBonus: 10,
hpBonus: 0,
armorBonus: 0,
slot: EquipmentSlot.weapon,
effects: [],
price: 10,
),
);
ItemTable.shields = List.generate(
10,
(index) => ItemTemplate(
id: "shield_$index",
name: "Shield $index",
description: "Test Shield",
atkBonus: 0,
hpBonus: 0,
armorBonus: 10,
slot: EquipmentSlot.shield,
effects: [],
price: 10,
),
);
// Initialize other lists to empty to avoid null pointer if accessed loosely
ItemTable.armors = [];
ItemTable.accessories = [];
shopProvider = ShopProvider();
battleProvider = BattleProvider(shopProvider: shopProvider);
battleProvider.initializeBattle(); // Initialize player and stage 1
});
test('Armor should be reset to 0 when proceeding to next stage', () {
// 1. Setup initial state
battleProvider.player.armor = 50;
expect(
battleProvider.player.armor,
50,
reason: "Player armor should be set to 50 initially.",
);
// 2. Simulate proceeding to next stage
// Using proceedToNextStage which calls _prepareNextStage internally
battleProvider.proceedToNextStage();
// 3. Verify armor is reset
expect(battleProvider.stage, 2, reason: "Stage should advance to 2.");
expect(
battleProvider.player.armor,
0,
reason: "Player armor should be reset to 0 in the new stage.",
);
});
test('Armor should be reset to 0 when re-initializing battle', () {
// 1. Setup initial state
battleProvider.player.armor = 20;
expect(battleProvider.player.armor, 20);
// 2. Re-initialize
battleProvider.initializeBattle();
// 3. Verify armor is reset
expect(battleProvider.stage, 1);
expect(
battleProvider.player.armor,
0,
reason: "Player armor should be reset to 0 on initialization.",
);
});
});
}
+112
View File
@@ -0,0 +1,112 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:game_test/providers/battle_provider.dart';
import 'package:game_test/providers/shop_provider.dart';
import 'package:game_test/game/models.dart';
import 'package:game_test/game/enums.dart';
import 'package:game_test/game/data/item_table.dart';
import 'package:game_test/game/config/game_config.dart'; // Import GameConfig for multiplier
import 'dart:math'; // Import dart:math
void main() {
group('Disarm Mechanic (Weakened Attack) Test', () {
late BattleProvider battleProvider;
late ShopProvider shopProvider;
setUp(() {
TestWidgetsFlutterBinding.ensureInitialized();
SharedPreferences.setMockInitialValues({});
// Mock ItemTable
ItemTable.weapons = [];
ItemTable.shields = [];
ItemTable.armors = [];
ItemTable.accessories = [];
shopProvider = ShopProvider();
// Pass a fixed seed Random for predictable intent generation
battleProvider = BattleProvider(
shopProvider: shopProvider,
random: Random(0),
);
battleProvider.enemy = Character(
name: "Enemy",
maxHp: 100,
armor: 0,
atk: 50, // High base ATK for clear percentage reduction
baseDefense:
0, // Set to 0 to make canDefend false for predictable intent
);
battleProvider.player = Character(
name: "Player",
maxHp: 100,
armor: 0,
atk: 50, // High base ATK for clear percentage reduction
baseDefense: 10,
);
});
test('Enemy totalAtk reduced to 10% when Disarmed (Attack Forbidden)', () {
// 1. Verify initial ATK
expect(battleProvider.enemy.totalAtk, 50);
// 2. Apply Disarm
battleProvider.enemy.addStatusEffect(
StatusEffect(type: StatusEffectType.disarmed, duration: 2, value: 0),
);
// 3. Verify ATK is reduced to 10%
final expectedAtk = (50 * GameConfig.disarmedDamageMultiplier).toInt();
expect(battleProvider.enemy.totalAtk, expectedAtk);
// 4. Verify enemy still generates an attack intent (now predictable due to baseDefense: 0)
battleProvider.generateEnemyIntent();
final intent = battleProvider.currentEnemyIntent;
expect(intent, isNotNull);
expect(intent!.type, EnemyActionType.attack);
});
test(
'Player totalAtk reduced to 10% when Disarmed (Attack Forbidden) and turn proceeds',
() async {
// 1. Verify initial ATK
expect(battleProvider.player.totalAtk, 50);
// 2. Apply Disarm to Player
battleProvider.player.addStatusEffect(
StatusEffect(type: StatusEffectType.disarmed, duration: 2, value: 0),
);
// 3. Verify ATK is reduced to 10%
final expectedAtk = (50 * GameConfig.disarmedDamageMultiplier).toInt();
expect(battleProvider.player.totalAtk, expectedAtk);
battleProvider.isPlayerTurn = true;
// 4. Attempt Attack - it should now proceed, not be rejected
await battleProvider.playerAction(ActionType.attack, RiskLevel.safe);
// 5. Verify turn ended (proceeded)
expect(
battleProvider.isPlayerTurn,
false,
reason: "Turn should end after successful (weakened) action.",
);
// 6. Verify log no longer contains "Cannot attack" (optional but good)
expect(
battleProvider.logs.last,
isNot(contains("Cannot attack")),
reason: "Should not log 'Cannot attack' anymore.",
);
expect(
battleProvider.logs.last,
contains("Player chose to attack with safe risk"),
reason: "Should log normal attack.",
);
},
);
});
}