Updated player dao + tests

This commit is contained in:
2026-04-24 14:29:01 +02:00
parent 8df5c24fa8
commit 95cad71ea0
2 changed files with 357 additions and 372 deletions

View File

@@ -10,35 +10,7 @@ part 'player_dao.g.dart';
class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin { class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
PlayerDao(super.db); PlayerDao(super.db);
/// Retrieves all players from the database. /* Create */
Future<List<Player>> getAllPlayers() async {
final query = select(playerTable);
final result = await query.get();
return result
.map(
(row) => Player(
id: row.id,
name: row.name,
description: row.description,
createdAt: row.createdAt,
nameCount: row.nameCount,
),
)
.toList();
}
/// Retrieves a [Player] by their [id].
Future<Player> getPlayerById({required String playerId}) async {
final query = select(playerTable)..where((p) => p.id.equals(playerId));
final result = await query.getSingle();
return Player(
id: result.id,
name: result.name,
description: result.description,
createdAt: result.createdAt,
nameCount: result.nameCount,
);
}
/// Adds a new [player] to the database. /// Adds a new [player] to the database.
/// If a player with the same ID already exists, updates their name to /// If a player with the same ID already exists, updates their name to
@@ -135,12 +107,15 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
return true; return true;
} }
/// Deletes the player with the given [id] from the database. /* Read */
/// Returns `true` if the player was deleted, `false` if the player did not exist.
Future<bool> deletePlayer({required String playerId}) async { /// Retrieves the total count of players in the database.
final query = delete(playerTable)..where((p) => p.id.equals(playerId)); Future<int> getPlayerCount() async {
final rowsAffected = await query.go(); final count =
return rowsAffected > 0; await (selectOnly(playerTable)..addColumns([playerTable.id.count()]))
.map((row) => row.read(playerTable.id.count()))
.getSingle();
return count ?? 0;
} }
/// Checks if a player with the given [playerId] exists in the database. /// Checks if a player with the given [playerId] exists in the database.
@@ -151,8 +126,40 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
return result != null; return result != null;
} }
/// Retrieves all players from the database.
Future<List<Player>> getAllPlayers() async {
final query = select(playerTable);
final result = await query.get();
return result
.map(
(row) => Player(
id: row.id,
name: row.name,
description: row.description,
createdAt: row.createdAt,
nameCount: row.nameCount,
),
)
.toList();
}
/// Retrieves a [Player] by their [id].
Future<Player> getPlayerById({required String playerId}) async {
final query = select(playerTable)..where((p) => p.id.equals(playerId));
final result = await query.getSingle();
return Player(
id: result.id,
name: result.name,
description: result.description,
createdAt: result.createdAt,
nameCount: result.nameCount,
);
}
/* Update */
/// Updates the name of the player with the given [playerId] to [newName]. /// Updates the name of the player with the given [playerId] to [newName].
Future<void> updatePlayerName({ Future<bool> updatePlayerName({
required String playerId, required String playerId,
required String newName, required String newName,
}) async { }) async {
@@ -164,6 +171,7 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
''; '';
final previousNameCount = await getNameCount(name: previousPlayerName); final previousNameCount = await getNameCount(name: previousPlayerName);
final rowsAffected =
await (update(playerTable)..where((p) => p.id.equals(playerId))).write( await (update(playerTable)..where((p) => p.id.equals(playerId))).write(
PlayerTableCompanion(name: Value(newName)), PlayerTableCompanion(name: Value(newName)),
); );
@@ -188,17 +196,35 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
); );
} }
} }
return rowsAffected > 0;
} }
/// Retrieves the total count of players in the database. /// Updates the description of the player with the given [playerId] to
Future<int> getPlayerCount() async { /// [newDescription].
final count = /// Returns `true` if more than 0 rows were affected, otherwise `false`.
await (selectOnly(playerTable)..addColumns([playerTable.id.count()])) Future<bool> updatePlayerDescription({
.map((row) => row.read(playerTable.id.count())) required String playerId,
.getSingle(); required String newDescription,
return count ?? 0; }) async {
final rowsAffected =
await (update(playerTable)..where((g) => g.id.equals(playerId))).write(
PlayerTableCompanion(description: Value(newDescription)),
);
return rowsAffected > 0;
} }
/* Delete */
/// Deletes the player with the given [id] from the database.
/// Returns `true` if the player was deleted, `false` if the player did not exist.
Future<bool> deletePlayer({required String playerId}) async {
final query = delete(playerTable)..where((p) => p.id.equals(playerId));
final rowsAffected = await query.go();
return rowsAffected > 0;
}
/* Name count management */
/// Retrieves the count of players with the given [name]. /// Retrieves the count of players with the given [name].
Future<int> getNameCount({required String name}) async { Future<int> getNameCount({required String name}) async {
final query = select(playerTable)..where((p) => p.name.equals(name)); final query = select(playerTable)..where((p) => p.name.equals(name));

View File

@@ -24,8 +24,8 @@ void main() {
); );
withClock(fakeClock, () { withClock(fakeClock, () {
testPlayer1 = Player(name: 'Test Player'); testPlayer1 = Player(name: 'Anna', description: 'First test player');
testPlayer2 = Player(name: 'Second Player'); testPlayer2 = Player(name: 'Bob', description: 'Second test player');
testPlayer3 = Player(name: 'Charlie'); testPlayer3 = Player(name: 'Charlie');
testPlayer4 = Player(name: 'Diana'); testPlayer4 = Player(name: 'Diana');
}); });
@@ -35,7 +35,7 @@ void main() {
}); });
group('Player Tests', () { group('Player Tests', () {
// Verifies that players can be added and retrieved with all fields intact. group('CREATE', () {
test('Adding and fetching single player works correctly', () async { test('Adding and fetching single player works correctly', () async {
await database.playerDao.addPlayer(player: testPlayer1); await database.playerDao.addPlayer(player: testPlayer1);
await database.playerDao.addPlayer(player: testPlayer2); await database.playerDao.addPlayer(player: testPlayer2);
@@ -48,15 +48,16 @@ void main() {
); );
expect(fetchedPlayer1.name, testPlayer1.name); expect(fetchedPlayer1.name, testPlayer1.name);
expect(fetchedPlayer1.createdAt, testPlayer1.createdAt); expect(fetchedPlayer1.createdAt, testPlayer1.createdAt);
expect(fetchedPlayer1.description, testPlayer1.description);
final fetchedPlayer2 = allPlayers.firstWhere( final fetchedPlayer2 = allPlayers.firstWhere(
(g) => g.id == testPlayer2.id, (g) => g.id == testPlayer2.id,
); );
expect(fetchedPlayer2.name, testPlayer2.name); expect(fetchedPlayer2.name, testPlayer2.name);
expect(fetchedPlayer2.createdAt, testPlayer2.createdAt); expect(fetchedPlayer2.createdAt, testPlayer2.createdAt);
expect(fetchedPlayer2.description, testPlayer2.description);
}); });
// Verifies that multiple players can be added at once and retrieved correctly.
test('Adding and fetching multiple players works correctly', () async { test('Adding and fetching multiple players works correctly', () async {
await database.playerDao.addPlayersAsList( await database.playerDao.addPlayersAsList(
players: [testPlayer1, testPlayer2, testPlayer3, testPlayer4], players: [testPlayer1, testPlayer2, testPlayer3, testPlayer4],
@@ -79,10 +80,10 @@ void main() {
expect(player.id, testPlayer.id); expect(player.id, testPlayer.id);
expect(player.name, testPlayer.name); expect(player.name, testPlayer.name);
expect(player.createdAt, testPlayer.createdAt); expect(player.createdAt, testPlayer.createdAt);
expect(player.description, testPlayer.description);
} }
}); });
// Verifies that adding the same player twice does not create duplicates.
test('Adding the same player twice does not create duplicates', () async { test('Adding the same player twice does not create duplicates', () async {
await database.playerDao.addPlayer(player: testPlayer1); await database.playerDao.addPlayer(player: testPlayer1);
await database.playerDao.addPlayer(player: testPlayer1); await database.playerDao.addPlayer(player: testPlayer1);
@@ -91,86 +92,95 @@ void main() {
expect(allPlayers.length, 1); expect(allPlayers.length, 1);
}); });
// Verifies that playerExists returns correct boolean based on player presence. test('addPlayer() returns false when player already exists', () async {
test('Player existence check works correctly', () async { var added = await database.playerDao.addPlayer(player: testPlayer1);
expect(added, true);
added = await database.playerDao.addPlayer(player: testPlayer1);
expect(added, false);
});
test('addPlayersAsList() handles empty list correctly', () async {
final added = await database.playerDao.addPlayersAsList(players: []);
expect(added, false);
final allPlayers = await database.playerDao.getAllPlayers();
expect(allPlayers, isEmpty);
});
test(
'addPlayersAsList() with duplicate IDs ignores duplicates',
() async {
await database.playerDao.addPlayersAsList(
players: [testPlayer1, testPlayer1, testPlayer2],
);
final allPlayers = await database.playerDao.getAllPlayers();
expect(allPlayers.length, 2);
},
);
test(
'Player with special characters in name is stored correctly',
() async {
final specialPlayer = Player(
name: 'Test!@#\$%^&*()_+-=[]{}|;\':"😎,.<>?/`~',
);
await database.playerDao.addPlayer(player: specialPlayer);
final fetchedPlayer = await database.playerDao.getPlayerById(
playerId: specialPlayer.id,
);
expect(fetchedPlayer.name, specialPlayer.name);
},
);
});
group('READ', () {
test('getPlayerCount() works correctly', () async {
var playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 0);
await database.playerDao.addPlayer(player: testPlayer1);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 1);
await database.playerDao.addPlayer(player: testPlayer2);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 2);
await database.playerDao.deletePlayer(playerId: testPlayer1.id);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 1);
await database.playerDao.deletePlayer(playerId: testPlayer2.id);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 0);
});
test('playerExists() works correctly', () async {
var playerExists = await database.playerDao.playerExists( var playerExists = await database.playerDao.playerExists(
playerId: testPlayer1.id, playerId: testPlayer1.id,
); );
expect(playerExists, false); expect(playerExists, false);
await database.playerDao.addPlayer(player: testPlayer1); await database.playerDao.addPlayer(player: testPlayer1);
playerExists = await database.playerDao.playerExists( playerExists = await database.playerDao.playerExists(
playerId: testPlayer1.id, playerId: testPlayer1.id,
); );
expect(playerExists, true); expect(playerExists, true);
}); });
// Verifies that deletePlayer removes the player and returns true. test(
test('Deleting a player works correctly', () async { 'getAllPlayers() returns empty list when no players exist',
await database.playerDao.addPlayer(player: testPlayer1); () async {
final playerDeleted = await database.playerDao.deletePlayer(
playerId: testPlayer1.id,
);
expect(playerDeleted, true);
final playerExists = await database.playerDao.playerExists(
playerId: testPlayer1.id,
);
expect(playerExists, false);
});
// Verifies that updatePlayerName correctly updates only the name field.
test('Updating a player name works correctly', () async {
await database.playerDao.addPlayer(player: testPlayer1);
const newPlayerName = 'new player name';
await database.playerDao.updatePlayerName(
playerId: testPlayer1.id,
newName: newPlayerName,
);
final result = await database.playerDao.getPlayerById(
playerId: testPlayer1.id,
);
expect(result.name, newPlayerName);
});
// Verifies that getPlayerCount returns correct count through add/delete operations.
test('Getting the player count works correctly', () async {
var playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 0);
await database.playerDao.addPlayer(player: testPlayer1);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 1);
await database.playerDao.addPlayer(player: testPlayer2);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 2);
await database.playerDao.deletePlayer(playerId: testPlayer1.id);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 1);
await database.playerDao.deletePlayer(playerId: testPlayer2.id);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 0);
});
// Verifies that getAllPlayers returns an empty list when no players exist.
test('getAllPlayers returns empty list when no players exist', () async {
final allPlayers = await database.playerDao.getAllPlayers(); final allPlayers = await database.playerDao.getAllPlayers();
expect(allPlayers, isEmpty); expect(allPlayers, isEmpty);
}); },
);
// Verifies that getPlayerById returns the correct player. test('getPlayerById() returns correct player', () async {
test('getPlayerById returns correct player', () async {
await database.playerDao.addPlayer(player: testPlayer1); await database.playerDao.addPlayer(player: testPlayer1);
await database.playerDao.addPlayer(player: testPlayer2); await database.playerDao.addPlayer(player: testPlayer2);
@@ -184,134 +194,76 @@ void main() {
expect(fetchedPlayer.description, testPlayer1.description); expect(fetchedPlayer.description, testPlayer1.description);
}); });
// Verifies that getPlayerById throws StateError for non-existent player ID. test(
test('getPlayerById throws exception for non-existent player', () async { 'getPlayerById() throws exception for non-existent player',
() async {
expect( expect(
() => database.playerDao.getPlayerById(playerId: 'non-existent-id'), () => database.playerDao.getPlayerById(playerId: 'non-existent-id'),
throwsA(isA<StateError>()), throwsA(isA<StateError>()),
); );
}); },
// Verifies that addPlayer returns false when trying to add a duplicate player.
test('addPlayer returns false when player already exists', () async {
final firstAdd = await database.playerDao.addPlayer(player: testPlayer1);
expect(firstAdd, true);
final secondAdd = await database.playerDao.addPlayer(player: testPlayer1);
expect(secondAdd, false);
});
// Verifies that addPlayersAsList handles empty list correctly.
test('addPlayersAsList handles empty list correctly', () async {
final result = await database.playerDao.addPlayersAsList(players: []);
expect(result, false);
final allPlayers = await database.playerDao.getAllPlayers();
expect(allPlayers, isEmpty);
});
// Verifies that addPlayersAsList ignores duplicate player IDs.
test('addPlayersAsList with duplicate IDs ignores duplicates', () async {
await database.playerDao.addPlayersAsList(
players: [testPlayer1, testPlayer1, testPlayer2],
); );
final allPlayers = await database.playerDao.getAllPlayers();
expect(allPlayers.length, 2);
}); });
// Verifies that deletePlayer returns false for non-existent player. group('UPDATE', () {
test('deletePlayer returns false for non-existent player', () async { test('updatePlayerName() works correctly', () async {
final result = await database.playerDao.deletePlayer( await database.playerDao.addPlayer(player: testPlayer1);
playerId: 'non-existent-id',
); const newName = 'New name';
expect(result, false);
});
// Verifies that updatePlayerName does nothing for non-existent player (no exception).
test('updatePlayerName does nothing for non-existent player', () async {
// Should not throw, just do nothing
await database.playerDao.updatePlayerName( await database.playerDao.updatePlayerName(
playerId: 'non-existent-id', playerId: testPlayer1.id,
newName: 'New Name', newName: newName,
); );
final player = await database.playerDao.getPlayerById(
playerId: testPlayer1.id,
);
expect(player.name, newName);
});
test('updatePlayerName() does nothing for non-existent player', () async {
final updated = await database.playerDao.updatePlayerName(
playerId: 'non-existent-id',
newName: 'New name',
);
expect(updated, false);
final allPlayers = await database.playerDao.getAllPlayers(); final allPlayers = await database.playerDao.getAllPlayers();
expect(allPlayers, isEmpty); expect(allPlayers, isEmpty);
}); });
// Verifies that deleteAllPlayers removes all players. test('updatePlayerDescription() works correctly', () async {
test('deleteAllPlayers removes all players', () async { await database.playerDao.addPlayer(player: testPlayer1);
await database.playerDao.addPlayersAsList(
players: [testPlayer1, testPlayer2, testPlayer3], const newDescription = 'New description';
final updated = await database.playerDao.updatePlayerDescription(
playerId: testPlayer1.id,
newDescription: newDescription,
); );
expect(updated, true);
var playerCount = await database.playerDao.getPlayerCount(); final player = await database.playerDao.getPlayerById(
expect(playerCount, 3); playerId: testPlayer1.id,
);
final result = await database.playerDao.deleteAllPlayers(); expect(player.description, newDescription);
expect(result, true);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 0);
}); });
// Verifies that deleteAllPlayers returns false when no players exist.
test('deleteAllPlayers returns false when no players exist', () async {
final result = await database.playerDao.deleteAllPlayers();
expect(result, false);
});
// Verifies that a player with special characters in name is stored correctly.
test( test(
'Player with special characters in name is stored correctly', 'updatePlayerDescription() does nothing for non-existent player',
() async { () async {
final specialPlayer = Player( final updated = await database.playerDao.updatePlayerDescription(
name: 'Test!@#\$%^&*()_+-=[]{}|;\':",.<>?/`~', playerId: 'non-existent-id',
description: '', newDescription: 'New description',
); );
expect(updated, false);
await database.playerDao.addPlayer(player: specialPlayer); final allPlayers = await database.playerDao.getAllPlayers();
expect(allPlayers, isEmpty);
final fetchedPlayer = await database.playerDao.getPlayerById(
playerId: specialPlayer.id,
);
expect(fetchedPlayer.name, specialPlayer.name);
}, },
); );
// Verifies that a player with description is stored correctly.
test('Player with description is stored correctly', () async {
final playerWithDescription = Player(
name: 'Described Player',
description: 'This is a test description',
);
await database.playerDao.addPlayer(player: playerWithDescription);
final fetchedPlayer = await database.playerDao.getPlayerById(
playerId: playerWithDescription.id,
);
expect(fetchedPlayer.name, playerWithDescription.name);
expect(fetchedPlayer.description, playerWithDescription.description);
});
// Verifies that a player with null description is stored correctly.
test('Player with null description is stored correctly', () async {
final playerWithoutDescription = Player(
name: 'No Description Player',
description: '',
);
await database.playerDao.addPlayer(player: playerWithoutDescription);
final fetchedPlayer = await database.playerDao.getPlayerById(
playerId: playerWithoutDescription.id,
);
expect(fetchedPlayer.description, '');
});
// Verifies that multiple updates to the same player work correctly.
test('Multiple updates to the same player work correctly', () async { test('Multiple updates to the same player work correctly', () async {
await database.playerDao.addPlayer(player: testPlayer1); await database.playerDao.addPlayer(player: testPlayer1);
@@ -335,54 +287,61 @@ void main() {
); );
expect(fetchedPlayer.name, 'Second Update'); expect(fetchedPlayer.name, 'Second Update');
await database.playerDao.updatePlayerName( await database.playerDao.updatePlayerDescription(
playerId: testPlayer1.id, playerId: testPlayer1.id,
newName: 'Third Update', newDescription: 'Third Update',
); );
fetchedPlayer = await database.playerDao.getPlayerById( fetchedPlayer = await database.playerDao.getPlayerById(
playerId: testPlayer1.id, playerId: testPlayer1.id,
); );
expect(fetchedPlayer.name, 'Third Update'); expect(fetchedPlayer.description, 'Third Update');
});
}); });
// Verifies that a player with empty string name is stored correctly. group('DELETE', () {
test('Player with empty string name is stored correctly', () async { test('deletePlayer() works correctly', () async {
final emptyNamePlayer = Player(name: ''); await database.playerDao.addPlayer(player: testPlayer1);
final playerDeleted = await database.playerDao.deletePlayer(
await database.playerDao.addPlayer(player: emptyNamePlayer); playerId: testPlayer1.id,
final fetchedPlayer = await database.playerDao.getPlayerById(
playerId: emptyNamePlayer.id,
); );
expect(fetchedPlayer.name, ''); expect(playerDeleted, true);
});
// Verifies that a player with very long name is stored correctly.
test('Player with very long name is stored correctly', () async {
final longName = 'A' * 1000;
final longNamePlayer = Player(name: longName);
await database.playerDao.addPlayer(player: longNamePlayer);
final fetchedPlayer = await database.playerDao.getPlayerById(
playerId: longNamePlayer.id,
);
expect(fetchedPlayer.name, longName);
});
// Verifies that addPlayer returns true on first add.
test('addPlayer returns true when player is added successfully', () async {
final result = await database.playerDao.addPlayer(player: testPlayer1);
expect(result, true);
final playerExists = await database.playerDao.playerExists( final playerExists = await database.playerDao.playerExists(
playerId: testPlayer1.id, playerId: testPlayer1.id,
); );
expect(playerExists, true); expect(playerExists, false);
}); });
group('Name Count Tests', () { test('deletePlayer() returns false for non-existent player', () async {
final deleted = await database.playerDao.deletePlayer(
playerId: 'non-existent-id',
);
expect(deleted, false);
});
test('deleteAllPlayers() removes all players', () async {
await database.playerDao.addPlayersAsList(
players: [testPlayer1, testPlayer2, testPlayer3],
);
var playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 3);
final deleted = await database.playerDao.deleteAllPlayers();
expect(deleted, true);
playerCount = await database.playerDao.getPlayerCount();
expect(playerCount, 0);
});
test('deleteAllPlayers() returns false when no players exist', () async {
final deleted = await database.playerDao.deleteAllPlayers();
expect(deleted, false);
});
});
group('NAME COUNT', () {
test('Single player gets initialized wih name count 0', () async { test('Single player gets initialized wih name count 0', () async {
await database.playerDao.addPlayer(player: testPlayer1); await database.playerDao.addPlayer(player: testPlayer1);