12 Commits

Author SHA1 Message Date
gelbeinhalb
e4ea46c6cd Merge remote-tracking branch 'origin/development' into feature/88-neue-datenbank-struktur
All checks were successful
Pull Request Pipeline / lint (pull_request) Successful in 40s
Pull Request Pipeline / test (pull_request) Successful in 36s
2026-02-07 20:11:51 +01:00
gelbeinhalb
e881cf0555 fix expected null when empty string is correct
All checks were successful
Pull Request Pipeline / lint (pull_request) Successful in 40s
Pull Request Pipeline / test (pull_request) Successful in 35s
2026-02-07 18:17:08 +01:00
gelbeinhalb
278544788e fix formatting
Some checks failed
Pull Request Pipeline / lint (pull_request) Successful in 1m25s
Pull Request Pipeline / test (pull_request) Failing after 36s
2026-02-07 17:40:27 +01:00
gelbeinhalb
a12f4eb1c1 implement winner methods
Some checks failed
Pull Request Pipeline / test (pull_request) Failing after 28s
Pull Request Pipeline / lint (pull_request) Failing after 40s
2026-02-07 17:35:43 +01:00
gelbeinhalb
0eb8e2683c add replace players in a match test 2026-02-07 17:31:23 +01:00
gelbeinhalb
07b9b78252 add replace players in a match method 2026-02-07 17:31:19 +01:00
gelbeinhalb
fa9ad9dbae add test for replacing group players 2026-02-07 17:26:07 +01:00
gelbeinhalb
25699dffc0 add replaceGroupPlayers method 2026-02-07 17:25:49 +01:00
a4d4703069 Updated licenses [skip ci] 2026-02-06 12:32:19 +00:00
fabb7bae19 Updated version number [skip ci] 2026-02-06 12:31:47 +00:00
gelbeinhalb
70d6178829 restructure tests 2026-02-01 19:51:57 +01:00
d1458443eb Added ref again
Some checks failed
Push Pipeline / update_version (push) Successful in 6s
Push Pipeline / build (push) Failing after 31s
Push Pipeline / generate_licenses (push) Successful in 30s
Push Pipeline / test (push) Successful in 38s
Push Pipeline / format (push) Successful in 41s
2026-01-26 14:47:26 +01:00
13 changed files with 241 additions and 72 deletions

View File

@@ -85,7 +85,6 @@ jobs:
strategy: 'patch' strategy: 'patch'
path: './pubspec.yaml' path: './pubspec.yaml'
- name: Commit version update - name: Commit version update
env: env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }} GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
@@ -107,6 +106,7 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
token: ${{ secrets.BOT_TOKEN }} token: ${{ secrets.BOT_TOKEN }}
ref: ${{ gitea.ref_name }}
# Required for Flutter action # Required for Flutter action
- name: Install jq - name: Install jq

View File

@@ -231,4 +231,44 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
final rowsAffected = await query.go(); final rowsAffected = await query.go();
return rowsAffected > 0; return rowsAffected > 0;
} }
/// Replaces all players in a group with the provided list of players.
/// Removes all existing players from the group and adds the new players.
/// Also adds any new players to the player table if they don't exist.
Future<void> replaceGroupPlayers({
required String groupId,
required List<Player> newPlayers,
}) async {
await db.transaction(() async {
// Remove all existing players from the group
final deleteQuery = delete(db.playerGroupTable)
..where((p) => p.groupId.equals(groupId));
await deleteQuery.go();
// Add new players to the player table if they don't exist
await Future.wait(
newPlayers.map((player) async {
if (!await db.playerDao.playerExists(playerId: player.id)) {
await db.playerDao.addPlayer(player: player);
}
}),
);
// Add the new players to the group
await db.batch(
(b) => b.insertAll(
db.playerGroupTable,
newPlayers
.map(
(player) => PlayerGroupTableCompanion.insert(
playerId: player.id,
groupId: groupId,
),
)
.toList(),
mode: InsertMode.insertOrReplace,
),
);
});
}
} }

View File

