523 lines
17 KiB
Dart
523 lines
17 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:lanebow/models/member_model.dart';
|
|
import 'package:lanebow/models/score_model.dart';
|
|
import 'package:lanebow/models/tie_breaker_option.dart';
|
|
import 'package:lanebow/utils/tie_breaker_util.dart';
|
|
|
|
void main() {
|
|
group('TieBreakerUtil 테스트', () {
|
|
// 테스트용 점수 데이터 생성
|
|
List<Score> createTestScores() {
|
|
return [
|
|
// 1위: 100점
|
|
Score(
|
|
id: '1',
|
|
memberId: '1',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10],
|
|
totalScore: 100,
|
|
handicap: 0,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 1',
|
|
),
|
|
// 공동 2위: 90점, 핸디캡 10
|
|
Score(
|
|
id: '2',
|
|
memberId: '2',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9],
|
|
totalScore: 90,
|
|
handicap: 10, // 핸디캡 포함 시 100점
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 2',
|
|
),
|
|
// 공동 2위: 90점, 핸디캡 0
|
|
Score(
|
|
id: '3',
|
|
memberId: '3',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9],
|
|
totalScore: 90,
|
|
handicap: 0,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 3',
|
|
),
|
|
// 4위: 80점, 핸디캡 20
|
|
Score(
|
|
id: '4',
|
|
memberId: '4',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
|
|
totalScore: 80,
|
|
handicap: 20, // 핸디캡 포함 시 100점
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 4',
|
|
),
|
|
];
|
|
}
|
|
|
|
// 테스트용 회원 데이터 생성
|
|
List<Member> createTestMembers() {
|
|
return [
|
|
Member(
|
|
id: '1',
|
|
userId: 'user1',
|
|
clubId: '1',
|
|
name: '참가자 1',
|
|
email: 'user1@example.com',
|
|
isActive: true,
|
|
birthDate: DateTime(1990, 1, 1), // 1990년생
|
|
),
|
|
Member(
|
|
id: '2',
|
|
userId: 'user2',
|
|
clubId: '1',
|
|
name: '참가자 2',
|
|
email: 'user2@example.com',
|
|
isActive: true,
|
|
birthDate: DateTime(1985, 1, 1), // 1985년생 (더 연장자)
|
|
),
|
|
Member(
|
|
id: '3',
|
|
userId: 'user3',
|
|
clubId: '1',
|
|
name: '참가자 3',
|
|
email: 'user3@example.com',
|
|
isActive: true,
|
|
birthDate: DateTime(1995, 1, 1), // 1995년생
|
|
),
|
|
Member(
|
|
id: '4',
|
|
userId: 'user4',
|
|
clubId: '1',
|
|
name: '참가자 4',
|
|
email: 'user4@example.com',
|
|
isActive: true,
|
|
birthDate: DateTime(1980, 1, 1), // 1980년생 (가장 연장자)
|
|
),
|
|
];
|
|
}
|
|
|
|
// 점수 격차가 다른 테스트 점수 데이터 생성
|
|
List<Score> createScoreGapTestScores() {
|
|
return [
|
|
// 모두 동일한 총점 100점
|
|
Score(
|
|
id: '1',
|
|
memberId: '1',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10], // 격차 0
|
|
totalScore: 100,
|
|
handicap: 0,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 1',
|
|
),
|
|
Score(
|
|
id: '2',
|
|
memberId: '2',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [5, 15, 5, 15, 5, 15, 5, 15, 5, 15], // 격차 10
|
|
totalScore: 100,
|
|
handicap: 0,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 2',
|
|
),
|
|
Score(
|
|
id: '3',
|
|
memberId: '3',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [0, 20, 0, 20, 0, 20, 0, 20, 0, 20], // 격차 20
|
|
totalScore: 100,
|
|
handicap: 0,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 3',
|
|
),
|
|
];
|
|
}
|
|
|
|
test('기본 점수 정렬 테스트 (핸디캡 미포함)', () {
|
|
// given
|
|
final scores = createTestScores();
|
|
|
|
// when
|
|
final sortedScores = TieBreakerUtil.sortScoresByOptions(
|
|
scores,
|
|
null, // 옵션 없음
|
|
null,
|
|
false // 핸디캡 미포함
|
|
);
|
|
|
|
// then
|
|
expect(sortedScores[0].id, '1'); // 100점
|
|
expect(sortedScores[1].id, '2'); // 90점
|
|
expect(sortedScores[2].id, '3'); // 90점
|
|
expect(sortedScores[3].id, '4'); // 80점
|
|
|
|
// 순위 계산 확인
|
|
final ranks = TieBreakerUtil.calculateRanks(sortedScores, false, options: null);
|
|
expect(ranks['1'], 1); // 1위
|
|
expect(ranks['2'], 2); // 2위
|
|
expect(ranks['3'], 2); // 2위
|
|
expect(ranks['4'], 4); // 4위
|
|
});
|
|
|
|
test('기본 점수 정렬 테스트 (핸디캡 포함)', () {
|
|
// given
|
|
final scores = createTestScores();
|
|
|
|
// when
|
|
final sortedScores = TieBreakerUtil.sortScoresByOptions(
|
|
scores,
|
|
null, // 옵션 없음
|
|
null,
|
|
true // 핸디캡 포함
|
|
);
|
|
|
|
// then
|
|
// 핸디캡 포함 시: 참가자1(100), 참가자2(100), 참가자4(100), 참가자3(90)
|
|
expect(sortedScores[0].id, equals('1')); // 100점
|
|
expect(sortedScores[1].id, equals('2')); // 100점
|
|
expect(sortedScores[2].id, equals('4')); // 100점
|
|
expect(sortedScores[3].id, equals('3')); // 90점
|
|
|
|
// 순위 계산 확인
|
|
final ranks = TieBreakerUtil.calculateRanks(sortedScores, true);
|
|
expect(ranks['1'], 1); // 1위
|
|
expect(ranks['2'], 1); // 1위
|
|
expect(ranks['4'], 1); // 1위
|
|
expect(ranks['3'], 4); // 4위
|
|
});
|
|
|
|
test('동점자 처리 옵션: 핸디캡이 적은 순 (lowerHandicap)', () {
|
|
// given
|
|
final scores = createTestScores();
|
|
final options = [TieBreakerOption.lowerHandicap];
|
|
|
|
// when
|
|
final sortedScores = TieBreakerUtil.sortScoresByOptions(
|
|
scores,
|
|
options,
|
|
null,
|
|
true // 핸디캡 포함
|
|
);
|
|
|
|
// then
|
|
// 핸디캡 포함 시 동점인 경우, 핸디캡이 적은 순으로 정렬
|
|
// 참가자1(100점, 핸디캡0), 참가자2(100점, 핸디캡10), 참가자4(100점, 핸디캡20), 참가자3(90점)
|
|
expect(sortedScores[0].id, equals('1')); // 핸디캡 0
|
|
expect(sortedScores[1].id, equals('2')); // 핸디캡 10
|
|
expect(sortedScores[2].id, equals('4')); // 핸디캡 20
|
|
expect(sortedScores[3].id, equals('3')); // 90점
|
|
|
|
// 순위 계산 확인
|
|
final ranks = TieBreakerUtil.calculateRanks(sortedScores, true);
|
|
expect(ranks['1'], 1); // 1위
|
|
expect(ranks['2'], 1); // 1위
|
|
expect(ranks['4'], 1); // 1위
|
|
expect(ranks['3'], 4); // 4위
|
|
});
|
|
|
|
test('동점자 처리 옵션: 점수 격차가 적은 순 (lowerScoreGap)', () {
|
|
// given
|
|
final scores = createScoreGapTestScores();
|
|
final options = [TieBreakerOption.lowerScoreGap];
|
|
|
|
// when
|
|
final sortedScores = TieBreakerUtil.sortScoresByOptions(
|
|
scores,
|
|
options,
|
|
null,
|
|
false // 핸디캡 미포함
|
|
);
|
|
|
|
// then
|
|
// 모두 100점으로 동점이지만, 점수 격차가 적은 순으로 정렬
|
|
// 참가자1(격차0), 참가자2(격차10), 참가자3(격차20)
|
|
expect(sortedScores[0].id, equals('1')); // 격차 0
|
|
expect(sortedScores[1].id, equals('2')); // 격차 10
|
|
expect(sortedScores[2].id, equals('3')); // 격차 20
|
|
|
|
// 순위 계산 확인
|
|
final ranks = TieBreakerUtil.calculateRanks(sortedScores, false, options: options);
|
|
expect(ranks['1'], 1); // 1위
|
|
expect(ranks['2'], 1); // 1위
|
|
expect(ranks['3'], 1); // 1위
|
|
});
|
|
|
|
test('동점자 처리 옵션: 연장자 우선 (olderAge)', () {
|
|
// given
|
|
final scores = createTestScores();
|
|
final members = createTestMembers();
|
|
final options = [TieBreakerOption.olderAge];
|
|
|
|
// 테스트 데이터 확인용 로그
|
|
debugPrint('\n===== 테스트 데이터 확인 =====');
|
|
for (var score in scores) {
|
|
debugPrint('Score ID: ${score.id}, 총점: ${score.totalScore}, 핸디캡: ${score.handicap}');
|
|
}
|
|
for (var member in members) {
|
|
debugPrint('Member ID: ${member.id}, 생년월일: ${member.birthDate}');
|
|
}
|
|
|
|
// when
|
|
final sortedScores = TieBreakerUtil.sortScoresByOptions(
|
|
scores,
|
|
options,
|
|
members,
|
|
true // 핸디캡 포함
|
|
);
|
|
|
|
// 정렬 결과 확인용 로그
|
|
debugPrint('\n===== 정렬 결과 확인 =====');
|
|
for (var score in sortedScores) {
|
|
debugPrint('Sorted Score ID: ${score.id}, 총점: ${score.totalScore}, 핸디캡: ${score.handicap}');
|
|
}
|
|
|
|
// then
|
|
// 핸디캡 포함 시 동점인 경우, 연장자 우선으로 정렬
|
|
// 참가자4(1980년생), 참가자2(1985년생), 참가자1(1990년생), 참가자3(90점)
|
|
expect(sortedScores[0].id, equals('4')); // 1980년생
|
|
expect(sortedScores[1].id, equals('2')); // 1985년생
|
|
expect(sortedScores[2].id, equals('1')); // 1990년생
|
|
expect(sortedScores[3].id, equals('3')); // 90점
|
|
|
|
// 순위 계산 확인
|
|
final ranks = TieBreakerUtil.calculateRanks(sortedScores, true, options: options);
|
|
|
|
// 순위 계산 결과 확인용 로그
|
|
debugPrint('\n===== 순위 계산 결과 확인 =====');
|
|
for (var id in ranks.keys) {
|
|
debugPrint('ID: $id, 순위: ${ranks[id]}');
|
|
}
|
|
|
|
expect(ranks['4'], 1); // 1위
|
|
expect(ranks['2'], 2); // 2위
|
|
expect(ranks['1'], 3); // 3위
|
|
expect(ranks['3'], 4); // 4위
|
|
});
|
|
|
|
test('동점자 처리 옵션 우선순위 적용 (lowerHandicap -> olderAge)', () {
|
|
// given
|
|
// 핸디캐프이 같은 경우 연장자 우선
|
|
final options = [TieBreakerOption.lowerHandicap, TieBreakerOption.olderAge];
|
|
final members = createTestMembers();
|
|
|
|
debugPrint('\n===== lowerHandicap -> olderAge 테스트 데이터 확인 =====');
|
|
for (var member in members) {
|
|
debugPrint('Member ID: ${member.id}, 생년월일: ${member.birthDate}');
|
|
}
|
|
|
|
// 핸디캐프이 서로 다른 새 점수 데이터 생성
|
|
final scores = [
|
|
// 참가자1: 100점, 핸디캐프 0, 1990년생
|
|
Score(
|
|
id: '1',
|
|
memberId: '1',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10],
|
|
totalScore: 100,
|
|
handicap: 0,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 1',
|
|
),
|
|
// 참가자2: 90점, 핸디캐프 10, 1985년생
|
|
Score(
|
|
id: '2',
|
|
memberId: '2',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9],
|
|
totalScore: 90,
|
|
handicap: 10,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 2',
|
|
),
|
|
// 참가자3: 90점, 핸디캐프 0, 1995년생
|
|
Score(
|
|
id: '3',
|
|
memberId: '3',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9],
|
|
totalScore: 90,
|
|
handicap: 0,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 3',
|
|
),
|
|
];
|
|
|
|
// 점수 데이터 확인
|
|
debugPrint('\n===== 점수 데이터 확인 =====');
|
|
for (var score in scores) {
|
|
debugPrint('Score ID: ${score.id}, 총점: ${score.totalScore}, 핸디캡: ${score.handicap}');
|
|
}
|
|
|
|
// when
|
|
final sortedScores = TieBreakerUtil.sortScoresByOptions(
|
|
scores,
|
|
options,
|
|
members,
|
|
false // 핸디캡 미포함
|
|
);
|
|
|
|
// 정렬 결과 확인
|
|
debugPrint('\n===== 정렬 결과 확인 =====');
|
|
for (var score in sortedScores) {
|
|
debugPrint('Sorted Score ID: ${score.id}, 총점: ${score.totalScore}, 핸디캡: ${score.handicap}');
|
|
}
|
|
|
|
// then
|
|
// 기본 점수 정렬 후 핸디캡이 낮은 순, 연장자 순으로 정렬
|
|
expect(sortedScores[0].id, equals('1')); // 100점
|
|
expect(sortedScores[1].id, equals('3')); // 90점, 핸디캡 0
|
|
expect(sortedScores[2].id, equals('2')); // 90점, 핸디캡 10
|
|
|
|
// 순위 계산 확인
|
|
final ranks = TieBreakerUtil.calculateRanks(sortedScores, false, options: options);
|
|
|
|
// 순위 계산 결과 확인
|
|
debugPrint('\n===== 순위 계산 결과 확인 =====');
|
|
for (var id in ranks.keys) {
|
|
debugPrint('ID: $id, 순위: ${ranks[id]}');
|
|
}
|
|
|
|
expect(ranks['1'], 1); // 1위
|
|
expect(ranks['3'], 2); // 2위
|
|
expect(ranks['2'], 3); // 3위
|
|
});
|
|
|
|
test('동점자 처리 옵션 우선순위 적용 (lowerScoreGap -> lowerHandicap -> olderAge)', () {
|
|
// given
|
|
final scores = [
|
|
Score(
|
|
id: '1',
|
|
memberId: '1',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [5, 15, 5, 15, 5, 15, 5, 15, 5, 15], // 격차 10
|
|
totalScore: 100,
|
|
handicap: 10,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 1',
|
|
),
|
|
Score(
|
|
id: '2',
|
|
memberId: '2',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10], // 격차 0
|
|
totalScore: 100,
|
|
handicap: 0,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 2',
|
|
),
|
|
Score(
|
|
id: '3',
|
|
memberId: '3',
|
|
eventId: '1',
|
|
clubId: '1',
|
|
frames: [5, 15, 5, 15, 5, 15, 5, 15, 5, 15], // 격차 10
|
|
totalScore: 100,
|
|
handicap: 0,
|
|
date: DateTime.now(),
|
|
notes: '',
|
|
participantName: '참가자 3',
|
|
),
|
|
];
|
|
|
|
final members = createTestMembers();
|
|
// 점수 격차 -> 핸디캡 -> 연장자 순으로 우선순위 적용
|
|
final options = [
|
|
TieBreakerOption.lowerScoreGap,
|
|
TieBreakerOption.lowerHandicap,
|
|
TieBreakerOption.olderAge
|
|
];
|
|
|
|
// 테스트 데이터 확인용 로그
|
|
debugPrint('\n===== lowerScoreGap -> lowerHandicap -> olderAge 테스트 데이터 확인 =====');
|
|
for (var score in scores) {
|
|
debugPrint('Score ID: ${score.id}, 총점: ${score.totalScore}, 핸디캡: ${score.handicap}, 프레임: ${score.frames}');
|
|
}
|
|
for (var member in members) {
|
|
debugPrint('Member ID: ${member.id}, 생년월일: ${member.birthDate}');
|
|
}
|
|
|
|
// when
|
|
final sortedScores = TieBreakerUtil.sortScoresByOptions(
|
|
scores,
|
|
options,
|
|
members,
|
|
false // 핸디캡 미포함
|
|
);
|
|
|
|
// 정렬 결과 확인용 로그
|
|
debugPrint('\n===== 정렬 결과 확인 =====');
|
|
for (var score in sortedScores) {
|
|
debugPrint('Sorted Score ID: ${score.id}, 총점: ${score.totalScore}, 핸디캡: ${score.handicap}, 프레임: ${score.frames}');
|
|
}
|
|
|
|
// then
|
|
// 1. 점수 격차가 적은 순: 참가자2(격차0) > 참가자1,3(격차10)
|
|
// 2. 핸디캡이 적은 순: 참가자3(핸디캡0) > 참가자1(핸디캡10)
|
|
expect(sortedScores[0].id, equals('2')); // 격차0, 핸디캡0
|
|
expect(sortedScores[1].id, equals('3')); // 격차10, 핸디캡0
|
|
expect(sortedScores[2].id, equals('1')); // 격차10, 핸디캡10
|
|
|
|
// 순위 계산 확인
|
|
final ranks = TieBreakerUtil.calculateRanks(sortedScores, false, options: options);
|
|
|
|
// 순위 계산 결과 확인용 로그
|
|
debugPrint('\n===== 순위 계산 결과 확인 =====');
|
|
for (var id in ranks.keys) {
|
|
debugPrint('ID: $id, 순위: ${ranks[id]}');
|
|
}
|
|
|
|
expect(ranks['2'], 1); // 1위
|
|
expect(ranks['3'], 1); // 1위 (lowerScoreGap 옵션에 의해 동일 순위)
|
|
expect(ranks['1'], 3); // 3위
|
|
});
|
|
|
|
test('옵션이 없는 경우 기본 정렬만 적용', () {
|
|
// given
|
|
final scores = createTestScores();
|
|
final options = [TieBreakerOption.none];
|
|
|
|
// when
|
|
final sortedScores = TieBreakerUtil.sortScoresByOptions(
|
|
scores,
|
|
options,
|
|
null,
|
|
false // 핸디캡 미포함
|
|
);
|
|
|
|
// then
|
|
// 기본 점수 정렬만 적용
|
|
expect(sortedScores[0].id, equals('1')); // 100점
|
|
expect(sortedScores[1].id, equals('2')); // 90점
|
|
expect(sortedScores[2].id, equals('3')); // 90점
|
|
expect(sortedScores[3].id, equals('4')); // 80점
|
|
});
|
|
});
|
|
}
|