From 3fc1dcb71e3b98a856199fcb17910274e3062acf Mon Sep 17 00:00:00 2001 From: xantus smith <281845000+smith-909@users.noreply.github.com> Date: Tue, 27 Oct 2026 15:39:10 -0700 Subject: [PATCH 1/3] docs: correct the README's requirements, setup and privacy notes - Requirements: Flutter 3.38.1+, Dart 3.10+, iOS 13.0+, Android API 24+. Every app_links version the SDK accepts needs iOS 13 and minSdk 24, and the oldest needs Flutter 3.38.1 (as do device_info_plus 13.1 and package_info_plus 10.1); the README said Flutter 3.10, iOS 12, API 21. - Flutter's built-in deep linking: since Flutter 3.27 it's on by default and conflicts with app_links, so it must be turned off, not only "if you also use it". Adds the opt-out snippets from Flutter's breaking-change note to Platform Setup (the iOS key takes , not NO). - Quick Start: shows appToken, and says apiKey is only needed for createLink. - Privacy: no advertising IDs is the accurate claim; installs on Android are matched by the Play install referrer where available; the SDK stores the install ID the server assigns. Data collected now lists the platform, the Play install referrer and an optional app-supplied device ID. - Android setup: minSdk 24 and the Play App Signing fingerprint. --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 8b28a37..c6c858c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **Native Flutter SDK for deep linking, mobile attribution, and conversion tracking.** [![Pub Version](https://img.shields.io/pub/v/linkforty_flutter.svg)](https://pub.dev/packages/linkforty_flutter) -[![Flutter](https://img.shields.io/badge/Flutter-3.10+-02569B.svg)](https://flutter.dev) +[![Flutter](https://img.shields.io/badge/Flutter-3.38+-02569B.svg)](https://flutter.dev) [![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) ## Features @@ -16,16 +16,18 @@ - **Last-Click Attribution**: In-app events are automatically credited to the deep link that most recently opened the app - **Screen-Flow Tracking**: Report screen views (manually or automatically via a `NavigatorObserver`) to see what users do after clicking a link - **Offline Support**: Queue events when offline with automatic retry -- **Privacy-First**: No IDFA/GAID collection by default, complies with privacy requirements +- **Privacy-First**: Never collects IDFA or GAID, and never shows the App Tracking Transparency prompt - **Programmatic Link Creation**: Create short links directly from your app - **Pure Dart/Flutter**: 100% Dart, standard `Future`/`Stream` APIs ## Requirements -- Flutter 3.10+ -- Dart 3.0+ -- iOS 12.0+ -- Android API 21+ +- Flutter 3.38.1+ +- Dart 3.10+ +- iOS 13.0+ +- Android API 24+ (`minSdk 24`) + +These follow from the SDK's dependencies: every version of `app_links` it accepts needs iOS 13 and Android API 24, and the oldest needs Flutter 3.38.1. ## Installation @@ -46,7 +48,7 @@ flutter pub add linkforty_flutter ### 1. Initialize the SDK -Initialize the SDK in your `main.dart` or early in your app lifecycle. +Initialize the SDK once, in your `main.dart` or early in your app lifecycle. ```dart import 'package:linkforty_flutter/linkforty_flutter.dart'; @@ -57,8 +59,13 @@ void main() async { // Initialize LinkForty try { final config = LinkFortyConfig( - baseURL: Uri.parse('https://go.yourdomain.com'), - apiKey: 'your-api-key', // Optional for self-hosted + // Your LinkForty server: https://api.linkforty.com on the hosted service, + // or the URL of your own LinkForty Core server. + baseURL: Uri.parse('https://api.linkforty.com'), + // Your workspace's app token. Required on the hosted service: it limits + // install matching to your own links. Safe to ship in the app. + appToken: 'at_your_app_token', + apiKey: 'your-api-key', // Only needed to create links from the app (createLink) debug: true, // Enable debug logging attributionWindowHours: 168, // 7 days ); @@ -132,7 +139,7 @@ The SDK listens for incoming links itself (via `app_links`), including the link You don't need your own `app_links` listener. If you have one from an earlier version, remove it; if you keep it, the SDK ignores the same URL passed to `handleDeepLink()` again within 10 seconds. Use `handleDeepLink()` for links that reach the app some other way, such as a push notification payload. -If you also use Flutter's built-in deep linking, set `flutter_deeplinking_enabled` to `false` in `AndroidManifest.xml` (and `FlutterDeepLinkingEnabled` to `NO` in `Info.plist`) so the router doesn't also try to open the link's path. +**Turn off Flutter's built-in deep linking** (see [Platform Setup](#turn-off-flutters-built-in-deep-linking)). Since Flutter 3.27 it's on by default and conflicts with `app_links`: Flutter would also hand each link's path to your router, so a short link's `/abc123` opens a route that doesn't exist. With it off, all links, including your app's own, arrive through `onDeepLink`. ```dart // Handle deep links when app is running or opened from background @@ -223,6 +230,23 @@ print("Share this link: ${result.url}"); ## Platform Setup +### Turn off Flutter's built-in deep linking + +Since Flutter 3.27, Flutter's own deep link handling is on by default. Flutter's [breaking-change note](https://docs.flutter.dev/release/breaking-changes/deep-links-flag-change) says apps using a link package such as `app_links`, which this SDK uses, must opt out: + +**Android**, inside the `` element of `AndroidManifest.xml`: + +```xml + +``` + +**iOS**, in `ios/Runner/Info.plist`: + +```xml +FlutterDeepLinkingEnabled + +``` + ### Android 1. **AndroidManifest.xml**: Add the intent filters for App Links (HTTPS) and Custom Schemes. @@ -247,7 +271,8 @@ print("Share this link: ${result.url}"); ``` -2. **Asset Links**: Ensure your `.well-known/assetlinks.json` is hosted on your domain. +2. **Asset Links**: Ensure your `.well-known/assetlinks.json` is hosted on your domain, listing your package name and signing certificate's SHA-256 fingerprint. For Play Store builds, use the fingerprint from Play Console → App integrity: Google re-signs your app. +3. **minSdk**: set `minSdk = 24` (or higher) in `android/app/build.gradle`. ### iOS @@ -265,7 +290,6 @@ If you're running your own LinkForty Core instance: ```dart final config = LinkFortyConfig( baseURL: Uri.parse('https://links.yourcompany.com'), - apiKey: null, // No API key needed for self-hosted debug: false, ); await LinkForty.initialize(config: config); @@ -312,18 +336,21 @@ LinkForty.instance.reset(); ### Privacy-First Design -- **No Persistent IDs**: Uses probabilistic fingerprinting only. +- **No advertising IDs**: Never collects IDFA or GAID, and never shows the App Tracking Transparency prompt. +- **How installs are matched**: on Android, from the Google Play install referrer when the install came from a link to Google Play; otherwise by probabilistic fingerprinting of the signals below. +- **Install ID**: The SDK stores the install ID your server assigns when the install is reported, to tie your app's events to that install. `clearData()` deletes it, with any cached attribution and queued events. - **Data Minimization**: Collects only necessary attribution data. -- **User Control**: Provides `clearData()` for user data deletion. ### Data Collected (for attribution only) - Device timezone - Device language - Screen resolution -- OS version (Android/iOS) +- Platform and OS version (Android/iOS) - App version - User-Agent string +- The Google Play install referrer (Android, on the launch that reports the install) +- A device ID, only if your app passes one to `initialize(deviceId: ...)` ### HTTPS Required From ccc1ed7c03e4ef0f2eb7e7dcd36f0fc428f4a890 Mon Sep 17 00:00:00 2001 From: xantus smith <281845000+smith-909@users.noreply.github.com> Date: Tue, 27 Oct 2026 16:51:30 -0700 Subject: [PATCH 2/3] chore: state the Flutter, Dart, iOS and Android minimums the dependencies require The oldest app_links, device_info_plus and package_info_plus versions the SDK accepts need Flutter 3.38.1 and Dart 3.10, and every accepted app_links needs iOS 13 and Android API 24. Raise the package and example environment constraints to match, and set the example's iOS platform and minSdk explicitly. --- CHANGELOG.md | 4 ++++ example/android/app/build.gradle.kts | 3 ++- example/ios/Podfile | 4 ++-- example/pubspec.yaml | 4 ++-- pubspec.yaml | 4 ++-- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e470299..95099a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## Unreleased + +* **Corrected minimums.** `pubspec.yaml` now states the Flutter and Dart versions the SDK actually needs: Flutter 3.38.1+ and Dart 3.10+ (it said Flutter 3.10 and Dart 3.0). The oldest versions of `app_links`, `device_info_plus` and `package_info_plus` the SDK accepts already required them, so an older toolchain could not resolve the package; nothing changes for an app that builds today. Apps need iOS 13+ and Android API 24+ (`minSdk 24`), which every accepted `app_links` version requires. The example app sets `platform :ios, '13.0'` and `minSdk = 24` explicitly. + ## 0.6.0 * **Google Play install referrer.** On Android, the launch that reports the install reads the Play install referrer and sends it as `installReferrer`. A LinkForty link puts its click id in the referrer of the Play listing it sends a visitor to, so a server on `@linkforty/core` 1.41.1 or later matches the install to that exact click: `attributionMethod` is `"install_referrer"`, `confidenceScore` 100, `matchedFactors` `["install_referrer"]` and `competingLinks` 0. The SDK waits at most 2 seconds for Play and asks once more after a failed read; without a referrer (iOS, another store, a sideload, no answer) the install is matched by fingerprint as before. diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts index 8e6238e..35db812 100644 --- a/example/android/app/build.gradle.kts +++ b/example/android/app/build.gradle.kts @@ -24,7 +24,8 @@ android { applicationId = "linkforty.com.example" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. - minSdk = flutter.minSdkVersion + // API 24 is the minimum the LinkForty SDK's dependencies (app_links) support. + minSdk = 24 targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName diff --git a/example/ios/Podfile b/example/ios/Podfile index 620e46e..0ade033 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '13.0' +# iOS 13 is the minimum the LinkForty SDK's dependencies (app_links) support. +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 9478b95..4d012cc 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -19,8 +19,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=2.12.0 <4.0.0' - flutter: '>=3.0.0' + sdk: '>=3.10.0 <4.0.0' + flutter: '>=3.38.1' # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions diff --git a/pubspec.yaml b/pubspec.yaml index 997359c..443522f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,8 +14,8 @@ topics: - sdk environment: - sdk: '>=3.0.0 <4.0.0' - flutter: '>=3.10.0' + sdk: '>=3.10.0 <4.0.0' + flutter: '>=3.38.1' dependencies: flutter: From 40a1c51b5feca38a7f6379dd7094f74970cc9445 Mon Sep 17 00:00:00 2001 From: xantus smith <281845000+smith-909@users.noreply.github.com> Date: Tue, 27 Oct 2026 16:51:30 -0700 Subject: [PATCH 3/3] style: apply Dart 3.10 formatting and lints Raising the language version to 3.10 switches dart format to the current style and enables the super-parameter and null-aware-element lints. Apply dart format, dart fix and regenerate the generated sources so analyze, the format check and the generated-code check pass. No behavior change. --- example/lib/main.dart | 143 ++- lib/attribution/attribution_context.dart | 24 +- lib/attribution/attribution_manager.dart | 12 +- lib/attribution/install_referrer.dart | 6 +- lib/deeplink/deeplink_handler.dart | 4 +- lib/errors/link_forty_error.dart | 28 +- lib/events/event_queue.dart | 3 +- lib/events/event_tracker.dart | 11 +- lib/fingerprint/fingerprint_collector.dart | 4 +- lib/models/create_link_options.g.dart | 9 +- .../dashboard_create_link_response.g.dart | 17 +- lib/models/deep_link_data.g.dart | 40 +- lib/models/event_request.g.dart | 29 +- lib/network/http_client.dart | 5 +- lib/network/network_manager.dart | 4 +- .../attribution/attribution_manager_test.dart | 15 +- .../attribution_manager_test.mocks.dart | 226 ++-- test/attribution/install_referrer_test.dart | 30 +- test/deeplink/deeplink_handler_test.dart | 62 +- .../deeplink/deeplink_handler_test.mocks.dart | 115 +-- test/events/event_server_contract_test.dart | 92 +- test/events/event_tracker_test.dart | 100 +- test/events/event_tracker_test.mocks.dart | 248 ++--- .../fingerprint_collector_test.dart | 55 +- .../fingerprint_collector_test.mocks.dart | 970 +++++++++--------- test/link_forty_test.dart | 201 ++-- test/link_forty_test.mocks.dart | 226 ++-- test/models/deep_link_data_test.dart | 43 +- test/models/install_response_test.dart | 18 +- test/network/network_manager_test.mocks.dart | 45 +- test/storage/storage_manager_test.dart | 45 +- test/storage/storage_manager_test.mocks.dart | 62 +- 32 files changed, 1413 insertions(+), 1479 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 352f709..cfd2534 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -7,16 +7,13 @@ void main() { } class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'LinkForty Example', - theme: ThemeData( - primarySwatch: Colors.blue, - useMaterial3: true, - ), + theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true), // Auto-reports a `screen_view` (stamped with last-click attribution) for // every named route. Give your routes names to have them tracked. navigatorObservers: [LinkFortyNavigatorObserver()], @@ -26,7 +23,7 @@ class MyApp extends StatelessWidget { } class LinkFortyDemo extends StatefulWidget { - const LinkFortyDemo({Key? key}) : super(key: key); + const LinkFortyDemo({super.key}); @override State createState() => _LinkFortyDemoState(); @@ -108,13 +105,10 @@ class _LinkFortyDemoState extends State { Future _trackEvent(String name) async { try { - await LinkForty.instance.trackEvent( - name, - { - 'timestamp': DateTime.now().millisecondsSinceEpoch / 1000, - 'source': 'example_app', - }, - ); + await LinkForty.instance.trackEvent(name, { + 'timestamp': DateTime.now().millisecondsSinceEpoch / 1000, + 'source': 'example_app', + }); if (!mounted) return; setState(() { @@ -157,10 +151,7 @@ class _LinkFortyDemoState extends State { await LinkForty.instance.trackRevenue( amount: amount, currency: currency, - properties: { - 'product': 'example_product', - 'quantity': 1, - }, + properties: {'product': 'example_product', 'quantity': 1}, ); if (!mounted) return; @@ -232,9 +223,7 @@ class _LinkFortyDemoState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text('LinkForty Example'), - ), + appBar: AppBar(title: const Text('LinkForty Example')), body: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( @@ -297,11 +286,7 @@ class _SectionContainer extends StatelessWidget { final String title; final Widget child; - const _SectionContainer({ - Key? key, - required this.title, - required this.child, - }) : super(key: key); + const _SectionContainer({required this.title, required this.child}); @override Widget build(BuildContext context) { @@ -315,9 +300,10 @@ class _SectionContainer extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, - style: - const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Text( + title, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), const SizedBox(height: 10), child, ], @@ -332,11 +318,10 @@ class _StatusSection extends StatelessWidget { final int queuedEvents; const _StatusSection({ - Key? key, required this.isInitialized, required this.eventCount, required this.queuedEvents, - }) : super(key: key); + }); @override Widget build(BuildContext context) { @@ -353,13 +338,17 @@ class _StatusSection extends StatelessWidget { ), _RowItem( label: 'Events Tracked:', - value: Text('$eventCount', - style: const TextStyle(fontWeight: FontWeight.bold)), + value: Text( + '$eventCount', + style: const TextStyle(fontWeight: FontWeight.bold), + ), ), _RowItem( label: 'Queued Events:', - value: Text('$queuedEvents', - style: const TextStyle(fontWeight: FontWeight.bold)), + value: Text( + '$queuedEvents', + style: const TextStyle(fontWeight: FontWeight.bold), + ), ), ], ), @@ -371,11 +360,7 @@ class _AttributionSection extends StatelessWidget { final String? installId; final bool isAttributed; - const _AttributionSection({ - Key? key, - this.installId, - required this.isAttributed, - }) : super(key: key); + const _AttributionSection({this.installId, required this.isAttributed}); @override Widget build(BuildContext context) { @@ -414,12 +399,11 @@ class _EventsSection extends StatelessWidget { final VoidCallback onFlushEvents; const _EventsSection({ - Key? key, required this.onTrackEvent, required this.onTrackScreenView, required this.onTrackRevenue, required this.onFlushEvents, - }) : super(key: key); + }); @override Widget build(BuildContext context) { @@ -473,11 +457,10 @@ class _LinkCreationSection extends StatelessWidget { final String? createdLinkShortCode; const _LinkCreationSection({ - Key? key, required this.onCreateLink, this.createdLinkURL, this.createdLinkShortCode, - }) : super(key: key); + }); @override Widget build(BuildContext context) { @@ -495,8 +478,10 @@ class _LinkCreationSection extends StatelessWidget { const SizedBox(height: 10), Text('URL: $createdLinkURL', style: const TextStyle(fontSize: 12)), if (createdLinkShortCode != null) - Text('Short Code: $createdLinkShortCode', - style: const TextStyle(fontSize: 12)), + Text( + 'Short Code: $createdLinkShortCode', + style: const TextStyle(fontSize: 12), + ), ], ], ), @@ -507,18 +492,17 @@ class _LinkCreationSection extends StatelessWidget { class _DeepLinkSection extends StatelessWidget { final DeepLinkData? deepLinkData; - const _DeepLinkSection({ - Key? key, - this.deepLinkData, - }) : super(key: key); + const _DeepLinkSection({this.deepLinkData}); @override Widget build(BuildContext context) { return _SectionContainer( title: 'Deep Link Data', child: deepLinkData == null - ? const Text('No deep link data', - style: TextStyle(color: Colors.grey, fontSize: 12)) + ? const Text( + 'No deep link data', + style: TextStyle(color: Colors.grey, fontSize: 12), + ) : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -527,31 +511,38 @@ class _DeepLinkSection extends StatelessWidget { _TextItem(label: 'iOS URL', value: deepLinkData!.iosURL), if (deepLinkData!.deepLinkPath != null) _TextItem( - label: 'Deep Link Path', - value: deepLinkData!.deepLinkPath), + label: 'Deep Link Path', + value: deepLinkData!.deepLinkPath, + ), if (deepLinkData!.appScheme != null) _TextItem( - label: 'App Scheme', value: deepLinkData!.appScheme), + label: 'App Scheme', + value: deepLinkData!.appScheme, + ), if (deepLinkData!.linkId != null) _TextItem( - label: 'Link ID', - value: deepLinkData!.linkId, - color: Colors.grey), + label: 'Link ID', + value: deepLinkData!.linkId, + color: Colors.grey, + ), if (deepLinkData!.utmParameters != null) ...[ if (deepLinkData!.utmParameters!.source != null) _TextItem( - label: 'UTM Source', - value: deepLinkData!.utmParameters!.source), + label: 'UTM Source', + value: deepLinkData!.utmParameters!.source, + ), if (deepLinkData!.utmParameters!.campaign != null) _TextItem( - label: 'UTM Campaign', - value: deepLinkData!.utmParameters!.campaign), + label: 'UTM Campaign', + value: deepLinkData!.utmParameters!.campaign, + ), ], if (deepLinkData!.customParameters != null && deepLinkData!.customParameters!.isNotEmpty) _TextItem( - label: 'Custom Params', - value: '${deepLinkData!.customParameters!.length}'), + label: 'Custom Params', + value: '${deepLinkData!.customParameters!.length}', + ), ], ), ); @@ -561,10 +552,7 @@ class _DeepLinkSection extends StatelessWidget { class _DataManagementSection extends StatelessWidget { final VoidCallback onClearData; - const _DataManagementSection({ - Key? key, - required this.onClearData, - }) : super(key: key); + const _DataManagementSection({required this.onClearData}); @override Widget build(BuildContext context) { @@ -584,11 +572,7 @@ class _RowItem extends StatelessWidget { final String label; final Widget value; - const _RowItem({ - Key? key, - required this.label, - required this.value, - }) : super(key: key); + const _RowItem({required this.label, required this.value}); @override Widget build(BuildContext context) { @@ -596,10 +580,7 @@ class _RowItem extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 4.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(label), - value, - ], + children: [Text(label), value], ), ); } @@ -610,12 +591,7 @@ class _TextItem extends StatelessWidget { final String? value; final Color? color; - const _TextItem({ - Key? key, - required this.label, - this.value, - this.color, - }) : super(key: key); + const _TextItem({required this.label, this.value, this.color}); @override Widget build(BuildContext context) { @@ -636,12 +612,11 @@ class _FullWidthButton extends StatelessWidget { final Color color; const _FullWidthButton({ - Key? key, required this.onPressed, required this.icon, required this.label, required this.color, - }) : super(key: key); + }); @override Widget build(BuildContext context) { diff --git a/lib/attribution/attribution_context.dart b/lib/attribution/attribution_context.dart index 4f349e9..3e3d320 100644 --- a/lib/attribution/attribution_context.dart +++ b/lib/attribution/attribution_context.dart @@ -24,10 +24,10 @@ class ActiveAttribution { }); Map toJson() => { - 'linkId': linkId, - if (clickId != null) 'clickId': clickId, - 'openedAt': openedAt, - }; + 'linkId': linkId, + if (clickId != null) 'clickId': clickId, + 'openedAt': openedAt, + }; factory ActiveAttribution.fromJson(Map json) => ActiveAttribution( @@ -80,9 +80,9 @@ class AttributionContext { AttributionContext({ required StorageManagerProtocol storage, bool debug = false, - }) : _storage = storage, - _debug = debug, - _sessionId = _generateSessionId() { + }) : _storage = storage, + _debug = debug, + _sessionId = _generateSessionId() { _active = _loadActive(); } @@ -116,11 +116,11 @@ class AttributionContext { /// The attribution fields to merge into every event payload. AttributionStamp getStamp() => AttributionStamp( - attributedLinkId: _active?.linkId, - attributedClickId: _active?.clickId, - linkOpenedAt: _active?.openedAt, - sessionId: _sessionId, - ); + attributedLinkId: _active?.linkId, + attributedClickId: _active?.clickId, + linkOpenedAt: _active?.openedAt, + sessionId: _sessionId, + ); /// The current session id (one app-open journey). String get sessionId => _sessionId; diff --git a/lib/attribution/attribution_manager.dart b/lib/attribution/attribution_manager.dart index 7187a51..0446a87 100644 --- a/lib/attribution/attribution_manager.dart +++ b/lib/attribution/attribution_manager.dart @@ -34,10 +34,10 @@ class AttributionManager { required StorageManagerProtocol storageManager, required FingerprintCollectorProtocol fingerprintCollector, InstallReferrerReader? readInstallReferrer, - }) : _networkManager = networkManager, - _storageManager = storageManager, - _fingerprintCollector = fingerprintCollector, - _readInstallReferrer = readInstallReferrer; + }) : _networkManager = networkManager, + _storageManager = storageManager, + _fingerprintCollector = fingerprintCollector, + _readInstallReferrer = readInstallReferrer; // MARK: - Install Attribution @@ -93,8 +93,8 @@ class AttributionManager { // to the correct workspace rather than relying solely on fingerprint matching. final body = { ...fingerprint.toJson(), - if (appToken != null) 'appToken': appToken, - if (installReferrer != null) 'installReferrer': installReferrer, + 'appToken': ?appToken, + 'installReferrer': ?installReferrer, }; LinkFortyLogger.log( diff --git a/lib/attribution/install_referrer.dart b/lib/attribution/install_referrer.dart index 8f4aecf..dc59bd8 100644 --- a/lib/attribution/install_referrer.dart +++ b/lib/attribution/install_referrer.dart @@ -37,10 +37,12 @@ class PlayInstallReferrer { bool? isAndroid, Duration timeout = defaultTimeout, }) async { - final android = isAndroid ?? + final android = + isAndroid ?? (!kIsWeb && defaultTargetPlatform == TargetPlatform.android); if (!android) return null; - final ask = query ?? + final ask = + query ?? () async => (await AndroidPlayInstallReferrer.installReferrer).installReferrer; diff --git a/lib/deeplink/deeplink_handler.dart b/lib/deeplink/deeplink_handler.dart index 243bc54..b79462f 100644 --- a/lib/deeplink/deeplink_handler.dart +++ b/lib/deeplink/deeplink_handler.dart @@ -193,8 +193,8 @@ class DeepLinkHandler { final resolvedData = (_networkManager != null && _fingerprintCollector != null) - ? await _resolveUrl(uri, fallback: localData) - : localData; + ? await _resolveUrl(uri, fallback: localData) + : localData; final callbacks = List.from(_deepLinkCallbacks); diff --git a/lib/errors/link_forty_error.dart b/lib/errors/link_forty_error.dart index 5e07faa..c5c50c7 100644 --- a/lib/errors/link_forty_error.dart +++ b/lib/errors/link_forty_error.dart @@ -18,7 +18,7 @@ abstract class LinkFortyError implements Exception { /// Call `LinkForty.instance.initialize(config:)` before using other SDK methods class NotInitializedError extends LinkFortyError { const NotInitializedError() - : super('LinkForty SDK is not initialized. Call initialize() first.'); + : super('LinkForty SDK is not initialized. Call initialize() first.'); } /// The SDK has already been initialized @@ -26,19 +26,19 @@ class NotInitializedError extends LinkFortyError { /// `initialize(config:)` can only be called once class AlreadyInitializedError extends LinkFortyError { const AlreadyInitializedError() - : super('LinkForty SDK has already been initialized.'); + : super('LinkForty SDK has already been initialized.'); } /// The configuration is invalid class InvalidConfigurationError extends LinkFortyError { InvalidConfigurationError(String detail) - : super('Invalid configuration: $detail'); + : super('Invalid configuration: $detail'); } /// A network error occurred class NetworkError extends LinkFortyError { NetworkError(Object cause) - : super('Network error: ${_extractMessage(cause)}', cause); + : super('Network error: ${_extractMessage(cause)}', cause); static String _extractMessage(Object error) { if (error is Exception) { @@ -54,7 +54,7 @@ class InvalidResponseError extends LinkFortyError { final String? responseMessage; InvalidResponseError({this.statusCode, this.responseMessage}) - : super(_buildMessage(statusCode, responseMessage)); + : super(_buildMessage(statusCode, responseMessage)); static String _buildMessage(int? statusCode, String? responseMessage) { final buffer = StringBuffer('Invalid server response'); @@ -71,7 +71,7 @@ class InvalidResponseError extends LinkFortyError { /// Failed to decode the response class DecodingError extends LinkFortyError { DecodingError(Object cause) - : super('Failed to decode response: ${_extractMessage(cause)}', cause); + : super('Failed to decode response: ${_extractMessage(cause)}', cause); static String _extractMessage(Object error) { if (error is Exception) { @@ -84,7 +84,7 @@ class DecodingError extends LinkFortyError { /// Failed to encode the request class EncodingError extends LinkFortyError { EncodingError(Object cause) - : super('Failed to encode request: ${_extractMessage(cause)}', cause); + : super('Failed to encode request: ${_extractMessage(cause)}', cause); static String _extractMessage(Object error) { if (error is Exception) { @@ -102,21 +102,21 @@ class InvalidEventDataError extends LinkFortyError { /// Invalid deep link URL class InvalidDeepLinkUrlError extends LinkFortyError { InvalidDeepLinkUrlError(String detail) - : super('Invalid deep link URL: $detail'); + : super('Invalid deep link URL: $detail'); } /// API key is required for this operation class MissingApiKeyError extends LinkFortyError { const MissingApiKeyError() - : super( - 'API key is required for this operation. Provide an apiKey in LinkFortyConfig.', - ); + : super( + 'API key is required for this operation. Provide an apiKey in LinkFortyConfig.', + ); } /// Template ID is required for link creation class MissingTemplateIdError extends LinkFortyError { const MissingTemplateIdError() - : super( - 'A template ID is required for link creation. Provide a templateId in CreateLinkOptions.', - ); + : super( + 'A template ID is required for link creation. Provide a templateId in CreateLinkOptions.', + ); } diff --git a/lib/events/event_queue.dart b/lib/events/event_queue.dart index 2c14bd4..a8f40a0 100644 --- a/lib/events/event_queue.dart +++ b/lib/events/event_queue.dart @@ -53,7 +53,8 @@ class EventQueue { while (_queue.length > _maxQueueSize) { final dropped = _queue.removeLast(); LinkFortyLogger.log( - 'Event queue full, dropping event: ${dropped.eventName}'); + 'Event queue full, dropping event: ${dropped.eventName}', + ); } } diff --git a/lib/events/event_tracker.dart b/lib/events/event_tracker.dart index 7ccd132..47eb45e 100644 --- a/lib/events/event_tracker.dart +++ b/lib/events/event_tracker.dart @@ -39,10 +39,10 @@ class EventTracker implements EventTrackerProtocol { required StorageManagerProtocol storageManager, required AttributionContext attributionContext, EventQueue? eventQueue, - }) : _networkManager = networkManager, - _storageManager = storageManager, - _attributionContext = attributionContext, - _eventQueue = eventQueue ?? EventQueue() { + }) : _networkManager = networkManager, + _storageManager = storageManager, + _attributionContext = attributionContext, + _eventQueue = eventQueue ?? EventQueue() { // Restore any events that were persisted before the last app session _restorePersistedQueue(); } @@ -180,7 +180,8 @@ class EventTracker implements EventTrackerProtocol { _eventQueue.requeueFront([event]); await _persistQueue(); LinkFortyLogger.log( - 'Failed to send queued event, keeping it queued: $e'); + 'Failed to send queued event, keeping it queued: $e', + ); return; } await _persistQueue(); diff --git a/lib/fingerprint/fingerprint_collector.dart b/lib/fingerprint/fingerprint_collector.dart index 3c296df..b366935 100644 --- a/lib/fingerprint/fingerprint_collector.dart +++ b/lib/fingerprint/fingerprint_collector.dart @@ -42,8 +42,8 @@ class FingerprintCollector implements FingerprintCollectorProtocol { /// - [deviceInfo]: Device info plugin instance /// - [packageInfo]: Package info (if already loaded) FingerprintCollector({DeviceInfoPlugin? deviceInfo, PackageInfo? packageInfo}) - : _deviceInfo = deviceInfo ?? DeviceInfoPlugin(), - _packageInfo = packageInfo; + : _deviceInfo = deviceInfo ?? DeviceInfoPlugin(), + _packageInfo = packageInfo; /// Collects a [DeviceFingerprint] containing properties like screen size, /// timezone, language, and platform version. diff --git a/lib/models/create_link_options.g.dart b/lib/models/create_link_options.g.dart index d873b9a..d234840 100644 --- a/lib/models/create_link_options.g.dart +++ b/lib/models/create_link_options.g.dart @@ -10,17 +10,16 @@ CreateLinkOptions _$CreateLinkOptionsFromJson(Map json) => CreateLinkOptions( templateId: json['templateId'] as String?, templateSlug: json['templateSlug'] as String?, - deepLinkParameters: - (json['deepLinkParameters'] as Map?)?.map( - (k, e) => MapEntry(k, e as String), - ), + deepLinkParameters: (json['deepLinkParameters'] as Map?) + ?.map((k, e) => MapEntry(k, e as String)), title: json['title'] as String?, description: json['description'] as String?, customCode: json['customCode'] as String?, utmParameters: json['utmParameters'] == null ? null : UTMParameters.fromJson( - json['utmParameters'] as Map), + json['utmParameters'] as Map, + ), externalUserId: json['externalUserId'] as String?, ); diff --git a/lib/models/dashboard_create_link_response.g.dart b/lib/models/dashboard_create_link_response.g.dart index 4503775..8c99720 100644 --- a/lib/models/dashboard_create_link_response.g.dart +++ b/lib/models/dashboard_create_link_response.g.dart @@ -7,15 +7,12 @@ part of 'dashboard_create_link_response.dart'; // ************************************************************************** DashboardCreateLinkResponse _$DashboardCreateLinkResponseFromJson( - Map json) => - DashboardCreateLinkResponse( - id: json['id'] as String, - shortCode: json['shortCode'] as String, - ); + Map json, +) => DashboardCreateLinkResponse( + id: json['id'] as String, + shortCode: json['shortCode'] as String, +); Map _$DashboardCreateLinkResponseToJson( - DashboardCreateLinkResponse instance) => - { - 'id': instance.id, - 'shortCode': instance.shortCode, - }; + DashboardCreateLinkResponse instance, +) => {'id': instance.id, 'shortCode': instance.shortCode}; diff --git a/lib/models/deep_link_data.g.dart b/lib/models/deep_link_data.g.dart index 8096cf5..6b9f1ec 100644 --- a/lib/models/deep_link_data.g.dart +++ b/lib/models/deep_link_data.g.dart @@ -7,27 +7,25 @@ part of 'deep_link_data.dart'; // ************************************************************************** DeepLinkData _$DeepLinkDataFromJson(Map json) => DeepLinkData( - shortCode: json['shortCode'] as String, - iosURL: json['iosUrl'] as String?, - androidURL: json['androidUrl'] as String?, - webURL: json['webUrl'] as String?, - utmParameters: json['utmParameters'] == null - ? null - : UTMParameters.fromJson( - json['utmParameters'] as Map), - customParameters: - (json['customParameters'] as Map?)?.map( - (k, e) => MapEntry(k, e as String), - ), - deepLinkPath: json['deepLinkPath'] as String?, - appScheme: json['appScheme'] as String?, - clickedAt: DeepLinkData._dateTimeFromJson(json['clickedAt'] as String?), - linkId: json['linkId'] as String?, - confidenceScore: doubleFromJsonOrNull(json['confidenceScore']), - matchedFactors: stringListFromJsonOrNull(json['matchedFactors']), - attributionMethod: stringFromJsonOrNull(json['attributionMethod']), - competingLinks: intFromJsonOrNull(json['competingLinks']), - ); + shortCode: json['shortCode'] as String, + iosURL: json['iosUrl'] as String?, + androidURL: json['androidUrl'] as String?, + webURL: json['webUrl'] as String?, + utmParameters: json['utmParameters'] == null + ? null + : UTMParameters.fromJson(json['utmParameters'] as Map), + customParameters: (json['customParameters'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ), + deepLinkPath: json['deepLinkPath'] as String?, + appScheme: json['appScheme'] as String?, + clickedAt: DeepLinkData._dateTimeFromJson(json['clickedAt'] as String?), + linkId: json['linkId'] as String?, + confidenceScore: doubleFromJsonOrNull(json['confidenceScore']), + matchedFactors: stringListFromJsonOrNull(json['matchedFactors']), + attributionMethod: stringFromJsonOrNull(json['attributionMethod']), + competingLinks: intFromJsonOrNull(json['competingLinks']), +); Map _$DeepLinkDataToJson(DeepLinkData instance) => { diff --git a/lib/models/event_request.g.dart b/lib/models/event_request.g.dart index 4ba4dad..842174e 100644 --- a/lib/models/event_request.g.dart +++ b/lib/models/event_request.g.dart @@ -7,20 +7,21 @@ part of 'event_request.dart'; // ************************************************************************** EventRequest _$EventRequestFromJson(Map json) => EventRequest( - installId: json['installId'] as String, - eventName: json['eventName'] as String, - eventData: EventRequest._eventDataFromJson( - json['eventData'] as Map), - timestamp: json['timestamp'] == null - ? null - : DateTime.parse(json['timestamp'] as String), - sdkName: json['sdkName'] as String? ?? SdkInfo.name, - sdkVersion: json['sdkVersion'] as String? ?? SdkInfo.version, - attributedLinkId: json['attributedLinkId'] as String?, - attributedClickId: json['attributedClickId'] as String?, - linkOpenedAt: json['linkOpenedAt'] as String?, - sessionId: json['sessionId'] as String?, - ); + installId: json['installId'] as String, + eventName: json['eventName'] as String, + eventData: EventRequest._eventDataFromJson( + json['eventData'] as Map, + ), + timestamp: json['timestamp'] == null + ? null + : DateTime.parse(json['timestamp'] as String), + sdkName: json['sdkName'] as String? ?? SdkInfo.name, + sdkVersion: json['sdkVersion'] as String? ?? SdkInfo.version, + attributedLinkId: json['attributedLinkId'] as String?, + attributedClickId: json['attributedClickId'] as String?, + linkOpenedAt: json['linkOpenedAt'] as String?, + sessionId: json['sessionId'] as String?, +); Map _$EventRequestToJson(EventRequest instance) => { diff --git a/lib/network/http_client.dart b/lib/network/http_client.dart index a1648f9..7564a99 100644 --- a/lib/network/http_client.dart +++ b/lib/network/http_client.dart @@ -43,8 +43,9 @@ class HttpClientImpl implements HttpClient { try { switch (method) { case HttpMethod.get: - response = - await _client.get(uri, headers: requestHeaders).timeout(timeout); + response = await _client + .get(uri, headers: requestHeaders) + .timeout(timeout); break; case HttpMethod.post: response = await _client diff --git a/lib/network/network_manager.dart b/lib/network/network_manager.dart index 445f260..46435f5 100644 --- a/lib/network/network_manager.dart +++ b/lib/network/network_manager.dart @@ -39,8 +39,8 @@ class NetworkManager implements NetworkManagerProtocol { static const int _maxRetries = 3; NetworkManager({required LinkFortyConfig config, HttpClient? httpClient}) - : _config = config, - _httpClient = httpClient ?? HttpClientImpl(); + : _config = config, + _httpClient = httpClient ?? HttpClientImpl(); /// Performs an asynchronous network request and decodes the JSON response. /// diff --git a/test/attribution/attribution_manager_test.dart b/test/attribution/attribution_manager_test.dart index 0662592..7026659 100644 --- a/test/attribution/attribution_manager_test.dart +++ b/test/attribution/attribution_manager_test.dart @@ -307,13 +307,14 @@ void main() { Map sentBody() { return verify( - mockNetworkManager.request( - endpoint: '/api/sdk/v1/install', - method: HttpMethod.post, - body: captureAnyNamed('body'), - fromJson: anyNamed('fromJson'), - ), - ).captured.single as Map; + mockNetworkManager.request( + endpoint: '/api/sdk/v1/install', + method: HttpMethod.post, + body: captureAnyNamed('body'), + fromJson: anyNamed('fromJson'), + ), + ).captured.single + as Map; } test('is sent with the fingerprint', () async { diff --git a/test/attribution/attribution_manager_test.mocks.dart b/test/attribution/attribution_manager_test.mocks.dart index ecafd3f..01e940d 100644 --- a/test/attribution/attribution_manager_test.mocks.dart +++ b/test/attribution/attribution_manager_test.mocks.dart @@ -3,6 +3,7 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes + import 'dart:async' as _i2; import 'package:linkforty_flutter/fingerprint/device_fingerprint.dart' as _i3; @@ -32,24 +33,14 @@ import 'package:mockito/src/dummies.dart' as _i6; // ignore_for_file: invalid_use_of_internal_member class _FakeFuture_0 extends _i1.SmartFake implements _i2.Future { - _FakeFuture_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeFuture_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeDeviceFingerprint_1 extends _i1.SmartFake implements _i3.DeviceFingerprint { - _FakeDeviceFingerprint_1( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeDeviceFingerprint_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } /// A class which mocks [NetworkManagerProtocol]. @@ -70,49 +61,39 @@ class MockNetworkManagerProtocol extends _i1.Mock required T Function(Map)? fromJson, }) => (super.noSuchMethod( - Invocation.method( - #request, - [], - { - #endpoint: endpoint, - #method: method, - #body: body, - #headers: headers, - #fromJson: fromJson, - }, - ), - returnValue: _i6.ifNotNull( - _i6.dummyValueOrNull( - this, - Invocation.method( - #request, - [], - { + Invocation.method(#request, [], { + #endpoint: endpoint, + #method: method, + #body: body, + #headers: headers, + #fromJson: fromJson, + }), + returnValue: + _i6.ifNotNull( + _i6.dummyValueOrNull( + this, + Invocation.method(#request, [], { + #endpoint: endpoint, + #method: method, + #body: body, + #headers: headers, + #fromJson: fromJson, + }), + ), + (T v) => _i2.Future.value(v), + ) ?? + _FakeFuture_0( + this, + Invocation.method(#request, [], { #endpoint: endpoint, #method: method, #body: body, #headers: headers, #fromJson: fromJson, - }, + }), ), - ), - (T v) => _i2.Future.value(v), - ) ?? - _FakeFuture_0( - this, - Invocation.method( - #request, - [], - { - #endpoint: endpoint, - #method: method, - #body: body, - #headers: headers, - #fromJson: fromJson, - }, - ), - ), - ) as _i2.Future); + ) + as _i2.Future); } /// A class which mocks [StorageManagerProtocol]. @@ -125,87 +106,76 @@ class MockStorageManagerProtocol extends _i1.Mock } @override - _i2.Future saveInstallId(String? installId) => (super.noSuchMethod( - Invocation.method( - #saveInstallId, - [installId], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future saveInstallId(String? installId) => + (super.noSuchMethod( + Invocation.method(#saveInstallId, [installId]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override _i2.Future saveInstallData(_i8.DeepLinkData? data) => (super.noSuchMethod( - Invocation.method( - #saveInstallData, - [data], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + Invocation.method(#saveInstallData, [data]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - bool isFirstLaunch() => (super.noSuchMethod( - Invocation.method( - #isFirstLaunch, - [], - ), - returnValue: false, - ) as bool); + bool isFirstLaunch() => + (super.noSuchMethod( + Invocation.method(#isFirstLaunch, []), + returnValue: false, + ) + as bool); @override - _i2.Future setHasLaunched() => (super.noSuchMethod( - Invocation.method( - #setHasLaunched, - [], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future setHasLaunched() => + (super.noSuchMethod( + Invocation.method(#setHasLaunched, []), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override _i2.Future saveEventQueue(List<_i9.EventRequest>? events) => (super.noSuchMethod( - Invocation.method( - #saveEventQueue, - [events], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + Invocation.method(#saveEventQueue, [events]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - List<_i9.EventRequest> loadEventQueue() => (super.noSuchMethod( - Invocation.method( - #loadEventQueue, - [], - ), - returnValue: <_i9.EventRequest>[], - ) as List<_i9.EventRequest>); + List<_i9.EventRequest> loadEventQueue() => + (super.noSuchMethod( + Invocation.method(#loadEventQueue, []), + returnValue: <_i9.EventRequest>[], + ) + as List<_i9.EventRequest>); @override - _i2.Future saveAttribution(String? json) => (super.noSuchMethod( - Invocation.method( - #saveAttribution, - [json], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future saveAttribution(String? json) => + (super.noSuchMethod( + Invocation.method(#saveAttribution, [json]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - _i2.Future removeAttribution() => (super.noSuchMethod( - Invocation.method( - #removeAttribution, - [], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future removeAttribution() => + (super.noSuchMethod( + Invocation.method(#removeAttribution, []), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - _i2.Future clearAll() => (super.noSuchMethod( - Invocation.method( - #clearAll, - [], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future clearAll() => + (super.noSuchMethod( + Invocation.method(#clearAll, []), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); } /// A class which mocks [FingerprintCollectorProtocol]. @@ -223,25 +193,19 @@ class MockFingerprintCollectorProtocol extends _i1.Mock String? deviceId, }) => (super.noSuchMethod( - Invocation.method( - #collectFingerprint, - [], - { - #attributionWindowHours: attributionWindowHours, - #deviceId: deviceId, - }, - ), - returnValue: - _i2.Future<_i3.DeviceFingerprint>.value(_FakeDeviceFingerprint_1( - this, - Invocation.method( - #collectFingerprint, - [], - { + Invocation.method(#collectFingerprint, [], { #attributionWindowHours: attributionWindowHours, #deviceId: deviceId, - }, - ), - )), - ) as _i2.Future<_i3.DeviceFingerprint>); + }), + returnValue: _i2.Future<_i3.DeviceFingerprint>.value( + _FakeDeviceFingerprint_1( + this, + Invocation.method(#collectFingerprint, [], { + #attributionWindowHours: attributionWindowHours, + #deviceId: deviceId, + }), + ), + ), + ) + as _i2.Future<_i3.DeviceFingerprint>); } diff --git a/test/attribution/install_referrer_test.dart b/test/attribution/install_referrer_test.dart index df9d879..d868673 100644 --- a/test/attribution/install_referrer_test.dart +++ b/test/attribution/install_referrer_test.dart @@ -22,20 +22,26 @@ void main() { test('returns the referrer Play recorded', () async { expect( - await PlayInstallReferrer.read( - isAndroid: true, query: () async => referrer), - referrer); + await PlayInstallReferrer.read( + isAndroid: true, + query: () async => referrer, + ), + referrer, + ); }); test('returns null for an empty referrer', () async { expect( - await PlayInstallReferrer.read( - isAndroid: true, query: () async => ' '), - isNull); + await PlayInstallReferrer.read(isAndroid: true, query: () async => ' '), + isNull, + ); expect( - await PlayInstallReferrer.read( - isAndroid: true, query: () async => null), - isNull); + await PlayInstallReferrer.read( + isAndroid: true, + query: () async => null, + ), + isNull, + ); }); test('asks once more after a failed read', () async { @@ -87,8 +93,10 @@ void main() { Future.delayed(const Duration(seconds: 5), () => referrer), ); expect(value, isNull); - expect(DateTime.now().difference(started), - lessThan(const Duration(seconds: 1))); + expect( + DateTime.now().difference(started), + lessThan(const Duration(seconds: 1)), + ); }); }); } diff --git a/test/deeplink/deeplink_handler_test.dart b/test/deeplink/deeplink_handler_test.dart index 69b83e8..4c035a6 100644 --- a/test/deeplink/deeplink_handler_test.dart +++ b/test/deeplink/deeplink_handler_test.dart @@ -49,38 +49,42 @@ void main() { expect(deliveredData, data); }); - test('holds a link that arrives before any callback, and delivers it once', - () async { - final uri = Uri.parse('https://example.com/abc'); - await handler.handleDeepLink(uri); - - final first = []; - final second = []; - final late = []; - handler.onDeepLink((u, _) => first.add(u)); - handler.onDeepLink((u, _) => second.add(u)); - await Future.delayed(Duration.zero); - handler.onDeepLink((u, _) => late.add(u)); - await Future.delayed(Duration.zero); - - expect(first, [uri]); - expect(second, [uri]); - expect(late, isEmpty); - }); + test( + 'holds a link that arrives before any callback, and delivers it once', + () async { + final uri = Uri.parse('https://example.com/abc'); + await handler.handleDeepLink(uri); + + final first = []; + final second = []; + final late = []; + handler.onDeepLink((u, _) => first.add(u)); + handler.onDeepLink((u, _) => second.add(u)); + await Future.delayed(Duration.zero); + handler.onDeepLink((u, _) => late.add(u)); + await Future.delayed(Duration.zero); + + expect(first, [uri]); + expect(second, [uri]); + expect(late, isEmpty); + }, + ); - test('ignores the same URL handled again within the duplicate window', - () async { - final uri = Uri.parse('https://example.com/abc'); - final other = Uri.parse('https://example.com/def'); - final delivered = []; - handler.onDeepLink((u, _) => delivered.add(u)); + test( + 'ignores the same URL handled again within the duplicate window', + () async { + final uri = Uri.parse('https://example.com/abc'); + final other = Uri.parse('https://example.com/def'); + final delivered = []; + handler.onDeepLink((u, _) => delivered.add(u)); - await handler.handleDeepLink(uri); - await handler.handleDeepLink(uri); - await handler.handleDeepLink(other); + await handler.handleDeepLink(uri); + await handler.handleDeepLink(uri); + await handler.handleDeepLink(other); - expect(delivered, [uri, other]); - }); + expect(delivered, [uri, other]); + }, + ); test('handleDeepLink parses local URL correctly', () async { final uri = Uri.parse('https://example.com/abc'); diff --git a/test/deeplink/deeplink_handler_test.mocks.dart b/test/deeplink/deeplink_handler_test.mocks.dart index 7f2f984..c94bc9d 100644 --- a/test/deeplink/deeplink_handler_test.mocks.dart +++ b/test/deeplink/deeplink_handler_test.mocks.dart @@ -3,6 +3,7 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes + import 'dart:async' as _i2; import 'package:linkforty_flutter/fingerprint/device_fingerprint.dart' as _i3; @@ -29,24 +30,14 @@ import 'package:mockito/src/dummies.dart' as _i6; // ignore_for_file: invalid_use_of_internal_member class _FakeFuture_0 extends _i1.SmartFake implements _i2.Future { - _FakeFuture_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeFuture_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeDeviceFingerprint_1 extends _i1.SmartFake implements _i3.DeviceFingerprint { - _FakeDeviceFingerprint_1( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeDeviceFingerprint_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } /// A class which mocks [NetworkManagerProtocol]. @@ -67,49 +58,39 @@ class MockNetworkManagerProtocol extends _i1.Mock required T Function(Map)? fromJson, }) => (super.noSuchMethod( - Invocation.method( - #request, - [], - { - #endpoint: endpoint, - #method: method, - #body: body, - #headers: headers, - #fromJson: fromJson, - }, - ), - returnValue: _i6.ifNotNull( - _i6.dummyValueOrNull( - this, - Invocation.method( - #request, - [], - { + Invocation.method(#request, [], { + #endpoint: endpoint, + #method: method, + #body: body, + #headers: headers, + #fromJson: fromJson, + }), + returnValue: + _i6.ifNotNull( + _i6.dummyValueOrNull( + this, + Invocation.method(#request, [], { + #endpoint: endpoint, + #method: method, + #body: body, + #headers: headers, + #fromJson: fromJson, + }), + ), + (T v) => _i2.Future.value(v), + ) ?? + _FakeFuture_0( + this, + Invocation.method(#request, [], { #endpoint: endpoint, #method: method, #body: body, #headers: headers, #fromJson: fromJson, - }, + }), ), - ), - (T v) => _i2.Future.value(v), - ) ?? - _FakeFuture_0( - this, - Invocation.method( - #request, - [], - { - #endpoint: endpoint, - #method: method, - #body: body, - #headers: headers, - #fromJson: fromJson, - }, - ), - ), - ) as _i2.Future); + ) + as _i2.Future); } /// A class which mocks [FingerprintCollectorProtocol]. @@ -127,25 +108,19 @@ class MockFingerprintCollectorProtocol extends _i1.Mock String? deviceId, }) => (super.noSuchMethod( - Invocation.method( - #collectFingerprint, - [], - { - #attributionWindowHours: attributionWindowHours, - #deviceId: deviceId, - }, - ), - returnValue: - _i2.Future<_i3.DeviceFingerprint>.value(_FakeDeviceFingerprint_1( - this, - Invocation.method( - #collectFingerprint, - [], - { + Invocation.method(#collectFingerprint, [], { #attributionWindowHours: attributionWindowHours, #deviceId: deviceId, - }, - ), - )), - ) as _i2.Future<_i3.DeviceFingerprint>); + }), + returnValue: _i2.Future<_i3.DeviceFingerprint>.value( + _FakeDeviceFingerprint_1( + this, + Invocation.method(#collectFingerprint, [], { + #attributionWindowHours: attributionWindowHours, + #deviceId: deviceId, + }), + ), + ), + ) + as _i2.Future<_i3.DeviceFingerprint>); } diff --git a/test/events/event_server_contract_test.dart b/test/events/event_server_contract_test.dart index e07bce9..f572d94 100644 --- a/test/events/event_server_contract_test.dart +++ b/test/events/event_server_contract_test.dart @@ -80,7 +80,9 @@ void main() { http.error = const SocketLikeException(); for (final name in ['first', 'second']) { await expectLater( - () => tracker.trackEvent(name), throwsA(isA())); + () => tracker.trackEvent(name), + throwsA(isA()), + ); } expect(queue.count, 2); @@ -96,10 +98,20 @@ void main() { test('a queued event that still fails keeps its place at the head', () async { queue - ..enqueue(EventRequest( - installId: 'install-1', eventName: 'first', eventData: const {})) - ..enqueue(EventRequest( - installId: 'install-1', eventName: 'second', eventData: const {})); + ..enqueue( + EventRequest( + installId: 'install-1', + eventName: 'first', + eventData: const {}, + ), + ) + ..enqueue( + EventRequest( + installId: 'install-1', + eventName: 'second', + eventData: const {}, + ), + ); http.status = 503; http.body = '{"error":"unavailable"}'; @@ -112,35 +124,51 @@ void main() { http.status = 404; http.body = '{"error":"Install not found"}'; - await expectLater(() => tracker.trackEvent('purchase'), - throwsA(isA())); - - expect(queue.count, 0); - }); - - test('a queued event the server rejects is dropped and the rest are sent', - () async { - queue - ..enqueue(EventRequest( - installId: 'gone', eventName: 'rejected', eventData: const {})) - ..enqueue(EventRequest( - installId: 'install-1', eventName: 'kept', eventData: const {})); - final client = _FirstRejected(http); - - final rejecting = EventTracker( - networkManager: NetworkManager( - config: LinkFortyConfig(baseURL: Uri.parse('https://api.example.com')), - httpClient: client, - ), - storageManager: storage, - attributionContext: AttributionContext(storage: storage), - eventQueue: queue, + await expectLater( + () => tracker.trackEvent('purchase'), + throwsA(isA()), ); - await rejecting.flushQueue(); - expect(client.sent, ['rejected', 'kept']); expect(queue.count, 0); }); + + test( + 'a queued event the server rejects is dropped and the rest are sent', + () async { + queue + ..enqueue( + EventRequest( + installId: 'gone', + eventName: 'rejected', + eventData: const {}, + ), + ) + ..enqueue( + EventRequest( + installId: 'install-1', + eventName: 'kept', + eventData: const {}, + ), + ); + final client = _FirstRejected(http); + + final rejecting = EventTracker( + networkManager: NetworkManager( + config: LinkFortyConfig( + baseURL: Uri.parse('https://api.example.com'), + ), + httpClient: client, + ), + storageManager: storage, + attributionContext: AttributionContext(storage: storage), + eventQueue: queue, + ); + await rejecting.flushQueue(); + + expect(client.sent, ['rejected', 'kept']); + expect(queue.count, 0); + }, + ); } /// A connection-level failure, as the HTTP client reports when offline. @@ -164,6 +192,8 @@ class _FirstRejected implements HttpClient { sent.add(jsonDecode(utf8.decode(body!))['eventName'] as String); final status = sent.length == 1 ? 404 : 200; return HttpResponse( - statusCode: status, body: Uint8List.fromList(utf8.encode(_inner.body))); + statusCode: status, + body: Uint8List.fromList(utf8.encode(_inner.body)), + ); } } diff --git a/test/events/event_tracker_test.dart b/test/events/event_tracker_test.dart index 02a07b7..995f682 100644 --- a/test/events/event_tracker_test.dart +++ b/test/events/event_tracker_test.dart @@ -72,8 +72,9 @@ void main() { body: anyNamed('body'), fromJson: anyNamed('fromJson'), ), - ).thenAnswer((_) async => - const EventResponse(eventId: 'evt-1', acknowledged: true)); + ).thenAnswer( + (_) async => const EventResponse(eventId: 'evt-1', acknowledged: true), + ); await eventTracker.trackEvent('test', {'key': 'value'}); @@ -97,8 +98,9 @@ void main() { test('trackEvent stamps the active last-click attribution', () async { when(mockStorageManager.getInstallId()).thenReturn('inst_1'); - when(mockStorageManager.saveAttribution(any)) - .thenAnswer((_) async => true); + when( + mockStorageManager.saveAttribution(any), + ).thenAnswer((_) async => true); when( mockNetworkManager.request( endpoint: anyNamed('endpoint'), @@ -106,8 +108,9 @@ void main() { body: anyNamed('body'), fromJson: anyNamed('fromJson'), ), - ).thenAnswer((_) async => - const EventResponse(eventId: 'evt-1', acknowledged: true)); + ).thenAnswer( + (_) async => const EventResponse(eventId: 'evt-1', acknowledged: true), + ); // A deep link opens the app, then the user does something. await attributionContext.recordDeepLinkOpen( @@ -136,41 +139,49 @@ void main() { ).called(1); }); - test('trackScreenView emits a screen_view with screen/previousScreen', - () async { - when(mockStorageManager.getInstallId()).thenReturn('inst_1'); - when( - mockNetworkManager.request( - endpoint: anyNamed('endpoint'), - method: anyNamed('method'), - body: anyNamed('body'), - fromJson: anyNamed('fromJson'), - ), - ).thenAnswer((_) async => - const EventResponse(eventId: 'evt-1', acknowledged: true)); + test( + 'trackScreenView emits a screen_view with screen/previousScreen', + () async { + when(mockStorageManager.getInstallId()).thenReturn('inst_1'); + when( + mockNetworkManager.request( + endpoint: anyNamed('endpoint'), + method: anyNamed('method'), + body: anyNamed('body'), + fromJson: anyNamed('fromJson'), + ), + ).thenAnswer( + (_) async => + const EventResponse(eventId: 'evt-1', acknowledged: true), + ); - await eventTracker.trackScreenView('Home'); - await eventTracker.trackScreenView('ProductDetail'); + await eventTracker.trackScreenView('Home'); + await eventTracker.trackScreenView('ProductDetail'); - verify( - mockNetworkManager.request( - endpoint: '/api/sdk/v1/event', - method: HttpMethod.post, - body: argThat( - isA() - .having((e) => e.eventName, 'eventName', 'screen_view') - .having((e) => e.eventData['screen'], 'screen', 'ProductDetail') - .having( - (e) => e.eventData['previousScreen'], - 'previousScreen', - 'Home', - ), - named: 'body', + verify( + mockNetworkManager.request( + endpoint: '/api/sdk/v1/event', + method: HttpMethod.post, + body: argThat( + isA() + .having((e) => e.eventName, 'eventName', 'screen_view') + .having( + (e) => e.eventData['screen'], + 'screen', + 'ProductDetail', + ) + .having( + (e) => e.eventData['previousScreen'], + 'previousScreen', + 'Home', + ), + named: 'body', + ), + fromJson: anyNamed('fromJson'), ), - fromJson: anyNamed('fromJson'), - ), - ).called(1); - }); + ).called(1); + }, + ); test('trackScreenView throws on an empty name', () async { await expectLater( @@ -221,8 +232,9 @@ void main() { body: anyNamed('body'), fromJson: anyNamed('fromJson'), ), - ).thenAnswer((_) async => - const EventResponse(eventId: 'evt-1', acknowledged: true)); + ).thenAnswer( + (_) async => const EventResponse(eventId: 'evt-1', acknowledged: true), + ); await eventTracker.trackRevenue(amount: 10.0, currency: 'USD'); @@ -274,8 +286,9 @@ void main() { body: anyNamed('body'), fromJson: anyNamed('fromJson'), ), - ).thenAnswer((_) async => - const EventResponse(eventId: 'evt-1', acknowledged: true)); + ).thenAnswer( + (_) async => const EventResponse(eventId: 'evt-1', acknowledged: true), + ); await eventTracker.flushQueue(); @@ -352,8 +365,7 @@ void main() { }, ); - test('EventTracker loads persisted queue from storage on creation', - () async { + test('EventTracker loads persisted queue from storage on creation', () async { final persistedEvent = EventRequest( installId: 'inst_1', eventName: 'persisted', diff --git a/test/events/event_tracker_test.mocks.dart b/test/events/event_tracker_test.mocks.dart index c639909..9b22be3 100644 --- a/test/events/event_tracker_test.mocks.dart +++ b/test/events/event_tracker_test.mocks.dart @@ -31,13 +31,8 @@ import 'package:mockito/src/dummies.dart' as _i5; // ignore_for_file: invalid_use_of_internal_member class _FakeFuture_0 extends _i1.SmartFake implements _i2.Future { - _FakeFuture_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeFuture_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } /// A class which mocks [NetworkManagerProtocol]. @@ -58,49 +53,39 @@ class MockNetworkManagerProtocol extends _i1.Mock required T Function(Map)? fromJson, }) => (super.noSuchMethod( - Invocation.method( - #request, - [], - { - #endpoint: endpoint, - #method: method, - #body: body, - #headers: headers, - #fromJson: fromJson, - }, - ), - returnValue: _i5.ifNotNull( - _i5.dummyValueOrNull( - this, - Invocation.method( - #request, - [], - { + Invocation.method(#request, [], { + #endpoint: endpoint, + #method: method, + #body: body, + #headers: headers, + #fromJson: fromJson, + }), + returnValue: + _i5.ifNotNull( + _i5.dummyValueOrNull( + this, + Invocation.method(#request, [], { + #endpoint: endpoint, + #method: method, + #body: body, + #headers: headers, + #fromJson: fromJson, + }), + ), + (T v) => _i2.Future.value(v), + ) ?? + _FakeFuture_0( + this, + Invocation.method(#request, [], { #endpoint: endpoint, #method: method, #body: body, #headers: headers, #fromJson: fromJson, - }, + }), ), - ), - (T v) => _i2.Future.value(v), - ) ?? - _FakeFuture_0( - this, - Invocation.method( - #request, - [], - { - #endpoint: endpoint, - #method: method, - #body: body, - #headers: headers, - #fromJson: fromJson, - }, - ), - ), - ) as _i2.Future); + ) + as _i2.Future); } /// A class which mocks [StorageManagerProtocol]. @@ -113,87 +98,76 @@ class MockStorageManagerProtocol extends _i1.Mock } @override - _i2.Future saveInstallId(String? installId) => (super.noSuchMethod( - Invocation.method( - #saveInstallId, - [installId], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future saveInstallId(String? installId) => + (super.noSuchMethod( + Invocation.method(#saveInstallId, [installId]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override _i2.Future saveInstallData(_i7.DeepLinkData? data) => (super.noSuchMethod( - Invocation.method( - #saveInstallData, - [data], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + Invocation.method(#saveInstallData, [data]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - bool isFirstLaunch() => (super.noSuchMethod( - Invocation.method( - #isFirstLaunch, - [], - ), - returnValue: false, - ) as bool); + bool isFirstLaunch() => + (super.noSuchMethod( + Invocation.method(#isFirstLaunch, []), + returnValue: false, + ) + as bool); @override - _i2.Future setHasLaunched() => (super.noSuchMethod( - Invocation.method( - #setHasLaunched, - [], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future setHasLaunched() => + (super.noSuchMethod( + Invocation.method(#setHasLaunched, []), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override _i2.Future saveEventQueue(List<_i8.EventRequest>? events) => (super.noSuchMethod( - Invocation.method( - #saveEventQueue, - [events], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + Invocation.method(#saveEventQueue, [events]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - List<_i8.EventRequest> loadEventQueue() => (super.noSuchMethod( - Invocation.method( - #loadEventQueue, - [], - ), - returnValue: <_i8.EventRequest>[], - ) as List<_i8.EventRequest>); + List<_i8.EventRequest> loadEventQueue() => + (super.noSuchMethod( + Invocation.method(#loadEventQueue, []), + returnValue: <_i8.EventRequest>[], + ) + as List<_i8.EventRequest>); @override - _i2.Future saveAttribution(String? json) => (super.noSuchMethod( - Invocation.method( - #saveAttribution, - [json], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future saveAttribution(String? json) => + (super.noSuchMethod( + Invocation.method(#saveAttribution, [json]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - _i2.Future removeAttribution() => (super.noSuchMethod( - Invocation.method( - #removeAttribution, - [], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future removeAttribution() => + (super.noSuchMethod( + Invocation.method(#removeAttribution, []), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - _i2.Future clearAll() => (super.noSuchMethod( - Invocation.method( - #clearAll, - [], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future clearAll() => + (super.noSuchMethod( + Invocation.method(#clearAll, []), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); } /// A class which mocks [EventQueue]. @@ -205,56 +179,44 @@ class MockEventQueue extends _i1.Mock implements _i9.EventQueue { } @override - int get count => (super.noSuchMethod( - Invocation.getter(#count), - returnValue: 0, - ) as int); + int get count => + (super.noSuchMethod(Invocation.getter(#count), returnValue: 0) as int); @override - bool get isEmpty => (super.noSuchMethod( - Invocation.getter(#isEmpty), - returnValue: false, - ) as bool); + bool get isEmpty => + (super.noSuchMethod(Invocation.getter(#isEmpty), returnValue: false) + as bool); @override - bool get isFull => (super.noSuchMethod( - Invocation.getter(#isFull), - returnValue: false, - ) as bool); + bool get isFull => + (super.noSuchMethod(Invocation.getter(#isFull), returnValue: false) + as bool); @override - bool enqueue(_i8.EventRequest? event) => (super.noSuchMethod( - Invocation.method( - #enqueue, - [event], - ), - returnValue: false, - ) as bool); + bool enqueue(_i8.EventRequest? event) => + (super.noSuchMethod( + Invocation.method(#enqueue, [event]), + returnValue: false, + ) + as bool); @override void requeueFront(List<_i8.EventRequest>? events) => super.noSuchMethod( - Invocation.method( - #requeueFront, - [events], - ), - returnValueForMissingStub: null, - ); + Invocation.method(#requeueFront, [events]), + returnValueForMissingStub: null, + ); @override - List<_i8.EventRequest> peek() => (super.noSuchMethod( - Invocation.method( - #peek, - [], - ), - returnValue: <_i8.EventRequest>[], - ) as List<_i8.EventRequest>); + List<_i8.EventRequest> peek() => + (super.noSuchMethod( + Invocation.method(#peek, []), + returnValue: <_i8.EventRequest>[], + ) + as List<_i8.EventRequest>); @override void clear() => super.noSuchMethod( - Invocation.method( - #clear, - [], - ), - returnValueForMissingStub: null, - ); + Invocation.method(#clear, []), + returnValueForMissingStub: null, + ); } diff --git a/test/fingerprint/fingerprint_collector_test.dart b/test/fingerprint/fingerprint_collector_test.dart index 4fc34af..6b980a6 100644 --- a/test/fingerprint/fingerprint_collector_test.dart +++ b/test/fingerprint/fingerprint_collector_test.dart @@ -72,17 +72,19 @@ void main() { expect(await FingerprintCollector.localTimezone(), 'Asia/Kolkata'); }); - test('falls back to the abbreviation when the platform cannot answer', - () async { - messenger.setMockMethodCallHandler(channel, (call) async { - throw PlatformException(code: 'unavailable'); - }); - - expect( - await FingerprintCollector.localTimezone(), - DateTime.now().timeZoneName, - ); - }); + test( + 'falls back to the abbreviation when the platform cannot answer', + () async { + messenger.setMockMethodCallHandler(channel, (call) async { + throw PlatformException(code: 'unavailable'); + }); + + expect( + await FingerprintCollector.localTimezone(), + DateTime.now().timeZoneName, + ); + }, + ); }); group('languageTag', () { @@ -94,11 +96,20 @@ void main() { 'fil-PH': const Locale('fil', 'PH'), // Script subtags are dropped. 'zh-CN': const Locale.fromSubtags( - languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'), + languageCode: 'zh', + scriptCode: 'Hans', + countryCode: 'CN', + ), 'zh-TW': const Locale.fromSubtags( - languageCode: 'zh', scriptCode: 'Hant', countryCode: 'TW'), + languageCode: 'zh', + scriptCode: 'Hant', + countryCode: 'TW', + ), 'sr-RS': const Locale.fromSubtags( - languageCode: 'sr', scriptCode: 'Latn', countryCode: 'RS'), + languageCode: 'sr', + scriptCode: 'Latn', + countryCode: 'RS', + ), 'zh': const Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans'), }; @@ -116,13 +127,19 @@ void main() { }); }); - testWidgets('reads the device locale from the platform dispatcher', - (tester) async { + testWidgets('reads the device locale from the platform dispatcher', ( + tester, + ) async { tester.platformDispatcher.localeTestValue = const Locale.fromSubtags( - languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'); + languageCode: 'zh', + scriptCode: 'Hans', + countryCode: 'CN', + ); addTearDown(tester.platformDispatcher.clearLocaleTestValue); - expect(FingerprintCollector.languageTag(tester.platformDispatcher.locale), - 'zh-CN'); + expect( + FingerprintCollector.languageTag(tester.platformDispatcher.locale), + 'zh-CN', + ); }); } diff --git a/test/fingerprint/fingerprint_collector_test.mocks.dart b/test/fingerprint/fingerprint_collector_test.mocks.dart index 4f204ca..71970e1 100644 --- a/test/fingerprint/fingerprint_collector_test.mocks.dart +++ b/test/fingerprint/fingerprint_collector_test.mocks.dart @@ -3,6 +3,7 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes + import 'dart:async' as _i10; import 'package:device_info_plus/device_info_plus.dart' as _i9; @@ -35,99 +36,54 @@ import 'package:package_info_plus/package_info_plus.dart' as _i11; class _FakeAndroidDeviceInfo_0 extends _i1.SmartFake implements _i2.AndroidDeviceInfo { - _FakeAndroidDeviceInfo_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeAndroidDeviceInfo_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeIosDeviceInfo_1 extends _i1.SmartFake implements _i3.IosDeviceInfo { - _FakeIosDeviceInfo_1( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeIosDeviceInfo_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeLinuxDeviceInfo_2 extends _i1.SmartFake implements _i4.LinuxDeviceInfo { - _FakeLinuxDeviceInfo_2( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeLinuxDeviceInfo_2(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeWebBrowserInfo_3 extends _i1.SmartFake implements _i5.WebBrowserInfo { - _FakeWebBrowserInfo_3( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeWebBrowserInfo_3(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeMacOsDeviceInfo_4 extends _i1.SmartFake implements _i6.MacOsDeviceInfo { - _FakeMacOsDeviceInfo_4( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeMacOsDeviceInfo_4(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeWindowsDeviceInfo_5 extends _i1.SmartFake implements _i7.WindowsDeviceInfo { - _FakeWindowsDeviceInfo_5( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeWindowsDeviceInfo_5(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeBaseDeviceInfo_6 extends _i1.SmartFake implements _i8.BaseDeviceInfo { - _FakeBaseDeviceInfo_6( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeBaseDeviceInfo_6(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeAndroidBuildVersion_7 extends _i1.SmartFake implements _i2.AndroidBuildVersion { - _FakeAndroidBuildVersion_7( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeAndroidBuildVersion_7(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeIosUtsname_8 extends _i1.SmartFake implements _i3.IosUtsname { - _FakeIosUtsname_8( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeIosUtsname_8(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } /// A class which mocks [DeviceInfoPlugin]. @@ -139,73 +95,74 @@ class MockDeviceInfoPlugin extends _i1.Mock implements _i9.DeviceInfoPlugin { } @override - _i10.Future<_i2.AndroidDeviceInfo> get androidInfo => (super.noSuchMethod( - Invocation.getter(#androidInfo), - returnValue: - _i10.Future<_i2.AndroidDeviceInfo>.value(_FakeAndroidDeviceInfo_0( - this, - Invocation.getter(#androidInfo), - )), - ) as _i10.Future<_i2.AndroidDeviceInfo>); - - @override - _i10.Future<_i3.IosDeviceInfo> get iosInfo => (super.noSuchMethod( - Invocation.getter(#iosInfo), - returnValue: _i10.Future<_i3.IosDeviceInfo>.value(_FakeIosDeviceInfo_1( - this, - Invocation.getter(#iosInfo), - )), - ) as _i10.Future<_i3.IosDeviceInfo>); - - @override - _i10.Future<_i4.LinuxDeviceInfo> get linuxInfo => (super.noSuchMethod( - Invocation.getter(#linuxInfo), - returnValue: - _i10.Future<_i4.LinuxDeviceInfo>.value(_FakeLinuxDeviceInfo_2( - this, - Invocation.getter(#linuxInfo), - )), - ) as _i10.Future<_i4.LinuxDeviceInfo>); - - @override - _i10.Future<_i5.WebBrowserInfo> get webBrowserInfo => (super.noSuchMethod( - Invocation.getter(#webBrowserInfo), - returnValue: - _i10.Future<_i5.WebBrowserInfo>.value(_FakeWebBrowserInfo_3( - this, - Invocation.getter(#webBrowserInfo), - )), - ) as _i10.Future<_i5.WebBrowserInfo>); - - @override - _i10.Future<_i6.MacOsDeviceInfo> get macOsInfo => (super.noSuchMethod( - Invocation.getter(#macOsInfo), - returnValue: - _i10.Future<_i6.MacOsDeviceInfo>.value(_FakeMacOsDeviceInfo_4( - this, - Invocation.getter(#macOsInfo), - )), - ) as _i10.Future<_i6.MacOsDeviceInfo>); - - @override - _i10.Future<_i7.WindowsDeviceInfo> get windowsInfo => (super.noSuchMethod( - Invocation.getter(#windowsInfo), - returnValue: - _i10.Future<_i7.WindowsDeviceInfo>.value(_FakeWindowsDeviceInfo_5( - this, - Invocation.getter(#windowsInfo), - )), - ) as _i10.Future<_i7.WindowsDeviceInfo>); - - @override - _i10.Future<_i8.BaseDeviceInfo> get deviceInfo => (super.noSuchMethod( - Invocation.getter(#deviceInfo), - returnValue: - _i10.Future<_i8.BaseDeviceInfo>.value(_FakeBaseDeviceInfo_6( - this, - Invocation.getter(#deviceInfo), - )), - ) as _i10.Future<_i8.BaseDeviceInfo>); + _i10.Future<_i2.AndroidDeviceInfo> get androidInfo => + (super.noSuchMethod( + Invocation.getter(#androidInfo), + returnValue: _i10.Future<_i2.AndroidDeviceInfo>.value( + _FakeAndroidDeviceInfo_0(this, Invocation.getter(#androidInfo)), + ), + ) + as _i10.Future<_i2.AndroidDeviceInfo>); + + @override + _i10.Future<_i3.IosDeviceInfo> get iosInfo => + (super.noSuchMethod( + Invocation.getter(#iosInfo), + returnValue: _i10.Future<_i3.IosDeviceInfo>.value( + _FakeIosDeviceInfo_1(this, Invocation.getter(#iosInfo)), + ), + ) + as _i10.Future<_i3.IosDeviceInfo>); + + @override + _i10.Future<_i4.LinuxDeviceInfo> get linuxInfo => + (super.noSuchMethod( + Invocation.getter(#linuxInfo), + returnValue: _i10.Future<_i4.LinuxDeviceInfo>.value( + _FakeLinuxDeviceInfo_2(this, Invocation.getter(#linuxInfo)), + ), + ) + as _i10.Future<_i4.LinuxDeviceInfo>); + + @override + _i10.Future<_i5.WebBrowserInfo> get webBrowserInfo => + (super.noSuchMethod( + Invocation.getter(#webBrowserInfo), + returnValue: _i10.Future<_i5.WebBrowserInfo>.value( + _FakeWebBrowserInfo_3(this, Invocation.getter(#webBrowserInfo)), + ), + ) + as _i10.Future<_i5.WebBrowserInfo>); + + @override + _i10.Future<_i6.MacOsDeviceInfo> get macOsInfo => + (super.noSuchMethod( + Invocation.getter(#macOsInfo), + returnValue: _i10.Future<_i6.MacOsDeviceInfo>.value( + _FakeMacOsDeviceInfo_4(this, Invocation.getter(#macOsInfo)), + ), + ) + as _i10.Future<_i6.MacOsDeviceInfo>); + + @override + _i10.Future<_i7.WindowsDeviceInfo> get windowsInfo => + (super.noSuchMethod( + Invocation.getter(#windowsInfo), + returnValue: _i10.Future<_i7.WindowsDeviceInfo>.value( + _FakeWindowsDeviceInfo_5(this, Invocation.getter(#windowsInfo)), + ), + ) + as _i10.Future<_i7.WindowsDeviceInfo>); + + @override + _i10.Future<_i8.BaseDeviceInfo> get deviceInfo => + (super.noSuchMethod( + Invocation.getter(#deviceInfo), + returnValue: _i10.Future<_i8.BaseDeviceInfo>.value( + _FakeBaseDeviceInfo_6(this, Invocation.getter(#deviceInfo)), + ), + ) + as _i10.Future<_i8.BaseDeviceInfo>); } /// A class which mocks [PackageInfo]. @@ -217,55 +174,67 @@ class MockPackageInfo extends _i1.Mock implements _i11.PackageInfo { } @override - String get appName => (super.noSuchMethod( - Invocation.getter(#appName), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#appName), - ), - ) as String); - - @override - String get packageName => (super.noSuchMethod( - Invocation.getter(#packageName), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#packageName), - ), - ) as String); - - @override - String get version => (super.noSuchMethod( - Invocation.getter(#version), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#version), - ), - ) as String); - - @override - String get buildNumber => (super.noSuchMethod( - Invocation.getter(#buildNumber), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#buildNumber), - ), - ) as String); - - @override - String get buildSignature => (super.noSuchMethod( - Invocation.getter(#buildSignature), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#buildSignature), - ), - ) as String); - - @override - Map get data => (super.noSuchMethod( - Invocation.getter(#data), - returnValue: {}, - ) as Map); + String get appName => + (super.noSuchMethod( + Invocation.getter(#appName), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#appName), + ), + ) + as String); + + @override + String get packageName => + (super.noSuchMethod( + Invocation.getter(#packageName), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#packageName), + ), + ) + as String); + + @override + String get version => + (super.noSuchMethod( + Invocation.getter(#version), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#version), + ), + ) + as String); + + @override + String get buildNumber => + (super.noSuchMethod( + Invocation.getter(#buildNumber), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#buildNumber), + ), + ) + as String); + + @override + String get buildSignature => + (super.noSuchMethod( + Invocation.getter(#buildSignature), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#buildSignature), + ), + ) + as String); + + @override + Map get data => + (super.noSuchMethod( + Invocation.getter(#data), + returnValue: {}, + ) + as Map); } /// A class which mocks [AndroidDeviceInfo]. @@ -277,223 +246,265 @@ class MockAndroidDeviceInfo extends _i1.Mock implements _i2.AndroidDeviceInfo { } @override - _i2.AndroidBuildVersion get version => (super.noSuchMethod( - Invocation.getter(#version), - returnValue: _FakeAndroidBuildVersion_7( - this, - Invocation.getter(#version), - ), - ) as _i2.AndroidBuildVersion); - - @override - String get board => (super.noSuchMethod( - Invocation.getter(#board), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#board), - ), - ) as String); - - @override - String get bootloader => (super.noSuchMethod( - Invocation.getter(#bootloader), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#bootloader), - ), - ) as String); - - @override - String get brand => (super.noSuchMethod( - Invocation.getter(#brand), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#brand), - ), - ) as String); - - @override - String get device => (super.noSuchMethod( - Invocation.getter(#device), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#device), - ), - ) as String); - - @override - String get display => (super.noSuchMethod( - Invocation.getter(#display), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#display), - ), - ) as String); - - @override - String get fingerprint => (super.noSuchMethod( - Invocation.getter(#fingerprint), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#fingerprint), - ), - ) as String); - - @override - String get hardware => (super.noSuchMethod( - Invocation.getter(#hardware), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#hardware), - ), - ) as String); - - @override - String get host => (super.noSuchMethod( - Invocation.getter(#host), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#host), - ), - ) as String); - - @override - String get id => (super.noSuchMethod( - Invocation.getter(#id), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#id), - ), - ) as String); - - @override - String get manufacturer => (super.noSuchMethod( - Invocation.getter(#manufacturer), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#manufacturer), - ), - ) as String); - - @override - String get model => (super.noSuchMethod( - Invocation.getter(#model), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#model), - ), - ) as String); - - @override - String get product => (super.noSuchMethod( - Invocation.getter(#product), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#product), - ), - ) as String); - - @override - String get name => (super.noSuchMethod( - Invocation.getter(#name), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#name), - ), - ) as String); + _i2.AndroidBuildVersion get version => + (super.noSuchMethod( + Invocation.getter(#version), + returnValue: _FakeAndroidBuildVersion_7( + this, + Invocation.getter(#version), + ), + ) + as _i2.AndroidBuildVersion); + + @override + String get board => + (super.noSuchMethod( + Invocation.getter(#board), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#board), + ), + ) + as String); + + @override + String get bootloader => + (super.noSuchMethod( + Invocation.getter(#bootloader), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#bootloader), + ), + ) + as String); + + @override + String get brand => + (super.noSuchMethod( + Invocation.getter(#brand), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#brand), + ), + ) + as String); + + @override + String get device => + (super.noSuchMethod( + Invocation.getter(#device), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#device), + ), + ) + as String); + + @override + String get display => + (super.noSuchMethod( + Invocation.getter(#display), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#display), + ), + ) + as String); + + @override + String get fingerprint => + (super.noSuchMethod( + Invocation.getter(#fingerprint), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#fingerprint), + ), + ) + as String); + + @override + String get hardware => + (super.noSuchMethod( + Invocation.getter(#hardware), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#hardware), + ), + ) + as String); + + @override + String get host => + (super.noSuchMethod( + Invocation.getter(#host), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#host), + ), + ) + as String); + + @override + String get id => + (super.noSuchMethod( + Invocation.getter(#id), + returnValue: _i12.dummyValue(this, Invocation.getter(#id)), + ) + as String); + + @override + String get manufacturer => + (super.noSuchMethod( + Invocation.getter(#manufacturer), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#manufacturer), + ), + ) + as String); + + @override + String get model => + (super.noSuchMethod( + Invocation.getter(#model), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#model), + ), + ) + as String); + + @override + String get product => + (super.noSuchMethod( + Invocation.getter(#product), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#product), + ), + ) + as String); + + @override + String get name => + (super.noSuchMethod( + Invocation.getter(#name), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#name), + ), + ) + as String); + + @override + List get supported32BitAbis => + (super.noSuchMethod( + Invocation.getter(#supported32BitAbis), + returnValue: [], + ) + as List); + + @override + List get supported64BitAbis => + (super.noSuchMethod( + Invocation.getter(#supported64BitAbis), + returnValue: [], + ) + as List); + + @override + List get supportedAbis => + (super.noSuchMethod( + Invocation.getter(#supportedAbis), + returnValue: [], + ) + as List); + + @override + String get tags => + (super.noSuchMethod( + Invocation.getter(#tags), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#tags), + ), + ) + as String); + + @override + int get time => + (super.noSuchMethod(Invocation.getter(#time), returnValue: 0) as int); + + @override + String get type => + (super.noSuchMethod( + Invocation.getter(#type), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#type), + ), + ) + as String); + + @override + bool get isPhysicalDevice => + (super.noSuchMethod( + Invocation.getter(#isPhysicalDevice), + returnValue: false, + ) + as bool); + + @override + int get freeDiskSize => + (super.noSuchMethod(Invocation.getter(#freeDiskSize), returnValue: 0) + as int); @override - List get supported32BitAbis => (super.noSuchMethod( - Invocation.getter(#supported32BitAbis), - returnValue: [], - ) as List); + int get totalDiskSize => + (super.noSuchMethod(Invocation.getter(#totalDiskSize), returnValue: 0) + as int); - @override - List get supported64BitAbis => (super.noSuchMethod( - Invocation.getter(#supported64BitAbis), - returnValue: [], - ) as List); - - @override - List get supportedAbis => (super.noSuchMethod( - Invocation.getter(#supportedAbis), - returnValue: [], - ) as List); + @override + List get systemFeatures => + (super.noSuchMethod( + Invocation.getter(#systemFeatures), + returnValue: [], + ) + as List); @override - String get tags => (super.noSuchMethod( - Invocation.getter(#tags), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#tags), - ), - ) as String); + bool get isLowRamDevice => + (super.noSuchMethod( + Invocation.getter(#isLowRamDevice), + returnValue: false, + ) + as bool); @override - String get type => (super.noSuchMethod( - Invocation.getter(#type), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#type), - ), - ) as String); + int get physicalRamSize => + (super.noSuchMethod(Invocation.getter(#physicalRamSize), returnValue: 0) + as int); @override - bool get isPhysicalDevice => (super.noSuchMethod( - Invocation.getter(#isPhysicalDevice), - returnValue: false, - ) as bool); + int get availableRamSize => + (super.noSuchMethod(Invocation.getter(#availableRamSize), returnValue: 0) + as int); @override - int get freeDiskSize => (super.noSuchMethod( - Invocation.getter(#freeDiskSize), - returnValue: 0, - ) as int); + Map get data => + (super.noSuchMethod( + Invocation.getter(#data), + returnValue: {}, + ) + as Map); @override - int get totalDiskSize => (super.noSuchMethod( - Invocation.getter(#totalDiskSize), - returnValue: 0, - ) as int); - - @override - List get systemFeatures => (super.noSuchMethod( - Invocation.getter(#systemFeatures), - returnValue: [], - ) as List); - - @override - bool get isLowRamDevice => (super.noSuchMethod( - Invocation.getter(#isLowRamDevice), - returnValue: false, - ) as bool); - - @override - int get physicalRamSize => (super.noSuchMethod( - Invocation.getter(#physicalRamSize), - returnValue: 0, - ) as int); - - @override - int get availableRamSize => (super.noSuchMethod( - Invocation.getter(#availableRamSize), - returnValue: 0, - ) as int); - - @override - Map get data => (super.noSuchMethod( - Invocation.getter(#data), - returnValue: {}, - ) as Map); - - @override - Map toMap() => (super.noSuchMethod( - Invocation.method( - #toMap, - [], - ), - returnValue: {}, - ) as Map); + Map toMap() => + (super.noSuchMethod( + Invocation.method(#toMap, []), + returnValue: {}, + ) + as Map); } /// A class which mocks [IosDeviceInfo]. @@ -505,122 +516,133 @@ class MockIosDeviceInfo extends _i1.Mock implements _i3.IosDeviceInfo { } @override - String get name => (super.noSuchMethod( - Invocation.getter(#name), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#name), - ), - ) as String); + String get name => + (super.noSuchMethod( + Invocation.getter(#name), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#name), + ), + ) + as String); @override - String get systemName => (super.noSuchMethod( - Invocation.getter(#systemName), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#systemName), - ), - ) as String); + String get systemName => + (super.noSuchMethod( + Invocation.getter(#systemName), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#systemName), + ), + ) + as String); @override - String get systemVersion => (super.noSuchMethod( - Invocation.getter(#systemVersion), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#systemVersion), - ), - ) as String); + String get systemVersion => + (super.noSuchMethod( + Invocation.getter(#systemVersion), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#systemVersion), + ), + ) + as String); @override - String get model => (super.noSuchMethod( - Invocation.getter(#model), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#model), - ), - ) as String); + String get model => + (super.noSuchMethod( + Invocation.getter(#model), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#model), + ), + ) + as String); @override - String get modelName => (super.noSuchMethod( - Invocation.getter(#modelName), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#modelName), - ), - ) as String); + String get modelName => + (super.noSuchMethod( + Invocation.getter(#modelName), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#modelName), + ), + ) + as String); @override - String get localizedModel => (super.noSuchMethod( - Invocation.getter(#localizedModel), - returnValue: _i12.dummyValue( - this, - Invocation.getter(#localizedModel), - ), - ) as String); + String get localizedModel => + (super.noSuchMethod( + Invocation.getter(#localizedModel), + returnValue: _i12.dummyValue( + this, + Invocation.getter(#localizedModel), + ), + ) + as String); @override - bool get isPhysicalDevice => (super.noSuchMethod( - Invocation.getter(#isPhysicalDevice), - returnValue: false, - ) as bool); + bool get isPhysicalDevice => + (super.noSuchMethod( + Invocation.getter(#isPhysicalDevice), + returnValue: false, + ) + as bool); @override - int get physicalRamSize => (super.noSuchMethod( - Invocation.getter(#physicalRamSize), - returnValue: 0, - ) as int); + int get physicalRamSize => + (super.noSuchMethod(Invocation.getter(#physicalRamSize), returnValue: 0) + as int); @override - int get availableRamSize => (super.noSuchMethod( - Invocation.getter(#availableRamSize), - returnValue: 0, - ) as int); + int get availableRamSize => + (super.noSuchMethod(Invocation.getter(#availableRamSize), returnValue: 0) + as int); @override - bool get isiOSAppOnMac => (super.noSuchMethod( - Invocation.getter(#isiOSAppOnMac), - returnValue: false, - ) as bool); + bool get isiOSAppOnMac => + (super.noSuchMethod(Invocation.getter(#isiOSAppOnMac), returnValue: false) + as bool); @override - bool get isiOSAppOnVision => (super.noSuchMethod( - Invocation.getter(#isiOSAppOnVision), - returnValue: false, - ) as bool); + bool get isiOSAppOnVision => + (super.noSuchMethod( + Invocation.getter(#isiOSAppOnVision), + returnValue: false, + ) + as bool); @override - _i3.IosUtsname get utsname => (super.noSuchMethod( - Invocation.getter(#utsname), - returnValue: _FakeIosUtsname_8( - this, - Invocation.getter(#utsname), - ), - ) as _i3.IosUtsname); + _i3.IosUtsname get utsname => + (super.noSuchMethod( + Invocation.getter(#utsname), + returnValue: _FakeIosUtsname_8(this, Invocation.getter(#utsname)), + ) + as _i3.IosUtsname); + + @override + int get freeDiskSize => + (super.noSuchMethod(Invocation.getter(#freeDiskSize), returnValue: 0) + as int); @override - int get freeDiskSize => (super.noSuchMethod( - Invocation.getter(#freeDiskSize), - returnValue: 0, - ) as int); - - @override - int get totalDiskSize => (super.noSuchMethod( - Invocation.getter(#totalDiskSize), - returnValue: 0, - ) as int); - + int get totalDiskSize => + (super.noSuchMethod(Invocation.getter(#totalDiskSize), returnValue: 0) + as int); + @override - Map get data => (super.noSuchMethod( - Invocation.getter(#data), - returnValue: {}, - ) as Map); + Map get data => + (super.noSuchMethod( + Invocation.getter(#data), + returnValue: {}, + ) + as Map); @override - Map toMap() => (super.noSuchMethod( - Invocation.method( - #toMap, - [], - ), - returnValue: {}, - ) as Map); + Map toMap() => + (super.noSuchMethod( + Invocation.method(#toMap, []), + returnValue: {}, + ) + as Map); } diff --git a/test/link_forty_test.dart b/test/link_forty_test.dart index 1797a85..d5fb12e 100644 --- a/test/link_forty_test.dart +++ b/test/link_forty_test.dart @@ -229,8 +229,10 @@ void main() { ).thenAnswer((_) async => fingerprint); when( mockNetworkManager.request( - endpoint: - argThat(startsWith('/api/sdk/v1/resolve/'), named: 'endpoint'), + endpoint: argThat( + startsWith('/api/sdk/v1/resolve/'), + named: 'endpoint', + ), method: anyNamed('method'), body: anyNamed('body'), fromJson: anyNamed('fromJson'), @@ -238,8 +240,9 @@ void main() { ).thenAnswer( (_) async => const DeepLinkData(shortCode: 'abc', linkId: 'direct'), ); - when(mockStorageManager.saveAttribution(any)) - .thenAnswer((_) async => true); + when( + mockStorageManager.saveAttribution(any), + ).thenAnswer((_) async => true); }); // close() never completes on a controller nothing listened to. @@ -278,53 +281,54 @@ void main() { matchedFactors: [], ); + test('delivers the launch link to an onDeepLink callback registered after ' + 'initialize', () async { + stubInstall(organic); + links.add(launchLink); + await initialize(); + + Uri? deliveredUri; + DeepLinkData? deliveredData; + LinkForty.instance.onDeepLink((uri, data) { + deliveredUri = uri; + deliveredData = data; + }); + await pumpEventQueue(); + + expect(deliveredUri, launchLink); + expect(deliveredData?.linkId, 'direct'); + }); + test( - 'delivers the launch link to an onDeepLink callback registered after ' - 'initialize', + 'delivers a link opened while running to registered callbacks', () async { stubInstall(organic); - links.add(launchLink); await initialize(); - Uri? deliveredUri; - DeepLinkData? deliveredData; - LinkForty.instance.onDeepLink((uri, data) { - deliveredUri = uri; - deliveredData = data; - }); + final delivered = []; + LinkForty.instance.onDeepLink((uri, _) => delivered.add(uri)); + links.add(launchLink); await pumpEventQueue(); - expect(deliveredUri, launchLink); - expect(deliveredData?.linkId, 'direct'); + expect(delivered, [launchLink]); }, ); - test('delivers a link opened while running to registered callbacks', - () async { - stubInstall(organic); - await initialize(); - - final delivered = []; - LinkForty.instance.onDeepLink((uri, _) => delivered.add(uri)); - links.add(launchLink); - await pumpEventQueue(); - - expect(delivered, [launchLink]); - }); - - test('a manual handleDeepLink of the same link is delivered once', - () async { - stubInstall(organic); - links.add(launchLink); - await initialize(); + test( + 'a manual handleDeepLink of the same link is delivered once', + () async { + stubInstall(organic); + links.add(launchLink); + await initialize(); - final delivered = []; - LinkForty.instance.onDeepLink((uri, _) => delivered.add(uri)); - await LinkForty.instance.handleDeepLink(launchLink); - await pumpEventQueue(); + final delivered = []; + LinkForty.instance.onDeepLink((uri, _) => delivered.add(uri)); + await LinkForty.instance.handleDeepLink(launchLink); + await pumpEventQueue(); - expect(delivered, [launchLink]); - }); + expect(delivered, [launchLink]); + }, + ); test('calls onDeferredDeepLink with null for an organic install', () async { stubInstall(organic); @@ -342,51 +346,55 @@ void main() { expect(delivered, isNull); }); - test('reports the install with the configured attribution window', - () async { - stubInstall(organic); - await initialize( - withConfig: LinkFortyConfig( - baseURL: Uri.parse('https://example.com'), - attributionWindowHours: 24, - ), - ); - - verify( - mockFingerprintCollector.collectFingerprint( - attributionWindowHours: 24, - deviceId: anyNamed('deviceId'), - ), - ).called(1); - }); + test( + 'reports the install with the configured attribution window', + () async { + stubInstall(organic); + await initialize( + withConfig: LinkFortyConfig( + baseURL: Uri.parse('https://example.com'), + attributionWindowHours: 24, + ), + ); + + verify( + mockFingerprintCollector.collectFingerprint( + attributionWindowHours: 24, + deviceId: anyNamed('deviceId'), + ), + ).called(1); + }, + ); - test('a direct open during the install launch outranks the install link', - () async { - stubInstall( - const InstallResponse( - installId: 'inst_1', - attributed: true, - confidenceScore: 90, - matchedFactors: [], - deepLinkData: DeepLinkData(shortCode: 'xyz', linkId: 'install'), - ), - delay: const Duration(milliseconds: 20), - ); - links.add(launchLink); - await initialize(); + test( + 'a direct open during the install launch outranks the install link', + () async { + stubInstall( + const InstallResponse( + installId: 'inst_1', + attributed: true, + confidenceScore: 90, + matchedFactors: [], + deepLinkData: DeepLinkData(shortCode: 'xyz', linkId: 'install'), + ), + delay: const Duration(milliseconds: 20), + ); + links.add(launchLink); + await initialize(); - final saved = verify(mockStorageManager.saveAttribution(captureAny)) - .captured - .cast(); - expect(saved, hasLength(1)); - expect(saved.single, contains('"direct"')); - }); + final saved = verify( + mockStorageManager.saveAttribution(captureAny), + ).captured.cast(); + expect(saved, hasLength(1)); + expect(saved.single, contains('"direct"')); + }, + ); test('a later launch delivers no deferred deep link', () async { when(mockStorageManager.getInstallId()).thenReturn('inst_1'); - when(mockStorageManager.getInstallData()).thenReturn( - const DeepLinkData(shortCode: 'xyz', linkId: 'install'), - ); + when( + mockStorageManager.getInstallData(), + ).thenReturn(const DeepLinkData(shortCode: 'xyz', linkId: 'install')); await initialize(); final delivered = []; @@ -399,24 +407,25 @@ void main() { }); test( - 'the launch that reports the install delivers the deferred deep link once', - () async { - stubInstall( - const InstallResponse( - installId: 'inst_1', - attributed: true, - confidenceScore: 90, - matchedFactors: [], - deepLinkData: DeepLinkData(shortCode: 'xyz', linkId: 'install'), - ), - ); - await initialize(); + 'the launch that reports the install delivers the deferred deep link once', + () async { + stubInstall( + const InstallResponse( + installId: 'inst_1', + attributed: true, + confidenceScore: 90, + matchedFactors: [], + deepLinkData: DeepLinkData(shortCode: 'xyz', linkId: 'install'), + ), + ); + await initialize(); - final delivered = []; - LinkForty.instance.onDeferredDeepLink(delivered.add); - await pumpEventQueue(); + final delivered = []; + LinkForty.instance.onDeferredDeepLink(delivered.add); + await pumpEventQueue(); - expect(delivered.map((d) => d?.linkId), ['install']); - }); + expect(delivered.map((d) => d?.linkId), ['install']); + }, + ); }); } diff --git a/test/link_forty_test.mocks.dart b/test/link_forty_test.mocks.dart index de635ad..1aa44a8 100644 --- a/test/link_forty_test.mocks.dart +++ b/test/link_forty_test.mocks.dart @@ -3,6 +3,7 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes + import 'dart:async' as _i2; import 'package:linkforty_flutter/fingerprint/device_fingerprint.dart' as _i3; @@ -32,24 +33,14 @@ import 'package:mockito/src/dummies.dart' as _i6; // ignore_for_file: invalid_use_of_internal_member class _FakeFuture_0 extends _i1.SmartFake implements _i2.Future { - _FakeFuture_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeFuture_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeDeviceFingerprint_1 extends _i1.SmartFake implements _i3.DeviceFingerprint { - _FakeDeviceFingerprint_1( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeDeviceFingerprint_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } /// A class which mocks [NetworkManagerProtocol]. @@ -70,49 +61,39 @@ class MockNetworkManagerProtocol extends _i1.Mock required T Function(Map)? fromJson, }) => (super.noSuchMethod( - Invocation.method( - #request, - [], - { - #endpoint: endpoint, - #method: method, - #body: body, - #headers: headers, - #fromJson: fromJson, - }, - ), - returnValue: _i6.ifNotNull( - _i6.dummyValueOrNull( - this, - Invocation.method( - #request, - [], - { + Invocation.method(#request, [], { + #endpoint: endpoint, + #method: method, + #body: body, + #headers: headers, + #fromJson: fromJson, + }), + returnValue: + _i6.ifNotNull( + _i6.dummyValueOrNull( + this, + Invocation.method(#request, [], { + #endpoint: endpoint, + #method: method, + #body: body, + #headers: headers, + #fromJson: fromJson, + }), + ), + (T v) => _i2.Future.value(v), + ) ?? + _FakeFuture_0( + this, + Invocation.method(#request, [], { #endpoint: endpoint, #method: method, #body: body, #headers: headers, #fromJson: fromJson, - }, + }), ), - ), - (T v) => _i2.Future.value(v), - ) ?? - _FakeFuture_0( - this, - Invocation.method( - #request, - [], - { - #endpoint: endpoint, - #method: method, - #body: body, - #headers: headers, - #fromJson: fromJson, - }, - ), - ), - ) as _i2.Future); + ) + as _i2.Future); } /// A class which mocks [StorageManagerProtocol]. @@ -125,87 +106,76 @@ class MockStorageManagerProtocol extends _i1.Mock } @override - _i2.Future saveInstallId(String? installId) => (super.noSuchMethod( - Invocation.method( - #saveInstallId, - [installId], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future saveInstallId(String? installId) => + (super.noSuchMethod( + Invocation.method(#saveInstallId, [installId]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override _i2.Future saveInstallData(_i8.DeepLinkData? data) => (super.noSuchMethod( - Invocation.method( - #saveInstallData, - [data], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + Invocation.method(#saveInstallData, [data]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - bool isFirstLaunch() => (super.noSuchMethod( - Invocation.method( - #isFirstLaunch, - [], - ), - returnValue: false, - ) as bool); + bool isFirstLaunch() => + (super.noSuchMethod( + Invocation.method(#isFirstLaunch, []), + returnValue: false, + ) + as bool); @override - _i2.Future setHasLaunched() => (super.noSuchMethod( - Invocation.method( - #setHasLaunched, - [], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future setHasLaunched() => + (super.noSuchMethod( + Invocation.method(#setHasLaunched, []), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override _i2.Future saveEventQueue(List<_i9.EventRequest>? events) => (super.noSuchMethod( - Invocation.method( - #saveEventQueue, - [events], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + Invocation.method(#saveEventQueue, [events]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - List<_i9.EventRequest> loadEventQueue() => (super.noSuchMethod( - Invocation.method( - #loadEventQueue, - [], - ), - returnValue: <_i9.EventRequest>[], - ) as List<_i9.EventRequest>); + List<_i9.EventRequest> loadEventQueue() => + (super.noSuchMethod( + Invocation.method(#loadEventQueue, []), + returnValue: <_i9.EventRequest>[], + ) + as List<_i9.EventRequest>); @override - _i2.Future saveAttribution(String? json) => (super.noSuchMethod( - Invocation.method( - #saveAttribution, - [json], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future saveAttribution(String? json) => + (super.noSuchMethod( + Invocation.method(#saveAttribution, [json]), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - _i2.Future removeAttribution() => (super.noSuchMethod( - Invocation.method( - #removeAttribution, - [], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future removeAttribution() => + (super.noSuchMethod( + Invocation.method(#removeAttribution, []), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); @override - _i2.Future clearAll() => (super.noSuchMethod( - Invocation.method( - #clearAll, - [], - ), - returnValue: _i2.Future.value(false), - ) as _i2.Future); + _i2.Future clearAll() => + (super.noSuchMethod( + Invocation.method(#clearAll, []), + returnValue: _i2.Future.value(false), + ) + as _i2.Future); } /// A class which mocks [FingerprintCollectorProtocol]. @@ -223,25 +193,19 @@ class MockFingerprintCollectorProtocol extends _i1.Mock String? deviceId, }) => (super.noSuchMethod( - Invocation.method( - #collectFingerprint, - [], - { - #attributionWindowHours: attributionWindowHours, - #deviceId: deviceId, - }, - ), - returnValue: - _i2.Future<_i3.DeviceFingerprint>.value(_FakeDeviceFingerprint_1( - this, - Invocation.method( - #collectFingerprint, - [], - { + Invocation.method(#collectFingerprint, [], { #attributionWindowHours: attributionWindowHours, #deviceId: deviceId, - }, - ), - )), - ) as _i2.Future<_i3.DeviceFingerprint>); + }), + returnValue: _i2.Future<_i3.DeviceFingerprint>.value( + _FakeDeviceFingerprint_1( + this, + Invocation.method(#collectFingerprint, [], { + #attributionWindowHours: attributionWindowHours, + #deviceId: deviceId, + }), + ), + ), + ) + as _i2.Future<_i3.DeviceFingerprint>); } diff --git a/test/models/deep_link_data_test.dart b/test/models/deep_link_data_test.dart index dd233e0..be8559b 100644 --- a/test/models/deep_link_data_test.dart +++ b/test/models/deep_link_data_test.dart @@ -150,19 +150,27 @@ void main() { expect(a.hashCode, b.hashCode); expect( a, - isNot(equals(const DeepLinkData( - shortCode: 'abc', - matchedFactors: ['ip'], - competingLinks: 1, - ))), + isNot( + equals( + const DeepLinkData( + shortCode: 'abc', + matchedFactors: ['ip'], + competingLinks: 1, + ), + ), + ), ); expect( a, - isNot(equals(const DeepLinkData( - shortCode: 'abc', - matchedFactors: ['ua'], - competingLinks: 0, - ))), + isNot( + equals( + const DeepLinkData( + shortCode: 'abc', + matchedFactors: ['ua'], + competingLinks: 0, + ), + ), + ), ); }); @@ -186,8 +194,9 @@ void main() { group('mergingUrlParameters', () { test('adds URL parameters when the link configures none', () { - final merged = const DeepLinkData(shortCode: 'abc123') - .mergingUrlParameters({'slug': 'titanic'}); + final merged = const DeepLinkData( + shortCode: 'abc123', + ).mergingUrlParameters({'slug': 'titanic'}); expect(merged.customParameters, {'slug': 'titanic'}); }); @@ -209,7 +218,9 @@ void main() { ); expect( - identical(resolved.mergingUrlParameters(null), resolved), isTrue); + identical(resolved.mergingUrlParameters(null), resolved), + isTrue, + ); expect(identical(resolved.mergingUrlParameters({}), resolved), isTrue); }); @@ -225,8 +236,10 @@ void main() { expect(merged.linkId, 'link-1'); expect(merged.deepLinkPath, '/product/1'); expect(merged.appScheme, 'myapp'); - expect(merged.androidURL, - 'https://play.google.com/store/apps/details?id=com.app'); + expect( + merged.androidURL, + 'https://play.google.com/store/apps/details?id=com.app', + ); }); }); }); diff --git a/test/models/install_response_test.dart b/test/models/install_response_test.dart index c42a94a..2984d4e 100644 --- a/test/models/install_response_test.dart +++ b/test/models/install_response_test.dart @@ -224,13 +224,17 @@ void main() { expect(res1, isNot(equals(res3))); expect( res1, - isNot(equals(InstallResponse( - installId: '1', - attributed: true, - confidenceScore: 10, - matchedFactors: ['a'], - competingLinks: 1, - ))), + isNot( + equals( + InstallResponse( + installId: '1', + attributed: true, + confidenceScore: 10, + matchedFactors: ['a'], + competingLinks: 1, + ), + ), + ), ); }); }); diff --git a/test/network/network_manager_test.mocks.dart b/test/network/network_manager_test.mocks.dart index 7296d1a..78ca27f 100644 --- a/test/network/network_manager_test.mocks.dart +++ b/test/network/network_manager_test.mocks.dart @@ -3,6 +3,7 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes + import 'dart:async' as _i4; import 'dart:typed_data' as _i6; @@ -27,13 +28,8 @@ import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: invalid_use_of_internal_member class _FakeHttpResponse_0 extends _i1.SmartFake implements _i2.HttpResponse { - _FakeHttpResponse_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeHttpResponse_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } /// A class which mocks [HttpClient]. @@ -52,28 +48,23 @@ class MockHttpClient extends _i1.Mock implements _i3.HttpClient { Map? headers, }) => (super.noSuchMethod( - Invocation.method( - #execute, - [], - { - #url: url, - #method: method, - #body: body, - #headers: headers, - }, - ), - returnValue: _i4.Future<_i2.HttpResponse>.value(_FakeHttpResponse_0( - this, - Invocation.method( - #execute, - [], - { + Invocation.method(#execute, [], { #url: url, #method: method, #body: body, #headers: headers, - }, - ), - )), - ) as _i4.Future<_i2.HttpResponse>); + }), + returnValue: _i4.Future<_i2.HttpResponse>.value( + _FakeHttpResponse_0( + this, + Invocation.method(#execute, [], { + #url: url, + #method: method, + #body: body, + #headers: headers, + }), + ), + ), + ) + as _i4.Future<_i2.HttpResponse>); } diff --git a/test/storage/storage_manager_test.dart b/test/storage/storage_manager_test.dart index 965aa27..f4fd6e8 100644 --- a/test/storage/storage_manager_test.dart +++ b/test/storage/storage_manager_test.dart @@ -54,27 +54,30 @@ void main() { expect(result?.shortCode, 'abc'); }); - test('getInstallData restores the match certainty fields it saved', - () async { - String? saved; - when(mockPrefs.setString(StorageKeys.installData, any)) - .thenAnswer((invocation) async { - saved = invocation.positionalArguments[1] as String; - return true; - }); - const data = DeepLinkData( - shortCode: 'abc', - confidenceScore: 88, - matchedFactors: ['ip', 'ua'], - attributionMethod: 'fingerprint', - competingLinks: 1, - ); - - await storageManager.saveInstallData(data); - when(mockPrefs.getString(StorageKeys.installData)).thenReturn(saved); - - expect(storageManager.getInstallData(), equals(data)); - }); + test( + 'getInstallData restores the match certainty fields it saved', + () async { + String? saved; + when(mockPrefs.setString(StorageKeys.installData, any)).thenAnswer(( + invocation, + ) async { + saved = invocation.positionalArguments[1] as String; + return true; + }); + const data = DeepLinkData( + shortCode: 'abc', + confidenceScore: 88, + matchedFactors: ['ip', 'ua'], + attributionMethod: 'fingerprint', + competingLinks: 1, + ); + + await storageManager.saveInstallData(data); + when(mockPrefs.getString(StorageKeys.installData)).thenReturn(saved); + + expect(storageManager.getInstallData(), equals(data)); + }, + ); test('getInstallData decodes data saved without the certainty fields', () { when(mockPrefs.getString(StorageKeys.installData)).thenReturn( diff --git a/test/storage/storage_manager_test.mocks.dart b/test/storage/storage_manager_test.mocks.dart index f8bfce9..36d6292 100644 --- a/test/storage/storage_manager_test.mocks.dart +++ b/test/storage/storage_manager_test.mocks.dart @@ -3,6 +3,7 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes + import 'dart:async' as _i3; import 'package:linkforty_flutter/storage/storage_manager.dart' as _i2; @@ -33,55 +34,34 @@ class MockSharedPreferencesProtocol extends _i1.Mock } @override - _i3.Future setString( - String? key, - String? value, - ) => + _i3.Future setString(String? key, String? value) => (super.noSuchMethod( - Invocation.method( - #setString, - [ - key, - value, - ], - ), - returnValue: _i3.Future.value(false), - ) as _i3.Future); + Invocation.method(#setString, [key, value]), + returnValue: _i3.Future.value(false), + ) + as _i3.Future); @override - String? getString(String? key) => (super.noSuchMethod(Invocation.method( - #getString, - [key], - )) as String?); + String? getString(String? key) => + (super.noSuchMethod(Invocation.method(#getString, [key])) as String?); @override - _i3.Future setBool( - String? key, - bool? value, - ) => + _i3.Future setBool(String? key, bool? value) => (super.noSuchMethod( - Invocation.method( - #setBool, - [ - key, - value, - ], - ), - returnValue: _i3.Future.value(false), - ) as _i3.Future); + Invocation.method(#setBool, [key, value]), + returnValue: _i3.Future.value(false), + ) + as _i3.Future); @override - bool? getBool(String? key) => (super.noSuchMethod(Invocation.method( - #getBool, - [key], - )) as bool?); + bool? getBool(String? key) => + (super.noSuchMethod(Invocation.method(#getBool, [key])) as bool?); @override - _i3.Future remove(String? key) => (super.noSuchMethod( - Invocation.method( - #remove, - [key], - ), - returnValue: _i3.Future.value(false), - ) as _i3.Future); + _i3.Future remove(String? key) => + (super.noSuchMethod( + Invocation.method(#remove, [key]), + returnValue: _i3.Future.value(false), + ) + as _i3.Future); }