made icon optional and default to empty string & adjust all game instances
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 36s
Pull Request Pipeline / lint (pull_request) Successful in 46s

This commit is contained in:
2026-03-09 16:24:04 +01:00
parent 16dc9746bc
commit 43e9196dca
11 changed files with 367 additions and 254 deletions

View File

@@ -1,6 +1,6 @@
import 'package:clock/clock.dart'; import 'package:clock/clock.dart';
import 'package:uuid/uuid.dart';
import 'package:tallee/core/enums.dart'; import 'package:tallee/core/enums.dart';
import 'package:uuid/uuid.dart';
class Game { class Game {
final String id; final String id;
@@ -18,10 +18,11 @@ class Game {
required this.ruleset, required this.ruleset,
String? description, String? description,
required this.color, required this.color,
required this.icon, String? icon,
}) : id = id ?? const Uuid().v4(), }) : id = id ?? const Uuid().v4(),
createdAt = createdAt ?? clock.now(), createdAt = createdAt ?? clock.now(),
description = description ?? ''; description = description ?? '',
icon = icon ?? '';
@override @override
String toString() { String toString() {
@@ -49,4 +50,3 @@ class Game {
'icon': icon, 'icon': icon,
}; };
} }

View File

@@ -40,9 +40,16 @@ class Match {
Match.fromJson(Map<String, dynamic> json) Match.fromJson(Map<String, dynamic> json)
: id = json['id'], : id = json['id'],
createdAt = DateTime.parse(json['createdAt']), createdAt = DateTime.parse(json['createdAt']),
endedAt = json['endedAt'] != null ? DateTime.parse(json['endedAt']) : null, endedAt = json['endedAt'] != null
? DateTime.parse(json['endedAt'])
: null,
name = json['name'], name = json['name'],
game = Game(name: '', ruleset: Ruleset.singleWinner, description: '', color: GameColor.blue, icon: ''), // Populated during import via DataTransferService game = Game(
name: '',
ruleset: Ruleset.singleWinner,
description: '',
color: GameColor.blue,
), // Populated during import via DataTransferService
group = null, // Populated during import via DataTransferService group = null, // Populated during import via DataTransferService
players = [], // Populated during import via DataTransferService players = [], // Populated during import via DataTransferService
notes = json['notes'] ?? ''; notes = json['notes'] ?? '';

View File