@@ -355,39 +355,119 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
return rowsAffected > 0; return rowsAffected > 0;
} }
/// Replaces all players in a match with the provided list of players.
/// Removes all existing players from the match and adds the new players.
/// Also adds any new players to the player table if they don't exist.
Future<void> replaceMatchPlayers({
required String matchId,
required List<Player> newPlayers,
}) async {
await db.transaction(() async {
// Remove all existing players from the match
final deleteQuery = delete(db.playerMatchTable)
..where((p) => p.matchId.equals(matchId));
await deleteQuery.go();
// Add new players to the player table if they don't exist
await Future.wait(
newPlayers.map((player) async {
if (!await db.playerDao.playerExists(playerId: player.id)) {
await db.playerDao.addPlayer(player: player);
}
}),
);
// Add the new players to the match
await Future.wait(
newPlayers.map((player) => db.playerMatchDao.addPlayerToMatch(
matchId: matchId,
playerId: player.id,
)),
);
});
}
// ============================================================ // ============================================================
// TEMPORARY: Winner methods - these are stubs and do not persist data // Winner methods - handle winner logic via player scores
// TODO: Implement proper winner handling
// ============================================================ // ============================================================
/// TEMPORARY: Checks if a match has a winner. /// Checks if a match has a winner.
/// Currently returns true if the match has any players. /// Returns true if any player in the match has their score set to 1.
Future<bool> hasWinner({required String matchId}) async { Future<bool> hasWinner({required String matchId}) async {
final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? []; final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? [];
return players.isNotEmpty;
for (final player in players) {
final score = await db.playerMatchDao.getPlayerScore(
matchId: matchId,
playerId: player.id,
);
if (score == 1) {
return true;
}
}
return false;
} }
/// TEMPORARY: Gets the winner of a match. /// Gets the winner of a match.
/// Currently returns the first player in the match's player list. /// Returns the player with score 1, or null if no winner is set.
Future<Player?> getWinner({required String matchId}) async { Future<Player?> getWinner({required String matchId}) async {
final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? []; final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? [];
return players.isNotEmpty ? players.first : null;
for (final player in players) {
final score = await db.playerMatchDao.getPlayerScore(
matchId: matchId,
playerId: player.id,
);
if (score == 1) {
return player;
}
}
return null;
} }
/// TEMPORARY: Sets the winner of a match. /// Sets the winner of a match.
/// Currently does nothing - winner is not persisted. /// Sets all players' scores to 0, then sets the specified player's score to 1.
/// Returns `true` if the operation was successful, otherwise `false`.
Future<bool> setWinner({ Future<bool> setWinner({
required String matchId, required String matchId,
required String winnerId, required String winnerId,
}) async { }) async {
// TODO: Implement winner persistence await db.transaction(() async {
final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? [];
// Set all players' scores to 0
for (final player in players) {
await db.playerMatchDao.updatePlayerScore(
matchId: matchId,
playerId: player.id,
newScore: 0,
);
}
// Set the winner's score to 1
await db.playerMatchDao.updatePlayerScore(
matchId: matchId,
playerId: winnerId,
newScore: 1,
);
});
return true; return true;
} }
/// TEMPORARY: Removes the winner of a match. /// Removes the winner of a match.
/// Currently does nothing - winner is not persisted. /// Sets the current winner's score to 0 (no winner).
/// Returns `true` if a winner was removed, otherwise `false`.
Future<bool> removeWinner({required String matchId}) async { Future<bool> removeWinner({required String matchId}) async {
// TODO: Implement winner persistence final winner = await getWinner(matchId: matchId);
return true; if (winner == null) {
return false;
}
final success = await db.playerMatchDao.updatePlayerScore(
matchId: matchId,
playerId: winner.id,
newScore: 0,
);
return success;
} }
} }

View File

