120 lines
4.3 KiB
Dart
120 lines
4.3 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:plezy/profiles/profile.dart';
|
|
|
|
void main() {
|
|
group('Profile', () {
|
|
test('local PIN hash is round-tripped via configJson', () {
|
|
final p = Profile.local(
|
|
id: 'local-1',
|
|
displayName: 'Kids',
|
|
pinHash: computePinHash('1234'),
|
|
createdAt: DateTime(2026, 1, 1),
|
|
);
|
|
final json = p.toConfigJson();
|
|
final restored = Profile.fromRow(
|
|
id: p.id,
|
|
kind: 'local',
|
|
displayName: p.displayName,
|
|
avatarThumbUrl: null,
|
|
json: json,
|
|
sortOrder: 0,
|
|
createdAt: p.createdAt,
|
|
lastUsedAt: null,
|
|
);
|
|
expect(restored.pinHash, p.pinHash);
|
|
expect(restored.isPinProtected, isTrue);
|
|
});
|
|
|
|
test('plex_home configJson round-trips with all flags', () {
|
|
final p = Profile.plexHome(
|
|
id: 'plex-home-acct1-uuid1',
|
|
displayName: 'Admin',
|
|
parentConnectionId: 'acct1',
|
|
plexAdmin: true,
|
|
plexRestricted: false,
|
|
plexProtected: true,
|
|
createdAt: DateTime(2026, 1, 1),
|
|
);
|
|
final json = p.toConfigJson();
|
|
final restored = Profile.fromRow(
|
|
id: p.id,
|
|
kind: 'plex_home',
|
|
displayName: p.displayName,
|
|
avatarThumbUrl: null,
|
|
json: json,
|
|
sortOrder: 0,
|
|
createdAt: p.createdAt,
|
|
lastUsedAt: null,
|
|
);
|
|
expect(restored.plexAdmin, isTrue);
|
|
expect(restored.plexRestricted, isFalse);
|
|
expect(restored.plexProtected, isTrue);
|
|
expect(restored.parentConnectionId, 'acct1');
|
|
});
|
|
|
|
test('plexHomeProfileId is deterministic', () {
|
|
expect(plexHomeProfileId(accountConnectionId: 'plex.dev1', homeUserUuid: 'uuid-1'), 'plex-home-plex.dev1-uuid-1');
|
|
});
|
|
|
|
test('parsePlexHomeProfileId round-trips a real 16-hex uuid', () {
|
|
// Real plex.tv home-user uuids are 16-char plain hex, and the account
|
|
// connection id itself usually ends in one (plex.{accountUuid}).
|
|
const acct = 'plex.e443d57860076fc3';
|
|
const uuid = '379704d0c6601309';
|
|
final id = plexHomeProfileId(accountConnectionId: acct, homeUserUuid: uuid);
|
|
final parsed = parsePlexHomeProfileId(id);
|
|
expect(parsed, isNotNull);
|
|
expect(parsed!.accountConnectionId, acct);
|
|
expect(parsed.homeUserUuid, uuid);
|
|
});
|
|
|
|
test('parsePlexHomeProfileId round-trips a hyphenated RFC-4122 uuid', () {
|
|
// Defensive alternate shape; accountConnectionId can carry hyphens too
|
|
// (e.g. plex.client-id).
|
|
const acct = 'plex.client-id-123';
|
|
const uuid = 'a1b2c3d4-e5f6-7890-abcd-ef0123456789';
|
|
final id = plexHomeProfileId(accountConnectionId: acct, homeUserUuid: uuid);
|
|
final parsed = parsePlexHomeProfileId(id);
|
|
expect(parsed, isNotNull);
|
|
expect(parsed!.accountConnectionId, acct);
|
|
expect(parsed.homeUserUuid, uuid);
|
|
});
|
|
|
|
test('parsePlexHomeProfileId splits at the last uuid-shaped segment', () {
|
|
// A hex-ending account id must not steal the uuid slot: the $ anchor
|
|
// forces the trailing segment to be the home-user uuid.
|
|
const acct = 'acct-aaaaaaaaaaaaaaaa';
|
|
const uuid = 'bbbbbbbbbbbbbbbb';
|
|
final parsed = parsePlexHomeProfileId(plexHomeProfileId(accountConnectionId: acct, homeUserUuid: uuid));
|
|
expect(parsed, isNotNull);
|
|
expect(parsed!.accountConnectionId, acct);
|
|
expect(parsed.homeUserUuid, uuid);
|
|
});
|
|
|
|
test('parsePlexHomeProfileId rejects non-Plex-Home ids', () {
|
|
expect(parsePlexHomeProfileId('local-1'), isNull);
|
|
expect(parsePlexHomeProfileId('plex-home-only'), isNull);
|
|
expect(parsePlexHomeProfileId('plex-home-acct-not-a-uuid'), isNull);
|
|
// 15 and 17 hex chars are not uuids.
|
|
expect(parsePlexHomeProfileId('plex-home-acct-aaaaaaaaaaaaaaa'), isNull);
|
|
expect(parsePlexHomeProfileId('plex-home-acct-aaaaaaaaaaaaaaaaa'), isNull);
|
|
});
|
|
});
|
|
|
|
group('PIN hashing', () {
|
|
test('computePinHash is deterministic for the same input', () {
|
|
expect(computePinHash('1234'), computePinHash('1234'));
|
|
});
|
|
|
|
test('computePinHash differs for different inputs', () {
|
|
expect(computePinHash('1234'), isNot(computePinHash('5678')));
|
|
});
|
|
|
|
test('verifyPin matches its hash', () {
|
|
final h = computePinHash('4242');
|
|
expect(verifyPin('4242', h), isTrue);
|
|
expect(verifyPin('1111', h), isFalse);
|
|
});
|
|
});
|
|
}
|