diff --git a/packages/neon/neon/lib/src/models/account.dart b/packages/neon/neon/lib/src/models/account.dart index a690483a..567b555a 100644 --- a/packages/neon/neon/lib/src/models/account.dart +++ b/packages/neon/neon/lib/src/models/account.dart @@ -66,16 +66,26 @@ class Account implements Credentials { String get id { final key = '$username@$serverURL'; - if (_idCache[key] != null) { - return _idCache[key]!; - } - return _idCache[key] = sha1.convert(utf8.encode(key)).toString(); + + return _idCache[key] ??= sha1.convert(utf8.encode(key)).toString(); } String get humanReadableID { final uri = Uri.parse(serverURL); + // Maybe also show path if it is not '/' ? - return '$username@${uri.port != 443 ? '${uri.host}:${uri.port}' : uri.host}'; + final buffer = StringBuffer() + ..write(username) + ..write('@') + ..write(uri.host); + + if (uri.hasPort) { + buffer + ..write(':') + ..write(uri.port); + } + + return buffer.toString(); } /// Completes an incomplete [Uri] using the [serverURL]. diff --git a/packages/neon/neon/test/account_test.dart b/packages/neon/neon/test/account_test.dart index a86b934e..34e360f4 100644 --- a/packages/neon/neon/test/account_test.dart +++ b/packages/neon/neon/test/account_test.dart @@ -60,4 +60,91 @@ void main() { }); } }); + + group('Account', () { + final account = Account( + serverURL: 'http://example.com', + username: 'JohnDoe', + password: 'super_secret', + ); + + test('serialization', () { + const json = { + 'serverURL': 'http://example.com', + 'username': 'JohnDoe', + 'password': 'super_secret', + 'userAgent': null, + }; + + expect(account.toJson(), equals(json)); + + expect(Account.fromJson(json), equals(account)); + }); + + test('id', () { + expect(account.id, '8bcb507a406c5ad0eed4072601bcfdd2d923e87d'); + }); + + test('humanReadableID', () { + expect(account.humanReadableID, 'JohnDoe@example.com'); + + final accountWithDefaultPort = Account( + serverURL: 'http://example.com:80', + username: 'JohnDoe', + password: 'super_secret', + ); + + expect(accountWithDefaultPort.humanReadableID, 'JohnDoe@example.com'); + + final accountWithPort = Account( + serverURL: 'http://example.com:8080', + username: 'JohnDoe', + password: 'super_secret', + ); + + expect(accountWithPort.humanReadableID, 'JohnDoe@example.com:8080'); + }); + }); + + test('AccountFind', () { + final account1 = Account( + serverURL: 'http://example.com', + username: 'JohnDoe', + password: 'super_secret', + ); + final account2 = Account( + serverURL: 'http://example.com', + username: 'JohnDoe2', + password: 'super_secret', + ); + final account3 = Account( + serverURL: 'http://example.com', + username: 'JohnDoe3', + password: 'super_secret', + ); + final account4 = Account( + serverURL: 'http://example.com', + username: 'JohnDoe4', + password: 'super_secret', + ); + final account5 = Account( + serverURL: 'http://example.com', + username: 'JohnDoe5', + password: 'super_secret', + ); + final accounts = { + account1, + account2, + account3, + account4, + account5, + }; + + expect(accounts.tryFind(null), isNull); + expect(accounts.tryFind('invalidID'), isNull); + expect(accounts.tryFind(account3.id), equals(account3)); + + expect(() => accounts.find('invalidID'), throwsA(isA())); + expect(accounts.find(account3.id), equals(account3)); + }); } diff --git a/packages/neon/neon/test/neon_platform_test.dart b/packages/neon/neon/test/neon_platform_test.dart new file mode 100644 index 00000000..06c6395d --- /dev/null +++ b/packages/neon/neon/test/neon_platform_test.dart @@ -0,0 +1,12 @@ +import 'package:neon/src/platform/platform.dart'; +import 'package:test/test.dart'; + +void main() { + test('NeonPlatform', () async { + expect(() => NeonPlatform.instance, throwsA(isA())); + + await NeonPlatform.setup(); + + expect(NeonPlatform.instance, isA()); + }); +} diff --git a/packages/neon/neon/test/stream_listenable_test.dart b/packages/neon/neon/test/stream_listenable_test.dart new file mode 100644 index 00000000..7ae1d841 --- /dev/null +++ b/packages/neon/neon/test/stream_listenable_test.dart @@ -0,0 +1,73 @@ +// ignore_for_file: unreachable_from_main + +import 'dart:async'; + +import 'package:mocktail/mocktail.dart'; +import 'package:neon/src/utils/stream_listenable.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:test/test.dart'; + +class MockCallbackFunction extends Mock { + FutureOr call(); +} + +void main() { + group('StreamListenable', () { + test('stream', () async { + final stream = BehaviorSubject(); + final callback = MockCallbackFunction(); + + StreamListenable(stream).addListener(callback.call); + + verifyNever(callback.call); + + stream.value = true; + await Future.delayed(const Duration(milliseconds: 100)); + verify(callback.call).called(1); + + stream.value = true; + await Future.delayed(const Duration(milliseconds: 100)); + verify(callback.call).called(1); + + unawaited(stream.close()); + }); + + test('multiStream', () async { + final stream = BehaviorSubject(); + final stream2 = BehaviorSubject(); + final callback = MockCallbackFunction(); + + StreamListenable.multiListenable({ + stream, + stream2, + }).addListener(callback.call); + + verifyNever(callback.call); + + stream.value = true; + await Future.delayed(const Duration(milliseconds: 100)); + verify(callback.call).called(1); + + stream2.value = 3; + await Future.delayed(const Duration(milliseconds: 100)); + verify(callback.call).called(1); + + unawaited(stream.close()); + unawaited(stream2.close()); + }); + + test('dispose', () { + final controller = StreamController(); + + final listenable = StreamListenable(controller.stream); + + expect(controller.hasListener, true); + + // ignore: cascade_invocations + listenable.dispose(); + + expect(controller.isClosed, false); + unawaited(controller.close()); + }); + }); +} diff --git a/packages/neon/neon/test/useragent_test.dart b/packages/neon/neon/test/useragent_test.dart new file mode 100644 index 00000000..b4550fa2 --- /dev/null +++ b/packages/neon/neon/test/useragent_test.dart @@ -0,0 +1,17 @@ +import 'package:neon/src/utils/user_agent.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:test/test.dart'; + +void main() { + test('UserAgent', () { + final packageInfo = PackageInfo( + appName: 'appName', + packageName: 'packageName', + version: 'version', + buildNumber: 'buildNumber', + ); + buildUserAgent(packageInfo); + + expect(neonUserAgent, 'Neon version+buildNumber'); + }); +}