@@ -1396,13 +1396,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
); );
/// cross_file 0.3.5+1 /// cross_file 0.3.5+2
const _cross_file = Package( const _cross_file = Package(
name: 'cross_file', name: 'cross_file',
description: 'An abstraction to allow working with files across multiple platforms.', description: 'An abstraction to allow working with files across multiple platforms.',
repository: 'https://github.com/flutter/packages/tree/main/packages/cross_file', repository: 'https://github.com/flutter/packages/tree/main/packages/cross_file',
authors: [], authors: [],
version: '0.3.5+1', version: '0.3.5+2',
spdxIdentifiers: ['BSD-3-Clause'], spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false, isMarkdown: false,
isSdk: false, isSdk: false,
@@ -1628,13 +1628,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
); );
/// dbus 0.7.11 /// dbus 0.7.12
const _dbus = Package( const _dbus = Package(
name: 'dbus', name: 'dbus',
description: 'A native Dart implementation of the D-Bus message bus client. This package allows Dart applications to directly access services on the Linux desktop.', description: 'A native Dart implementation of the D-Bus message bus client. This package allows Dart applications to directly access services on the Linux desktop.',
homepage: 'https://github.com/canonical/dbus.dart', homepage: 'https://github.com/canonical/dbus.dart',
authors: [], authors: [],
version: '0.7.11', version: '0.7.12',
spdxIdentifiers: ['MPL-2.0'], spdxIdentifiers: ['MPL-2.0'],
isMarkdown: false, isMarkdown: false,
isSdk: false, isSdk: false,
@@ -2015,7 +2015,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice
defined by the Mozilla Public License, v. 2.0.''', defined by the Mozilla Public License, v. 2.0.''',
); );
/// dio 5.9.0 /// dio 5.9.1
const _dio = Package( const _dio = Package(
name: 'dio', name: 'dio',
description: '''A powerful HTTP networking package, description: '''A powerful HTTP networking package,
@@ -2026,7 +2026,7 @@ Custom adapters, Transformers, etc.
homepage: 'https://github.com/cfug/dio', homepage: 'https://github.com/cfug/dio',
repository: 'https://github.com/cfug/dio/blob/main/dio', repository: 'https://github.com/cfug/dio/blob/main/dio',
authors: [], authors: [],
version: '5.9.0', version: '5.9.1',
spdxIdentifiers: ['MIT'], spdxIdentifiers: ['MIT'],
isMarkdown: false, isMarkdown: false,
isSdk: false, isSdk: false,
@@ -2497,14 +2497,14 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
); );
/// file_picker 10.3.8 /// file_picker 10.3.10
const _file_picker = Package( const _file_picker = Package(
name: 'file_picker', name: 'file_picker',
description: 'A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.', description: 'A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.',
homepage: 'https://github.com/miguelpruivo/plugins_flutter_file_picker', homepage: 'https://github.com/miguelpruivo/plugins_flutter_file_picker',
repository: 'https://github.com/miguelpruivo/flutter_file_picker', repository: 'https://github.com/miguelpruivo/flutter_file_picker',
authors: [], authors: [],
version: '10.3.8', version: '10.3.10',
spdxIdentifiers: ['MIT'], spdxIdentifiers: ['MIT'],
isMarkdown: false, isMarkdown: false,
isSdk: false, isSdk: false,
@@ -2947,13 +2947,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
); );
/// hooks 1.0.0 /// hooks 1.0.1
const _hooks = Package( const _hooks = Package(
name: 'hooks', name: 'hooks',
description: 'A library that contains a Dart API for the JSON-based protocol for `hook/build.dart` and `hook/link.dart`.', description: 'A library that contains a Dart API for the JSON-based protocol for `hook/build.dart` and `hook/link.dart`.',
repository: 'https://github.com/dart-lang/native/tree/main/pkgs/hooks', repository: 'https://github.com/dart-lang/native/tree/main/pkgs/hooks',
authors: [], authors: [],
version: '1.0.0', version: '1.0.1',
spdxIdentifiers: ['BSD-3-Clause'], spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false, isMarkdown: false,
isSdk: false, isSdk: false,
@@ -3271,13 +3271,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
); );
/// json_annotation 4.9.0 /// json_annotation 4.10.0
const _json_annotation = Package( const _json_annotation = Package(
name: 'json_annotation', name: 'json_annotation',
description: 'Classes and helper functions that support JSON code generation via the `json_serializable` package.', description: 'Classes and helper functions that support JSON code generation via the `json_serializable` package.',
repository: 'https://github.com/google/json_serializable.dart/tree/master/json_annotation', repository: 'https://github.com/google/json_serializable.dart/tree/master/json_annotation',
authors: [], authors: [],
version: '4.9.0', version: '4.10.0',
spdxIdentifiers: ['BSD-3-Clause'], spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false, isMarkdown: false,
isSdk: false, isSdk: false,
@@ -4085,13 +4085,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
); );
/// objective_c 9.2.4 /// objective_c 9.3.0
const _objective_c = Package( const _objective_c = Package(
name: 'objective_c', name: 'objective_c',
description: 'A library to access Objective C from Flutter that acts as a support library for package:ffigen.', description: 'A library to access Objective C from Flutter that acts as a support library for package:ffigen.',
repository: 'https://github.com/dart-lang/native/tree/main/pkgs/objective_c', repository: 'https://github.com/dart-lang/native/tree/main/pkgs/objective_c',
authors: [], authors: [],
version: '9.2.4', version: '9.3.0',
spdxIdentifiers: ['BSD-3-Clause'], spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false, isMarkdown: false,
isSdk: false, isSdk: false,
@@ -5869,13 +5869,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
); );
/// source_span 1.10.1 /// source_span 1.10.2
const _source_span = Package( const _source_span = Package(
name: 'source_span', name: 'source_span',
description: 'Provides a standard representation for source code locations and spans.', description: 'Provides a standard representation for source code locations and spans.',
repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_span', repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_span',
authors: [], authors: [],
version: '1.10.1', version: '1.10.2',
spdxIdentifiers: ['BSD-3-Clause'], spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false, isMarkdown: false,
isSdk: false, isSdk: false,
@@ -7499,12 +7499,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.''', SOFTWARE.''',
); );
/// tallee 0.0.13+247 /// tallee 0.0.15+249
const _tallee = Package( const _tallee = Package(
name: 'tallee', name: 'tallee',
description: 'Tracking App for Card Games', description: 'Tracking App for Card Games',
authors: [], authors: [],
version: '0.0.13+247', version: '0.0.15+249',
spdxIdentifiers: ['LGPL-3.0'], spdxIdentifiers: ['LGPL-3.0'],
isMarkdown: false, isMarkdown: false,
isSdk: false, isSdk: false,

View File

@@ -1,7 +1,7 @@
name: tallee name: tallee
description: "Tracking App for Card Games" description: "Tracking App for Card Games"
publish_to: 'none' publish_to: 'none'
version: 0.0.14+248 version: 0.0.15+249
environment: environment:
sdk: ^3.8.1 sdk: ^3.8.1

View File

@@ -122,19 +122,15 @@ void main() {
} else { } else {
fail('Group is null'); fail('Group is null');
} }
if (result.players != null) { expect(result.players.length, testMatch1.players.length);
expect(result.players!.length, testMatch1.players!.length);
for (int i = 0; i < testMatch1.players!.length; i++) { for (int i = 0; i < testMatch1.players.length; i++) {
expect(result.players![i].id, testMatch1.players![i].id); expect(result.players[i].id, testMatch1.players[i].id);
expect(result.players![i].name, testMatch1.players![i].name); expect(result.players[i].name, testMatch1.players[i].name);
expect( expect(
result.players![i].createdAt, result.players[i].createdAt,
testMatch1.players![i].createdAt, testMatch1.players[i].createdAt,
); );
}
} else {
fail('Players is null');
} }
}); });
@@ -191,18 +187,14 @@ void main() {
} }
// Players-Checks // Players-Checks
if (testMatch.players != null) { expect(match.players.length, testMatch.players.length);
expect(match.players!.length, testMatch.players!.length); for (int i = 0; i < testMatch.players.length; i++) {
for (int i = 0; i < testMatch.players!.length; i++) { expect(match.players[i].id, testMatch.players[i].id);
expect(match.players![i].id, testMatch.players![i].id); expect(match.players[i].name, testMatch.players[i].name);
expect(match.players![i].name, testMatch.players![i].name); expect(
expect( match.players[i].createdAt,
match.players![i].createdAt, testMatch.players[i].createdAt,
testMatch.players![i].createdAt, );
);
}
} else {
expect(match.players, null);
} }
} }
}); });

