MotorSignal-App/test/club_models_test.dart

249 lines
9.7 KiB
Dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:motorcycle_dash/services/clubs/club_models.dart';
void main() {
group('Club Enums', () {
test('ClubVisibility labels and parsing', () {
expect(ClubVisibility.public.label, equals('Public'));
expect(ClubVisibility.unlisted.label, equals('Unlisted'));
expect(ClubVisibility.private.label, equals('Private'));
expect(ClubVisibility.fromString('public'), equals(ClubVisibility.public));
expect(ClubVisibility.fromString('unlisted'), equals(ClubVisibility.unlisted));
expect(ClubVisibility.fromString('private'), equals(ClubVisibility.private));
expect(ClubVisibility.fromString('unknown'), equals(ClubVisibility.public));
expect(ClubVisibility.fromString(null), equals(ClubVisibility.public));
});
test('ClubAdmissionPolicy labels and parsing', () {
expect(ClubAdmissionPolicy.open.label, equals('Open to Join'));
expect(ClubAdmissionPolicy.request.label, equals('Request to Join'));
expect(ClubAdmissionPolicy.inviteOnly.label, equals('Invite Only'));
expect(ClubAdmissionPolicy.fromString('open'), equals(ClubAdmissionPolicy.open));
expect(ClubAdmissionPolicy.fromString('request'), equals(ClubAdmissionPolicy.request));
expect(ClubAdmissionPolicy.fromString('inviteOnly'), equals(ClubAdmissionPolicy.inviteOnly));
expect(ClubAdmissionPolicy.fromString('other'), equals(ClubAdmissionPolicy.request));
expect(ClubAdmissionPolicy.fromString(null), equals(ClubAdmissionPolicy.request));
});
test('ClubRole labels, rank hierarchy, and parsing', () {
expect(ClubRole.owner.label, equals('Owner'));
expect(ClubRole.admin.label, equals('Admin'));
expect(ClubRole.member.label, equals('Member'));
// Hierarchy
expect(ClubRole.owner.isAtLeast(ClubRole.owner), isTrue);
expect(ClubRole.owner.isAtLeast(ClubRole.admin), isTrue);
expect(ClubRole.owner.isAtLeast(ClubRole.member), isTrue);
expect(ClubRole.admin.isAtLeast(ClubRole.owner), isFalse);
expect(ClubRole.admin.isAtLeast(ClubRole.admin), isTrue);
expect(ClubRole.admin.isAtLeast(ClubRole.member), isTrue);
expect(ClubRole.member.isAtLeast(ClubRole.owner), isFalse);
expect(ClubRole.member.isAtLeast(ClubRole.admin), isFalse);
expect(ClubRole.member.isAtLeast(ClubRole.member), isTrue);
expect(ClubRole.fromString('owner'), equals(ClubRole.owner));
expect(ClubRole.fromString('admin'), equals(ClubRole.admin));
expect(ClubRole.fromString('member'), equals(ClubRole.member));
expect(ClubRole.fromString(null), equals(ClubRole.member));
});
test('ClubMemberStatus classification and parsing', () {
expect(ClubMemberStatus.active.isActive, isTrue);
expect(ClubMemberStatus.invited.isActive, isFalse);
expect(ClubMemberStatus.requested.isActive, isFalse);
expect(ClubMemberStatus.invited.isPending, isTrue);
expect(ClubMemberStatus.requested.isPending, isTrue);
expect(ClubMemberStatus.active.isPending, isFalse);
expect(ClubMemberStatus.declined.isHistorical, isTrue);
expect(ClubMemberStatus.left.isHistorical, isTrue);
expect(ClubMemberStatus.removed.isHistorical, isTrue);
expect(ClubMemberStatus.active.isHistorical, isFalse);
expect(ClubMemberStatus.fromString('active'), equals(ClubMemberStatus.active));
expect(ClubMemberStatus.fromString('invited'), equals(ClubMemberStatus.invited));
expect(ClubMemberStatus.fromString('requested'), equals(ClubMemberStatus.requested));
expect(ClubMemberStatus.fromString('left'), equals(ClubMemberStatus.left));
expect(ClubMemberStatus.fromString('removed'), equals(ClubMemberStatus.removed));
expect(ClubMemberStatus.fromString('declined'), equals(ClubMemberStatus.declined));
expect(ClubMemberStatus.fromString(null), equals(ClubMemberStatus.declined));
});
});
group('Club Model', () {
final now = DateTime(2026, 9, 6, 12, 0, 0);
test('full serialization roundtrip (JSON and Firestore)', () {
final club = Club(
id: 'club_1',
name: 'Bay Area Sport Riders',
slug: 'bay-area-sport-riders',
description: 'Twisties and canyon carving',
visibility: ClubVisibility.public,
admissionPolicy: ClubAdmissionPolicy.request,
ownerUid: 'user_alice',
memberCount: 24,
createdAt: now,
updatedAt: now,
archivedAt: null,
logoUrl: 'https://example.com/logo.png',
bannerUrl: 'https://example.com/banner.png',
homeRegion: 'San Francisco Bay Area',
motorcycleFocus: 'Sport / Canyon',
);
final json = club.toJson();
final fromJson = Club.fromJson(json);
expect(fromJson.id, equals(club.id));
expect(fromJson.name, equals(club.name));
expect(fromJson.slug, equals(club.slug));
expect(fromJson.description, equals(club.description));
expect(fromJson.visibility, equals(club.visibility));
expect(fromJson.admissionPolicy, equals(club.admissionPolicy));
expect(fromJson.ownerUid, equals(club.ownerUid));
expect(fromJson.memberCount, equals(club.memberCount));
expect(fromJson.createdAt, equals(club.createdAt));
expect(fromJson.updatedAt, equals(club.updatedAt));
expect(fromJson.archivedAt, isNull);
expect(fromJson.isArchived, isFalse);
expect(fromJson.logoUrl, equals(club.logoUrl));
expect(fromJson.bannerUrl, equals(club.bannerUrl));
expect(fromJson.homeRegion, equals(club.homeRegion));
expect(fromJson.motorcycleFocus, equals(club.motorcycleFocus));
// Firestore map serialization
final fsMap = club.toFirestore();
expect(fsMap['createdAt'], isA<Timestamp>());
expect(fsMap['updatedAt'], isA<Timestamp>());
expect(fsMap['archivedAt'], isNull);
// Deserializing from map with Timestamps
final fromFs = Club.fromJson(fsMap);
expect(fromFs.name, equals(club.name));
expect(fromFs.createdAt, equals(club.createdAt));
});
test('copyWith handles updates and null clearing', () {
final club = Club(
id: 'club_1',
name: 'Alpha Club',
slug: 'alpha-club',
ownerUid: 'alice',
createdAt: now,
updatedAt: now,
archivedAt: now,
);
expect(club.isArchived, isTrue);
final unarchived = club.copyWith(clearArchivedAt: true);
expect(unarchived.archivedAt, isNull);
expect(unarchived.isArchived, isFalse);
final updatedName = club.copyWith(name: 'Beta Club');
expect(updatedName.name, equals('Beta Club'));
expect(updatedName.slug, equals('alpha-club'));
});
});
group('ClubMember Model', () {
final now = DateTime(2026, 9, 6, 12, 0, 0);
test('lean serialization roundtrip without duplicated rider profile identity', () {
final member = ClubMember(
uid: 'user_bob',
clubId: 'club_1',
status: ClubMemberStatus.active,
role: ClubRole.admin,
displayRank: 'Road Captain',
joinedAt: now,
requestedAt: now.subtract(const Duration(days: 1)),
invitedByUid: 'user_alice',
updatedAt: now,
);
expect(member.isActive, isTrue);
expect(member.isAdmin, isTrue);
expect(member.isOwner, isFalse);
final json = member.toJson();
// Ensure no identity duplication
expect(json.containsKey('riderHandleSnapshot'), isFalse);
expect(json.containsKey('riderDisplayNameSnapshot'), isFalse);
expect(json.containsKey('riderAvatarPreset'), isFalse);
expect(json.containsKey('riderAvatarUrl'), isFalse);
final fromJson = ClubMember.fromJson(json);
expect(fromJson.uid, equals(member.uid));
expect(fromJson.clubId, equals(member.clubId));
expect(fromJson.status, equals(member.status));
expect(fromJson.role, equals(member.role));
expect(fromJson.displayRank, equals('Road Captain'));
expect(fromJson.invitedByUid, equals('user_alice'));
expect(fromJson.joinedAt, equals(member.joinedAt));
});
test('copyWith handles displayRank clearing', () {
final member = ClubMember(
uid: 'user_bob',
clubId: 'club_1',
status: ClubMemberStatus.active,
role: ClubRole.member,
displayRank: 'Tail Gunner',
updatedAt: now,
);
final cleared = member.copyWith(clearDisplayRank: true);
expect(cleared.displayRank, isNull);
});
});
group('ClubBan Model', () {
final now = DateTime(2026, 9, 6, 12, 0, 0);
test('ban document serialization preserves reason', () {
final ban = ClubBan(
uid: 'troublemaker',
clubId: 'club_1',
bannedByUid: 'alice',
bannedAt: now,
reason: 'Violating group ride safety rules',
);
final json = ban.toJson();
final fromJson = ClubBan.fromJson(json);
expect(fromJson.uid, equals('troublemaker'));
expect(fromJson.bannedByUid, equals('alice'));
expect(fromJson.bannedAt, equals(now));
expect(fromJson.reason, equals('Violating group ride safety rules'));
});
});
group('ClubHandle Model', () {
final now = DateTime(2026, 9, 6, 12, 0, 0);
test('handle reservation document serialization', () {
final handle = ClubHandle(
slug: 'norcal-adv',
clubId: 'club_norcal',
ownerUid: 'alice',
createdAt: now,
);
final json = handle.toJson();
final fromJson = ClubHandle.fromJson(json);
expect(fromJson.slug, equals('norcal-adv'));
expect(fromJson.clubId, equals('club_norcal'));
expect(fromJson.ownerUid, equals('alice'));
expect(fromJson.createdAt, equals(now));
});
});
}