diff --git a/.github/workflows/api_game_domain.yaml b/.github/workflows/api_game_domain.yaml new file mode 100644 index 000000000..c40c54918 --- /dev/null +++ b/.github/workflows/api_game_domain.yaml @@ -0,0 +1,20 @@ +name: api_game_domain + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + pull_request: + paths: + - "api/packages/game_domain/**" + - ".github/workflows/api_game_domain.yaml" + branches: + - main + +jobs: + build: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 + with: + dart_sdk: stable + working_directory: api/packages/game_domain diff --git a/api/packages/game_domain/.gitignore b/api/packages/game_domain/.gitignore new file mode 100644 index 000000000..526da1584 --- /dev/null +++ b/api/packages/game_domain/.gitignore @@ -0,0 +1,7 @@ +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +pubspec.lock \ No newline at end of file diff --git a/api/packages/game_domain/analysis_options.yaml b/api/packages/game_domain/analysis_options.yaml new file mode 100644 index 000000000..799268d3e --- /dev/null +++ b/api/packages/game_domain/analysis_options.yaml @@ -0,0 +1 @@ +include: package:very_good_analysis/analysis_options.5.1.0.yaml diff --git a/api/packages/game_domain/lib/game_domain.dart b/api/packages/game_domain/lib/game_domain.dart new file mode 100644 index 000000000..8cd70b4a8 --- /dev/null +++ b/api/packages/game_domain/lib/game_domain.dart @@ -0,0 +1,4 @@ +/// Domain classes for the game. +library game_domain; + +export 'src/models/models.dart'; diff --git a/api/packages/game_domain/lib/src/models/leaderboard_player.dart b/api/packages/game_domain/lib/src/models/leaderboard_player.dart new file mode 100644 index 000000000..275485159 --- /dev/null +++ b/api/packages/game_domain/lib/src/models/leaderboard_player.dart @@ -0,0 +1,35 @@ +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'leaderboard_player.g.dart'; + +/// {@template leaderboard_player} +/// A model that represents a player in the leaderboard. +/// {@endtemplate} +@JsonSerializable(ignoreUnannotated: true) +class LeaderboardPlayer extends Equatable { + /// {@macro leaderboard_player} + const LeaderboardPlayer({ + required this.id, + required this.initials, + }); + + /// {@macro leaderboard_player} + factory LeaderboardPlayer.fromJson(Map json) => + _$LeaderboardPlayerFromJson(json); + + /// Unique identifier of the leaderboard player object + /// and session id for the player. + @JsonKey() + final String id; + + /// Initials of the player. + @JsonKey() + final String initials; + + /// Returns a json representation from this instance. + Map toJson() => _$LeaderboardPlayerToJson(this); + + @override + List get props => [id, initials]; +} diff --git a/api/packages/game_domain/lib/src/models/leaderboard_player.g.dart b/api/packages/game_domain/lib/src/models/leaderboard_player.g.dart new file mode 100644 index 000000000..a9a747a2c --- /dev/null +++ b/api/packages/game_domain/lib/src/models/leaderboard_player.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'leaderboard_player.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LeaderboardPlayer _$LeaderboardPlayerFromJson(Map json) => + LeaderboardPlayer( + id: json['id'] as String, + initials: json['initials'] as String, + ); + +Map _$LeaderboardPlayerToJson(LeaderboardPlayer instance) => + { + 'id': instance.id, + 'initials': instance.initials, + }; diff --git a/api/packages/game_domain/lib/src/models/models.dart b/api/packages/game_domain/lib/src/models/models.dart new file mode 100644 index 000000000..4c1c38f2b --- /dev/null +++ b/api/packages/game_domain/lib/src/models/models.dart @@ -0,0 +1 @@ +export 'leaderboard_player.dart'; diff --git a/api/packages/game_domain/pubspec.yaml b/api/packages/game_domain/pubspec.yaml new file mode 100644 index 000000000..78f90dce0 --- /dev/null +++ b/api/packages/game_domain/pubspec.yaml @@ -0,0 +1,17 @@ +name: game_domain +description: Domain classes for the game. +version: 0.1.0+1 +publish_to: none + +environment: + sdk: ">=3.0.0 <4.0.0" + +dev_dependencies: + build_runner: ^2.4.8 + mocktail: ^1.0.0 + test: ^1.19.2 + very_good_analysis: ^5.1.0 + +dependencies: + equatable: ^2.0.5 + json_annotation: ^4.8.1 \ No newline at end of file diff --git a/api/packages/game_domain/test/src/models/leaderboard_player_test.dart b/api/packages/game_domain/test/src/models/leaderboard_player_test.dart new file mode 100644 index 000000000..d091ea55d --- /dev/null +++ b/api/packages/game_domain/test/src/models/leaderboard_player_test.dart @@ -0,0 +1,70 @@ +// ignore_for_file: prefer_const_constructors + +import 'package:game_domain/game_domain.dart'; +import 'package:test/test.dart'; + +void main() { + group('LeaderboardPlayer', () { + test('can be instantiated', () { + expect( + LeaderboardPlayer( + id: 'id', + initials: 'TST', + ), + isNotNull, + ); + }); + + final leaderboardPlayer = LeaderboardPlayer( + id: 'id', + initials: 'TST', + ); + + test('toJson returns the instance as json', () { + expect( + leaderboardPlayer.toJson(), + equals({ + 'id': 'id', + 'initials': 'TST', + }), + ); + }); + + test('fromJson returns the correct instance', () { + expect( + LeaderboardPlayer.fromJson(const { + 'id': 'id', + 'initials': 'TST', + }), + equals(leaderboardPlayer), + ); + }); + + test('supports equality', () { + expect( + LeaderboardPlayer(id: '', initials: 'TST'), + equals(LeaderboardPlayer(id: '', initials: 'TST')), + ); + + expect( + LeaderboardPlayer( + id: '', + initials: 'TST', + ), + isNot( + equals(leaderboardPlayer), + ), + ); + + expect( + LeaderboardPlayer( + id: 'id', + initials: 'WOW', + ), + isNot( + equals(leaderboardPlayer), + ), + ); + }); + }); +}