View File

@@ -132,7 +132,7 @@ void main() {
expect(allGames.length, 1); expect(allGames.length, 1);
}); });
// Verifies that a game with null 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, icon: '');
final result = await database.gameDao.addGame(game: gameWithNulls); final result = await database.gameDao.addGame(game: gameWithNulls);
@@ -144,7 +144,7 @@ void main() {
expect(fetchedGame.name, 'Simple Game'); expect(fetchedGame.name, 'Simple Game');
expect(fetchedGame.description, 'A simple game'); expect(fetchedGame.description, 'A simple game');
expect(fetchedGame.color, GameColor.green); expect(fetchedGame.color, GameColor.green);
expect(fetchedGame.icon, isNull); expect(fetchedGame.icon, '');
}); });
// Verifies that multiple games can be added at once using addGamesAsList. // Verifies that multiple games can be added at once using addGamesAsList.

View File

@@ -308,5 +308,35 @@ void main() {
); );
expect(secondRemoval, false); expect(secondRemoval, false);
}); });
// Verifies that replaceGroupPlayers removes all existing players and replaces with new list.
test('replaceGroupPlayers replaces all group members correctly', () async {
// Create initial group with 3 players
await database.groupDao.addGroup(group: testGroup);
// Verify initial members
var groupMembers = await database.groupDao.getGroupById(
groupId: testGroup.id,
);
expect(groupMembers.members.length, 3);
// Replace with new list containing 2 different players
final newPlayersList = [testPlayer3, testPlayer4];
await database.groupDao.replaceGroupPlayers(
groupId: testGroup.id,
newPlayers: newPlayersList,
);
// Get updated group and verify members
groupMembers = await database.groupDao.getGroupById(
groupId: testGroup.id,
);
expect(groupMembers.members.length, 2);
expect(groupMembers.members.any((p) => p.id == testPlayer3.id), true);
expect(groupMembers.members.any((p) => p.id == testPlayer4.id), true);
expect(groupMembers.members.any((p) => p.id == testPlayer1.id), false);
expect(groupMembers.members.any((p) => p.id == testPlayer2.id), false);
});
}); });
} }