@@ -42,7 +42,12 @@ class _HomeViewState extends State<HomeView> {
2, 2,
Match( Match(
name: 'Skeleton Match', name: 'Skeleton Match',
game: Game(name: '', ruleset: Ruleset.singleWinner, description: '', color: GameColor.blue, icon: ''), game: Game(
name: '',
ruleset: Ruleset.singleWinner,
description: '',
color: GameColor.blue,
),
group: Group( group: Group(
name: 'Skeleton Group', name: 'Skeleton Group',
description: '', description: '',
@@ -104,7 +109,9 @@ class _HomeViewState extends State<HomeView> {
if (recentMatches.isNotEmpty) if (recentMatches.isNotEmpty)
for (Match match in recentMatches) for (Match match in recentMatches)
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0), padding: const EdgeInsets.symmetric(
vertical: 6.0,
),
child: MatchTile( child: MatchTile(
compact: true, compact: true,
width: constraints.maxWidth * 0.9, width: constraints.maxWidth * 0.9,
@@ -113,7 +120,8 @@ class _HomeViewState extends State<HomeView> {
await Navigator.of(context).push( await Navigator.of(context).push(
adaptivePageRoute( adaptivePageRoute(
fullscreenDialog: true, fullscreenDialog: true,
builder: (context) => MatchResultView(match: match), builder: (context) =>
MatchResultView(match: match),
), ),
); );
await updatedWinnerInRecentMatches(match.id); await updatedWinnerInRecentMatches(match.id);
@@ -121,7 +129,10 @@ class _HomeViewState extends State<HomeView> {
), ),
) )
else else
Center(heightFactor: 5, child: Text(loc.no_recent_matches_available)), Center(
heightFactor: 5,
child: Text(loc.no_recent_matches_available),
),
], ],
), ),
), ),
@@ -137,22 +148,40 @@ class _HomeViewState extends State<HomeView> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
QuickCreateButton(text: 'Category 1', onPressed: () {}), QuickCreateButton(
QuickCreateButton(text: 'Category 2', onPressed: () {}), text: 'Category 1',
onPressed: () {},
),
QuickCreateButton(
text: 'Category 2',
onPressed: () {},
),
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
QuickCreateButton(text: 'Category 3', onPressed: () {}), QuickCreateButton(
QuickCreateButton(text: 'Category 4', onPressed: () {}), text: 'Category 3',
onPressed: () {},
),
QuickCreateButton(
text: 'Category 4',
onPressed: () {},
),
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
QuickCreateButton(text: 'Category 5', onPressed: () {}), QuickCreateButton(
QuickCreateButton(text: 'Category 6', onPressed: () {}), text: 'Category 5',
onPressed: () {},
),
QuickCreateButton(
text: 'Category 6',
onPressed: () {},
),
], ],
), ),
], ],
@@ -181,7 +210,9 @@ class _HomeViewState extends State<HomeView> {
matchCount = results[0] as int; matchCount = results[0] as int;
groupCount = results[1] as int; groupCount = results[1] as int;
loadedRecentMatches = results[2] as List<Match>; loadedRecentMatches = results[2] as List<Match>;
recentMatches = (loadedRecentMatches..sort((a, b) => b.createdAt.compareTo(a.createdAt))) recentMatches =
(loadedRecentMatches
..sort((a, b) => b.createdAt.compareTo(a.createdAt)))
.take(2) .take(2)
.toList(); .toList();
if (mounted) { if (mounted) {

View File

@@ -261,7 +261,6 @@ class _CreateGameViewState extends State<CreateGameView> {
description: _descriptionController.text.trim(), description: _descriptionController.text.trim(),
ruleset: selectedRuleset!, ruleset: selectedRuleset!,
color: selectedColor!, color: selectedColor!,
icon: '',
); );
if (isEditing) { if (isEditing) {
await handleGameUpdate(newGame); await handleGameUpdate(newGame);

View File

@@ -44,7 +44,6 @@ class _MatchViewState extends State<MatchView> {
ruleset: Ruleset.singleWinner, ruleset: Ruleset.singleWinner,
description: '', description: '',
color: GameColor.blue, color: GameColor.blue,
icon: '',
), ),
group: Group( group: Group(
name: 'Group name', name: 'Group name',

View File

@@ -40,24 +40,29 @@ class DataTransferService {
'players': players.map((p) => p.toJson()).toList(), 'players': players.map((p) => p.toJson()).toList(),
'games': games.map((g) => g.toJson()).toList(), 'games': games.map((g) => g.toJson()).toList(),
'groups': groups 'groups': groups
.map((g) => { .map(
(g) => {
'id': g.id, 'id': g.id,
'name': g.name, 'name': g.name,
'description': g.description, 'description': g.description,
'createdAt': g.createdAt.toIso8601String(), 'createdAt': g.createdAt.toIso8601String(),
'memberIds': (g.members).map((m) => m.id).toList(), 'memberIds': (g.members).map((m) => m.id).toList(),
}) },
)
.toList(), .toList(),
'teams': teams 'teams': teams
.map((t) => { .map(
(t) => {
'id': t.id, 'id': t.id,
'name': t.name, 'name': t.name,
'createdAt': t.createdAt.toIso8601String(), 'createdAt': t.createdAt.toIso8601String(),
'memberIds': (t.members).map((m) => m.id).toList(), 'memberIds': (t.members).map((m) => m.id).toList(),
}) },
)
.toList(), .toList(),
'matches': matches 'matches': matches
.map((m) => { .map(
(m) => {
'id': m.id, 'id': m.id,
'name': m.name, 'name': m.name,
'createdAt': m.createdAt.toIso8601String(), 'createdAt': m.createdAt.toIso8601String(),
@@ -66,7 +71,8 @@ class DataTransferService {
'groupId': m.group?.id, 'groupId': m.group?.id,
'playerIds': m.players.map((p) => p.id).toList(), 'playerIds': m.players.map((p) => p.id).toList(),
'notes': m.notes, 'notes': m.notes,
}) },
)
.toList(), .toList(),
}; };
@@ -80,7 +86,7 @@ class DataTransferService {
/// [fileName] The desired name for the exported file (without extension). /// [fileName] The desired name for the exported file (without extension).
static Future<ExportResult> exportData( static Future<ExportResult> exportData(
String jsonString, String jsonString,
String fileName String fileName,
) async { ) async {
try { try {
final bytes = Uint8List.fromList(utf8.encode(jsonString)); final bytes = Uint8List.fromList(utf8.encode(jsonString));
@@ -94,7 +100,6 @@ class DataTransferService {
} else { } else {
return ExportResult.success; return ExportResult.success;
} }
} catch (e, stack) { } catch (e, stack) {
print('[exportData] $e'); print('[exportData] $e');
print(stack); print(stack);
@@ -122,13 +127,19 @@ class DataTransferService {
final isValid = await _validateJsonSchema(jsonString); final isValid = await _validateJsonSchema(jsonString);
if (!isValid) return ImportResult.invalidSchema; if (!isValid) return ImportResult.invalidSchema;
final Map<String, dynamic> decoded = json.decode(jsonString) as Map<String, dynamic>; final Map<String, dynamic> decoded =
json.decode(jsonString) as Map<String, dynamic>;
final List<dynamic> playersJson = (decoded['players'] as List<dynamic>?) ?? []; final List<dynamic> playersJson =
final List<dynamic> gamesJson = (decoded['games'] as List<dynamic>?) ?? []; (decoded['players'] as List<dynamic>?) ?? [];
final List<dynamic> groupsJson = (decoded['groups'] as List<dynamic>?) ?? []; final List<dynamic> gamesJson =
final List<dynamic> teamsJson = (decoded['teams'] as List<dynamic>?) ?? []; (decoded['games'] as List<dynamic>?) ?? [];
final List<dynamic> matchesJson = (decoded['matches'] as List<dynamic>?) ?? []; final List<dynamic> groupsJson =
(decoded['groups'] as List<dynamic>?) ?? [];
final List<dynamic> teamsJson =
(decoded['teams'] as List<dynamic>?) ?? [];
final List<dynamic> matchesJson =
(decoded['matches'] as List<dynamic>?) ?? [];
// Import Players // Import Players
final List<Player> importedPlayers = playersJson final List<Player> importedPlayers = playersJson
@@ -151,7 +162,8 @@ class DataTransferService {
// Import Groups // Import Groups
final List<Group> importedGroups = groupsJson.map((g) { final List<Group> importedGroups = groupsJson.map((g) {
final map = g as Map<String, dynamic>; final map = g as Map<String, dynamic>;
final memberIds = (map['memberIds'] as List<dynamic>? ?? []).cast<String>(); final memberIds = (map['memberIds'] as List<dynamic>? ?? [])
.cast<String>();
final members = memberIds final members = memberIds
.map((id) => playerById[id]) .map((id) => playerById[id])
@@ -174,7 +186,8 @@ class DataTransferService {
// Import Teams // Import Teams
final List<Team> importedTeams = teamsJson.map((t) { final List<Team> importedTeams = teamsJson.map((t) {
final map = t as Map<String, dynamic>; final map = t as Map<String, dynamic>;
final memberIds = (map['memberIds'] as List<dynamic>? ?? []).cast<String>(); final memberIds = (map['memberIds'] as List<dynamic>? ?? [])
.cast<String>();
final members = memberIds final members = memberIds
.map((id) => playerById[id]) .map((id) => playerById[id])
@@ -195,8 +208,11 @@ class DataTransferService {
final String gameId = map['gameId'] as String; final String gameId = map['gameId'] as String;
final String? groupId = map['groupId'] as String?; final String? groupId = map['groupId'] as String?;
final List<String> playerIds = (map['playerIds'] as List<dynamic>? ?? []).cast<String>(); final List<String> playerIds =
final DateTime? endedAt = map['endedAt'] != null ? DateTime.parse(map['endedAt'] as String) : null; (map['playerIds'] as List<dynamic>? ?? []).cast<String>();
final DateTime? endedAt = map['endedAt'] != null
? DateTime.parse(map['endedAt'] as String)
: null;
final game = gameById[gameId]; final game = gameById[gameId];
final group = (groupId == null) ? null : groupById[groupId]; final group = (groupId == null) ? null : groupById[groupId];
@@ -208,7 +224,14 @@ class DataTransferService {
return Match( return Match(
id: map['id'] as String, id: map['id'] as String,
name: map['name'] as String, name: map['name'] as String,
game: game ?? Game(name: 'Unknown', ruleset: Ruleset.singleWinner, description: '', color: GameColor.blue, icon: ''), game:
game ??
Game(
name: 'Unknown',
ruleset: Ruleset.singleWinner,
description: '',
color: GameColor.blue,
),
group: group, group: group,
players: players, players: players,
createdAt: DateTime.parse(map['createdAt'] as String), createdAt: DateTime.parse(map['createdAt'] as String),

View File

@@ -56,7 +56,6 @@ void main() {
ruleset: Ruleset.singleWinner, ruleset: Ruleset.singleWinner,
description: 'A test game', description: 'A test game',
color: GameColor.blue, color: GameColor.blue,
icon: '',
); );
testMatch1 = Match( testMatch1 = Match(
name: 'First Test Match', name: 'First Test Match',

View File

@@ -2,12 +2,12 @@ import 'package:clock/clock.dart';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:drift/native.dart'; import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:tallee/core/enums.dart';
import 'package:tallee/data/db/database.dart'; import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/dto/game.dart'; import 'package:tallee/data/dto/game.dart';
import 'package:tallee/data/dto/match.dart'; import 'package:tallee/data/dto/match.dart';
import 'package:tallee/data/dto/player.dart'; import 'package:tallee/data/dto/player.dart';
import 'package:tallee/data/dto/team.dart'; import 'package:tallee/data/dto/team.dart';
import 'package:tallee/core/enums.dart';
void main() { void main() {
late AppDatabase database; late AppDatabase database;
@@ -37,20 +37,21 @@ void main() {
testPlayer2 = Player(name: 'Bob', description: ''); testPlayer2 = Player(name: 'Bob', description: '');
testPlayer3 = Player(name: 'Charlie', description: ''); testPlayer3 = Player(name: 'Charlie', description: '');
testPlayer4 = Player(name: 'Diana', description: ''); testPlayer4 = Player(name: 'Diana', description: '');
testTeam1 = Team( testTeam1 = Team(name: 'Team Alpha', members: [testPlayer1, testPlayer2]);
name: 'Team Alpha', testTeam2 = Team(name: 'Team Beta', members: [testPlayer3, testPlayer4]);
members: [testPlayer1, testPlayer2], testTeam3 = Team(name: 'Team Gamma', members: [testPlayer1, testPlayer3]);
testGame1 = Game(
name: 'Game 1',
ruleset: Ruleset.singleWinner,
description: 'Test game 1',
color: GameColor.blue,
); );
testTeam2 = Team( testGame2 = Game(
name: 'Team Beta', name: 'Game 2',
members: [testPlayer3, testPlayer4], ruleset: Ruleset.highestScore,
description: 'Test game 2',
color: GameColor.red,
); );
testTeam3 = Team(
name: 'Team Gamma',
members: [testPlayer1, testPlayer3],
);
testGame1 = Game(name: 'Game 1', ruleset: Ruleset.singleWinner, description: 'Test game 1', color: GameColor.blue, icon: '');
testGame2 = Game(name: 'Game 2', ruleset: Ruleset.highestScore, description: 'Test game 2', color: GameColor.red, icon: '');
}); });
await database.playerDao.addPlayersAsList( await database.playerDao.addPlayersAsList(
@@ -65,7 +66,6 @@ void main() {
}); });
group('Team Tests', () { group('Team Tests', () {
// Verifies that a single team can be added and retrieved with all fields intact. // Verifies that a single team can be added and retrieved with all fields intact.
test('Adding and fetching a single team works correctly', () async { test('Adding and fetching a single team works correctly', () async {
final added = await database.teamDao.addTeam(team: testTeam1); final added = await database.teamDao.addTeam(team: testTeam1);
@@ -285,10 +285,7 @@ void main() {
test('Updating team name to empty string works', () async { test('Updating team name to empty string works', () async {
await database.teamDao.addTeam(team: testTeam1); await database.teamDao.addTeam(team: testTeam1);
await database.teamDao.updateTeamName( await database.teamDao.updateTeamName(teamId: testTeam1.id, newName: '');
teamId: testTeam1.id,
newName: '',
);
final updatedTeam = await database.teamDao.getTeamById( final updatedTeam = await database.teamDao.getTeamById(
teamId: testTeam1.id, teamId: testTeam1.id,
@@ -350,9 +347,7 @@ void main() {
await database.matchDao.addMatch(match: match2); await database.matchDao.addMatch(match: match2);
// Add teams to database // Add teams to database
await database.teamDao.addTeamsAsList( await database.teamDao.addTeamsAsList(teams: [testTeam1, testTeam3]);
teams: [testTeam1, testTeam3],
);
// Associate players with teams through match1 // Associate players with teams through match1
// testTeam1: player1, player2 // testTeam1: player1, player2
@@ -420,10 +415,11 @@ void main() {
final allTeams = await database.teamDao.getAllTeams(); final allTeams = await database.teamDao.getAllTeams();
expect(allTeams.length, 3); expect(allTeams.length, 3);
expect( expect(allTeams.map((t) => t.id).toSet(), {
allTeams.map((t) => t.id).toSet(), testTeam1.id,
{testTeam1.id, testTeam2.id, testTeam3.id}, testTeam2.id,
); testTeam3.id,
});
}); });
// Verifies that teamExists returns false for deleted teams. // Verifies that teamExists returns false for deleted teams.
@@ -462,9 +458,7 @@ void main() {
// Verifies that addTeam after deleteAllTeams works correctly. // Verifies that addTeam after deleteAllTeams works correctly.
test('Adding team after deleteAllTeams works correctly', () async { test('Adding team after deleteAllTeams works correctly', () async {
await database.teamDao.addTeamsAsList( await database.teamDao.addTeamsAsList(teams: [testTeam1, testTeam2]);
teams: [testTeam1, testTeam2],
);
expect(await database.teamDao.getTeamCount(), 2); expect(await database.teamDao.getTeamCount(), 2);
await database.teamDao.deleteAllTeams(); await database.teamDao.deleteAllTeams();

View File

@@ -44,7 +44,6 @@ void main() {
ruleset: Ruleset.highestScore, ruleset: Ruleset.highestScore,
description: 'A board game about real estate', description: 'A board game about real estate',
color: GameColor.orange, color: GameColor.orange,
icon: '',
); );
}); });
}); });
@@ -54,7 +53,6 @@ void main() {
}); });
group('Game Tests', () { group('Game Tests', () {
// Verifies that getAllGames returns an empty list when the database has no games. // Verifies that getAllGames returns an empty list when the database has no games.
test('getAllGames returns empty list when no games exist', () async { test('getAllGames returns empty list when no games exist', () async {
final allGames = await database.gameDao.getAllGames(); final allGames = await database.gameDao.getAllGames();
@@ -134,7 +132,12 @@ void main() {
// Verifies that a game with empty optional fields can be added and retrieved. // Verifies that a game with empty optional fields can be added and retrieved.
test('addGame handles game with null optional fields', () async { test('addGame handles game with null optional fields', () async {
final gameWithNulls = Game(name: 'Simple Game', ruleset: Ruleset.lowestScore, description: 'A simple game', color: GameColor.green, icon: ''); final gameWithNulls = Game(
name: 'Simple Game',
ruleset: Ruleset.lowestScore,
description: 'A simple game',
color: GameColor.green,
);
final result = await database.gameDao.addGame(game: gameWithNulls); final result = await database.gameDao.addGame(game: gameWithNulls);
expect(result, true); expect(result, true);
@@ -419,9 +422,7 @@ void main() {
// Verifies that getGameCount updates correctly after deleting a game. // Verifies that getGameCount updates correctly after deleting a game.
test('getGameCount updates correctly after deletion', () async { test('getGameCount updates correctly after deletion', () async {
await database.gameDao.addGamesAsList( await database.gameDao.addGamesAsList(games: [testGame1, testGame2]);
games: [testGame1, testGame2],
);
final countBefore = await database.gameDao.getGameCount(); final countBefore = await database.gameDao.getGameCount();
expect(countBefore, 2); expect(countBefore, 2);
@@ -461,7 +462,6 @@ void main() {
ruleset: Ruleset.multipleWinners, ruleset: Ruleset.multipleWinners,
description: 'Description with émojis 🎮🎲', description: 'Description with émojis 🎮🎲',
color: GameColor.purple, color: GameColor.purple,
icon: '',
); );
await database.gameDao.addGame(game: specialGame); await database.gameDao.addGame(game: specialGame);
@@ -478,7 +478,6 @@ void main() {
name: '', name: '',
ruleset: Ruleset.singleWinner, ruleset: Ruleset.singleWinner,
description: '', description: '',
icon: '',
color: GameColor.red, color: GameColor.red,
); );
await database.gameDao.addGame(game: emptyGame); await database.gameDao.addGame(game: emptyGame);
@@ -500,7 +499,6 @@ void main() {
description: longString, description: longString,
ruleset: Ruleset.multipleWinners, ruleset: Ruleset.multipleWinners,
color: GameColor.yellow, color: GameColor.yellow,
icon: '',
); );
await database.gameDao.addGame(game: longGame); await database.gameDao.addGame(game: longGame);

View File

@@ -48,7 +48,12 @@ void main() {
description: '', description: '',
members: [testPlayer1, testPlayer2, testPlayer3], members: [testPlayer1, testPlayer2, testPlayer3],
); );
testGame = Game(name: 'Test Game', ruleset: Ruleset.singleWinner, description: 'A test game', color: GameColor.blue, icon: ''); testGame = Game(
name: 'Test Game',
ruleset: Ruleset.singleWinner,
description: 'A test game',
color: GameColor.blue,
);
testMatchOnlyGroup = Match( testMatchOnlyGroup = Match(
name: 'Test Match with Group', name: 'Test Match with Group',
game: testGame, game: testGame,
@@ -61,14 +66,8 @@ void main() {
players: [testPlayer4, testPlayer5, testPlayer6], players: [testPlayer4, testPlayer5, testPlayer6],
notes: '', notes: '',
); );
testTeam1 = Team( testTeam1 = Team(name: 'Team Alpha', members: [testPlayer1, testPlayer2]);
name: 'Team Alpha', testTeam2 = Team(name: 'Team Beta', members: [testPlayer3, testPlayer4]);
members: [testPlayer1, testPlayer2],
);
testTeam2 = Team(
name: 'Team Beta',
members: [testPlayer3, testPlayer4],
);
}); });
await database.playerDao.addPlayersAsList( await database.playerDao.addPlayersAsList(
players: [ players: [
@@ -88,7 +87,6 @@ void main() {
}); });
group('Player-Match Tests', () { group('Player-Match Tests', () {
// Verifies that matchHasPlayers returns false initially and true after adding a player. // Verifies that matchHasPlayers returns false initially and true after adding a player.
test('Match has player works correctly', () async { test('Match has player works correctly', () async {
await database.matchDao.addMatch(match: testMatchOnlyGroup); await database.matchDao.addMatch(match: testMatchOnlyGroup);
@@ -153,26 +151,23 @@ void main() {
); );
expect(result.players.length, testMatchOnlyPlayers.players.length - 1); expect(result.players.length, testMatchOnlyPlayers.players.length - 1);
final playerExists = result.players.any( final playerExists = result.players.any((p) => p.id == playerToRemove.id);
(p) => p.id == playerToRemove.id,
);
expect(playerExists, false); expect(playerExists, false);
}); });
// Verifies that getPlayersOfMatch returns all players of a match with correct data. // Verifies that getPlayersOfMatch returns all players of a match with correct data.
test('Retrieving players of a match works correctly', () async { test('Retrieving players of a match works correctly', () async {
await database.matchDao.addMatch(match: testMatchOnlyPlayers); await database.matchDao.addMatch(match: testMatchOnlyPlayers);
final players = await database.playerMatchDao.getPlayersOfMatch( final players =
await database.playerMatchDao.getPlayersOfMatch(
matchId: testMatchOnlyPlayers.id, matchId: testMatchOnlyPlayers.id,
) ?? []; ) ??
[];
for (int i = 0; i < players.length; i++) { for (int i = 0; i < players.length; i++) {
expect(players[i].id, testMatchOnlyPlayers.players[i].id); expect(players[i].id, testMatchOnlyPlayers.players[i].id);
expect(players[i].name, testMatchOnlyPlayers.players[i].name); expect(players[i].name, testMatchOnlyPlayers.players[i].name);
expect( expect(players[i].createdAt, testMatchOnlyPlayers.players[i].createdAt);
players[i].createdAt,
testMatchOnlyPlayers.players[i].createdAt,
);
} }
}); });
@@ -225,8 +220,18 @@ void main() {
'Adding the same player to separate matches works correctly', 'Adding the same player to separate matches works correctly',
() async { () async {
final playersList = [testPlayer1, testPlayer2, testPlayer3]; final playersList = [testPlayer1, testPlayer2, testPlayer3];
final match1 = Match(name: 'Match 1', game: testGame, players: playersList, notes: ''); final match1 = Match(
final match2 = Match(name: 'Match 2', game: testGame, players: playersList, notes: ''); name: 'Match 1',
game: testGame,
players: playersList,
notes: '',
);
final match2 = Match(
name: 'Match 2',
game: testGame,
players: playersList,
notes: '',
);
await Future.wait([ await Future.wait([
database.matchDao.addMatch(match: match1), database.matchDao.addMatch(match: match1),
@@ -299,7 +304,9 @@ void main() {
}); });
// Verifies that getPlayerScore returns null for non-existent player-match combination. // Verifies that getPlayerScore returns null for non-existent player-match combination.
test('getPlayerScore returns null for non-existent player in match', () async { test(
'getPlayerScore returns null for non-existent player in match',
() async {
await database.matchDao.addMatch(match: testMatchOnlyGroup); await database.matchDao.addMatch(match: testMatchOnlyGroup);
final score = await database.playerMatchDao.getPlayerScore( final score = await database.playerMatchDao.getPlayerScore(
@@ -308,7 +315,8 @@ void main() {
); );
expect(score, isNull); expect(score, isNull);
}); },
);
// Verifies that updatePlayerScore updates the score correctly. // Verifies that updatePlayerScore updates the score correctly.
test('updatePlayerScore updates score correctly', () async { test('updatePlayerScore updates score correctly', () async {
@@ -331,7 +339,9 @@ void main() {
}); });
// Verifies that updatePlayerScore returns false for non-existent player-match. // Verifies that updatePlayerScore returns false for non-existent player-match.
test('updatePlayerScore returns false for non-existent player-match', () async { test(
'updatePlayerScore returns false for non-existent player-match',
() async {
await database.matchDao.addMatch(match: testMatchOnlyGroup); await database.matchDao.addMatch(match: testMatchOnlyGroup);
final updated = await database.playerMatchDao.updatePlayerScore( final updated = await database.playerMatchDao.updatePlayerScore(
@@ -341,7 +351,8 @@ void main() {
); );
expect(updated, false); expect(updated, false);
}); },
);
// Verifies that adding a player with teamId works correctly. // Verifies that adding a player with teamId works correctly.
test('Adding player with teamId works correctly', () async { test('Adding player with teamId works correctly', () async {
@@ -431,7 +442,9 @@ void main() {
}); });
// Verifies that updatePlayerTeam returns false for non-existent player-match. // Verifies that updatePlayerTeam returns false for non-existent player-match.
test('updatePlayerTeam returns false for non-existent player-match', () async { test(
'updatePlayerTeam returns false for non-existent player-match',
() async {
await database.matchDao.addMatch(match: testMatchOnlyGroup); await database.matchDao.addMatch(match: testMatchOnlyGroup);
final updated = await database.playerMatchDao.updatePlayerTeam( final updated = await database.playerMatchDao.updatePlayerTeam(
@@ -441,7 +454,8 @@ void main() {
); );
expect(updated, false); expect(updated, false);
}); },
);
// Verifies that getPlayersInTeam returns empty list for non-existent team. // Verifies that getPlayersInTeam returns empty list for non-existent team.
test('getPlayersInTeam returns empty list for non-existent team', () async { test('getPlayersInTeam returns empty list for non-existent team', () async {
@@ -483,7 +497,9 @@ void main() {
}); });
// Verifies that removePlayerFromMatch returns false for non-existent player. // Verifies that removePlayerFromMatch returns false for non-existent player.
test('removePlayerFromMatch returns false for non-existent player', () async { test(
'removePlayerFromMatch returns false for non-existent player',
() async {
await database.matchDao.addMatch(match: testMatchOnlyPlayers); await database.matchDao.addMatch(match: testMatchOnlyPlayers);
final removed = await database.playerMatchDao.removePlayerFromMatch( final removed = await database.playerMatchDao.removePlayerFromMatch(
@@ -492,7 +508,8 @@ void main() {
); );
expect(removed, false); expect(removed, false);
}); },
);
// Verifies that adding the same player twice to the same match is ignored. // Verifies that adding the same player twice to the same match is ignored.
test('Adding same player twice to same match is ignored', () async { test('Adding same player twice to same match is ignored', () async {
@@ -528,7 +545,9 @@ void main() {
}); });
// Verifies that updatePlayersFromMatch with empty list removes all players. // Verifies that updatePlayersFromMatch with empty list removes all players.
test('updatePlayersFromMatch with empty list removes all players', () async { test(
'updatePlayersFromMatch with empty list removes all players',
() async {
await database.matchDao.addMatch(match: testMatchOnlyPlayers); await database.matchDao.addMatch(match: testMatchOnlyPlayers);
// Verify players exist initially // Verify players exist initially
@@ -548,7 +567,8 @@ void main() {
matchId: testMatchOnlyPlayers.id, matchId: testMatchOnlyPlayers.id,
); );
expect(players, isNull); expect(players, isNull);
}); },
);
// Verifies that updatePlayersFromMatch with same players makes no changes. // Verifies that updatePlayersFromMatch with same players makes no changes.
test('updatePlayersFromMatch with same players makes no changes', () async { test('updatePlayersFromMatch with same players makes no changes', () async {
@@ -702,7 +722,9 @@ void main() {
}); });
// Verifies that getPlayersInTeam returns empty list for non-existent match. // Verifies that getPlayersInTeam returns empty list for non-existent match.
test('getPlayersInTeam returns empty list for non-existent match', () async { test(
'getPlayersInTeam returns empty list for non-existent match',
() async {
await database.teamDao.addTeam(team: testTeam1); await database.teamDao.addTeam(team: testTeam1);
final players = await database.playerMatchDao.getPlayersInTeam( final players = await database.playerMatchDao.getPlayersInTeam(
@@ -711,7 +733,8 @@ void main() {
); );
expect(players.isEmpty, true); expect(players.isEmpty, true);
}); },
);
// Verifies that players in different teams within the same match are returned correctly. // Verifies that players in different teams within the same match are returned correctly.
test('Players in different teams within same match are separate', () async { test('Players in different teams within same match are separate', () async {
@@ -759,8 +782,18 @@ void main() {
// Verifies that removePlayerFromMatch does not affect other matches. // Verifies that removePlayerFromMatch does not affect other matches.
test('removePlayerFromMatch does not affect other matches', () async { test('removePlayerFromMatch does not affect other matches', () async {
final playersList = [testPlayer1, testPlayer2]; final playersList = [testPlayer1, testPlayer2];
final match1 = Match(name: 'Match 1', game: testGame, players: playersList, notes: ''); final match1 = Match(
final match2 = Match(name: 'Match 2', game: testGame, players: playersList, notes: ''); name: 'Match 1',
game: testGame,
players: playersList,
notes: '',
);
final match2 = Match(
name: 'Match 2',
game: testGame,
players: playersList,
notes: '',
);
await Future.wait([ await Future.wait([
database.matchDao.addMatch(match: match1), database.matchDao.addMatch(match: match1),
@@ -792,8 +825,18 @@ void main() {
// Verifies that updating scores for players in different matches are independent. // Verifies that updating scores for players in different matches are independent.
test('Player scores are independent across matches', () async { test('Player scores are independent across matches', () async {
final playersList = [testPlayer1]; final playersList = [testPlayer1];
final match1 = Match(name: 'Match 1', game: testGame, players: playersList, notes: ''); final match1 = Match(
final match2 = Match(name: 'Match 2', game: testGame, players: playersList, notes: ''); name: 'Match 1',
game: testGame,
players: playersList,
notes: '',
);
final match2 = Match(
name: 'Match 2',
game: testGame,
players: playersList,
notes: '',
);
await Future.wait([ await Future.wait([
database.matchDao.addMatch(match: match1), database.matchDao.addMatch(match: match1),
@@ -829,7 +872,9 @@ void main() {
}); });
// Verifies that updatePlayersFromMatch on non-existent match fails with constraint error. // Verifies that updatePlayersFromMatch on non-existent match fails with constraint error.
test('updatePlayersFromMatch on non-existent match fails with foreign key constraint', () async { test(
'updatePlayersFromMatch on non-existent match fails with foreign key constraint',
() async {
// Should throw due to foreign key constraint - match doesn't exist // Should throw due to foreign key constraint - match doesn't exist
await expectLater( await expectLater(
database.playerMatchDao.updatePlayersFromMatch( database.playerMatchDao.updatePlayersFromMatch(
@@ -838,7 +883,8 @@ void main() {
), ),
throwsA(anything), throwsA(anything),
); );
}); },
);
// Verifies that a player can be in a match without being assigned to a team. // Verifies that a player can be in a match without being assigned to a team.
test('Player can exist in match without team assignment', () async { test('Player can exist in match without team assignment', () async {

View File

@@ -2,11 +2,11 @@ import 'package:clock/clock.dart';
import 'package:drift/drift.dart' hide isNull, isNotNull; import 'package:drift/drift.dart' hide isNull, isNotNull;
import 'package:drift/native.dart'; import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:tallee/core/enums.dart';
import 'package:tallee/data/db/database.dart'; import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/dto/game.dart'; import 'package:tallee/data/dto/game.dart';
import 'package:tallee/data/dto/match.dart'; import 'package:tallee/data/dto/match.dart';
import 'package:tallee/data/dto/player.dart'; import 'package:tallee/data/dto/player.dart';
import 'package:tallee/core/enums.dart';
void main() { void main() {
late AppDatabase database; late AppDatabase database;
@@ -32,7 +32,12 @@ void main() {
testPlayer1 = Player(name: 'Alice', description: ''); testPlayer1 = Player(name: 'Alice', description: '');
testPlayer2 = Player(name: 'Bob', description: ''); testPlayer2 = Player(name: 'Bob', description: '');
testPlayer3 = Player(name: 'Charlie', description: ''); testPlayer3 = Player(name: 'Charlie', description: '');
testGame = Game(name: 'Test Game', ruleset: Ruleset.singleWinner, description: 'A test game', color: GameColor.blue, icon: ''); testGame = Game(
name: 'Test Game',
ruleset: Ruleset.singleWinner,
description: 'A test game',
color: GameColor.blue,
);
testMatch1 = Match( testMatch1 = Match(
name: 'Test Match 1', name: 'Test Match 1',
game: testGame, game: testGame,
@@ -60,7 +65,6 @@ void main() {
}); });
group('Score Tests', () { group('Score Tests', () {
// Verifies that a score can be added and retrieved with all fields intact. // Verifies that a score can be added and retrieved with all fields intact.
test('Adding and fetching a score works correctly', () async { test('Adding and fetching a score works correctly', () async {
await database.scoreDao.addScore( await database.scoreDao.addScore(
@@ -431,13 +435,16 @@ void main() {
}); });
// Verifies that getScoresForMatch returns empty list for match with no scores. // Verifies that getScoresForMatch returns empty list for match with no scores.
test('Getting scores for match with no scores returns empty list', () async { test(
'Getting scores for match with no scores returns empty list',
() async {
final scores = await database.scoreDao.getScoresForMatch( final scores = await database.scoreDao.getScoresForMatch(
matchId: testMatch1.id, matchId: testMatch1.id,
); );
expect(scores.isEmpty, true); expect(scores.isEmpty, true);
}); },
);
// Verifies that getPlayerScoresInMatch returns empty list when player has no scores. // Verifies that getPlayerScoresInMatch returns empty list when player has no scores.
test('Getting player scores with no scores returns empty list', () async { test('Getting player scores with no scores returns empty list', () async {
@@ -666,7 +673,9 @@ void main() {
}); });
// Verifies that updating one player's score doesn't affect another player's score in same round. // Verifies that updating one player's score doesn't affect another player's score in same round.
test('Updating one player score does not affect other players in same round', () async { test(
'Updating one player score does not affect other players in same round',
() async {
await database.scoreDao.addScore( await database.scoreDao.addScore(
playerId: testPlayer1.id, playerId: testPlayer1.id,
matchId: testMatch1.id, matchId: testMatch1.id,
@@ -702,10 +711,20 @@ void main() {
); );
expect(scores.length, 3); expect(scores.length, 3);
expect(scores.where((s) => s.playerId == testPlayer1.id).first.score, 10); expect(
expect(scores.where((s) => s.playerId == testPlayer2.id).first.score, 99); scores.where((s) => s.playerId == testPlayer1.id).first.score,
expect(scores.where((s) => s.playerId == testPlayer3.id).first.score, 30); 10,
}); );
expect(
scores.where((s) => s.playerId == testPlayer2.id).first.score,
99,
);
expect(
scores.where((s) => s.playerId == testPlayer3.id).first.score,
30,
);
},
);
// Verifies that deleting a player's scores only affects that specific player. // Verifies that deleting a player's scores only affects that specific player.
test('Deleting player scores only affects target player', () async { test('Deleting player scores only affects target player', () async {
@@ -724,9 +743,7 @@ void main() {
change: 20, change: 20,
); );
await database.scoreDao.deleteScoresForPlayer( await database.scoreDao.deleteScoresForPlayer(playerId: testPlayer1.id);
playerId: testPlayer1.id,
);
final match1Scores = await database.scoreDao.getScoresForMatch( final match1Scores = await database.scoreDao.getScoresForMatch(
matchId: testMatch1.id, matchId: testMatch1.id,