View File

@@ -140,7 +140,7 @@ void main() {
test('Removing player from match works correctly', () async { test('Removing player from match works correctly', () async {
await database.matchDao.addMatch(match: testMatchOnlyPlayers); await database.matchDao.addMatch(match: testMatchOnlyPlayers);
final playerToRemove = testMatchOnlyPlayers.players![0]; final playerToRemove = testMatchOnlyPlayers.players[0];
final removed = await database.playerMatchDao.removePlayerFromMatch( final removed = await database.playerMatchDao.removePlayerFromMatch(
playerId: playerToRemove.id, playerId: playerToRemove.id,
@@ -151,9 +151,9 @@ void main() {
final result = await database.matchDao.getMatchById( final result = await database.matchDao.getMatchById(
matchId: testMatchOnlyPlayers.id, matchId: testMatchOnlyPlayers.id,
); );
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);
@@ -164,18 +164,14 @@ void main() {
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,
); ) ?? [];
if (players == null) {
fail('Players should not be null');
}
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, players[i].createdAt,
testMatchOnlyPlayers.players![i].createdAt, testMatchOnlyPlayers.players[i].createdAt,
); );
} }
}); });
@@ -884,5 +880,36 @@ void main() {
expect(playersInTeam.length, 1); expect(playersInTeam.length, 1);
expect(playersInTeam[0].id, testPlayer2.id); expect(playersInTeam[0].id, testPlayer2.id);
}); });
// Verifies that replaceMatchPlayers removes all existing players and replaces with new list.
test('replaceMatchPlayers replaces all match players correctly', () async {
// Create initial match with 3 players
await database.matchDao.addMatch(match: testMatchOnlyPlayers);
// Verify initial players
var matchPlayers = await database.matchDao.getMatchById(
matchId: testMatchOnlyPlayers.id,
);
expect(matchPlayers.players.length, 3);
// Replace with new list containing 2 different players
final newPlayersList = [testPlayer1, testPlayer2];
await database.matchDao.replaceMatchPlayers(
matchId: testMatchOnlyPlayers.id,
newPlayers: newPlayersList,
);
// Get updated match and verify players
matchPlayers = await database.matchDao.getMatchById(
matchId: testMatchOnlyPlayers.id,
);
expect(matchPlayers.players.length, 2);
expect(matchPlayers.players.any((p) => p.id == testPlayer1.id), true);
expect(matchPlayers.players.any((p) => p.id == testPlayer2.id), true);
expect(matchPlayers.players.any((p) => p.id == testPlayer4.id), false);
expect(matchPlayers.players.any((p) => p.id == testPlayer5.id), false);
expect(matchPlayers.players.any((p) => p.id == testPlayer6.id), false);
});
}); });
} }