Skip to content

Commit

Permalink
Increasing Unit Test Coverage and adding Firebase Analytics and Crash…
Browse files Browse the repository at this point in the history
…lytics (#169)

* test: Added tests for api service

* feat: Added Firebase analytics and crashlytics

* feat: Added environment variables for sensitive info

* Create .env
  • Loading branch information
buildwithmalik authored Sep 5, 2022
1 parent e5c3051 commit 5fab0be
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 33 deletions.
7 changes: 7 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiKey=
appId=
messagingSenderId=
projectId=
storageBucket=
iosClientId=
iosBundleId=
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
.buildlog/
.history
.svn/
*.env

# IntelliJ related
*.iml
Expand Down Expand Up @@ -42,3 +43,9 @@ app.*.map.json

# Exceptions to above rules.
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

# Firebase
android/app/google-services.json
ios/firebase_app_id_file.json
ios/Runner/GoogleService-Info.plist

70 changes: 70 additions & 0 deletions lib/firebase_options.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// File generated by FlutterFire CLI.
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
import 'package:flutter_dotenv/flutter_dotenv.dart';

/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for web - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for macos - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}

static FirebaseOptions android = FirebaseOptions(
apiKey: dotenv.env['apiKey'] ?? "",
appId: dotenv.env['appId'] ?? "",
messagingSenderId: dotenv.env['messagingSenderId'] ?? "",
projectId: dotenv.env['projectId'] ?? "",
storageBucket: dotenv.env['storageBucket'] ?? "",
);

static FirebaseOptions ios = FirebaseOptions(
apiKey: dotenv.env['apiKey'] ?? "",
appId: dotenv.env['appId'] ?? "",
messagingSenderId: dotenv.env['messagingSenderId'] ?? "",
projectId: dotenv.env['projectId'] ?? "",
storageBucket: dotenv.env['storageBucket'] ?? "",
iosClientId: dotenv.env['iosClientId'] ?? "",
iosBundleId: dotenv.env['iosBundleId'] ?? "",
);
}
46 changes: 33 additions & 13 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// ignore_for_file: import_of_legacy_library_into_null_safe

import 'dart:async';

import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:hive/hive.dart';
import 'package:injectable/injectable.dart';
import 'package:path_provider/path_provider.dart';
Expand All @@ -11,23 +15,39 @@ import 'package:rutorrentflutter/services/state_services/user_preferences_servic
import 'package:rutorrentflutter/theme/app_state_notifier.dart';
import 'package:rutorrentflutter/theme/app_theme.dart';
import 'package:rutorrentflutter/ui/widgets/smart_widgets/bottom_sheets/bottom_sheet_setup.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();
//Setting up Hive DB
final appDir = await getApplicationDocumentsDirectory();
Hive.init(appDir.path);
await Hive.openBox('DB');
//To work in development environment, simply change the environment to Environment.dev below
setupLocator(environment: Environment.prod);
//Setting custom Bottom Sheet
setUpBottomSheetUi();
//Setting up Services
locator<NotificationService>().init();
await locator<UserPreferencesService>().init();
runApp(MyApp());
//Zone guarded for Firebase Crashlytics to catch errors
runZonedGuarded<Future<void>>(() async {
WidgetsFlutterBinding.ensureInitialized();
//Setting up Hive DB
final appDir = await getApplicationDocumentsDirectory();
Hive.init(appDir.path);
await Hive.openBox('DB');
//To work in development environment, simply change the environment to Environment.dev below
setupLocator(environment: Environment.prod);
//Setting custom Bottom Sheet
setUpBottomSheetUi();
//Setting up Services
locator<NotificationService>().init();
await locator<UserPreferencesService>().init();
//Setting up Firebase
await dotenv.load(fileName: ".env");
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);

// Make sure to comment out this line in development to see Errors
// FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;

runApp(MyApp());
},
(error, stack) =>
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true));
}

class MyApp extends StatelessWidget {
Expand Down
63 changes: 63 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,62 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
firebase_analytics:
dependency: "direct main"
description:
name: firebase_analytics
url: "https://pub.dartlang.org"
source: hosted
version: "9.3.3"
firebase_analytics_platform_interface:
dependency: transitive
description:
name: firebase_analytics_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.3"
firebase_analytics_web:
dependency: transitive
description:
name: firebase_analytics_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2+3"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
url: "https://pub.dartlang.org"
source: hosted
version: "1.21.1"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.5.1"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.2"
firebase_crashlytics:
dependency: "direct main"
description:
name: firebase_crashlytics
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.9"
firebase_crashlytics_platform_interface:
dependency: transitive
description:
name: firebase_crashlytics_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.15"
fixnum:
dependency: transitive
description:
Expand Down Expand Up @@ -272,6 +328,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_dotenv:
dependency: "direct main"
description:
name: flutter_dotenv
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.2"
flutter_launcher_icons:
dependency: "direct dev"
description:
Expand Down
7 changes: 6 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: rutorrentflutter
description: A rutorrent-based client in flutter

publish_to: "none"
version: 1.0.0-alpha+4
version: 1.0.0-alpha+6

environment:
sdk: ">=2.12.0-0 <3.0.0"
Expand Down Expand Up @@ -45,6 +45,10 @@ dependencies:
webview_flutter_plus: ^0.3.0+2
percent_indicator: ^4.2.2
logger:
firebase_core: ^1.21.1
firebase_analytics: ^9.3.3
firebase_crashlytics: ^2.8.9
flutter_dotenv: ^5.0.2
# webviewx: ^0.2.1

dev_dependencies:
Expand All @@ -66,6 +70,7 @@ flutter:
assets:
- assets/logo/
- assets/animation/
- .env

fonts:
- family: SFUIDisplay
Expand Down
43 changes: 24 additions & 19 deletions test/helpers/mock_ioclient.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:convert';

import 'package:http/http.dart';
import 'package:logger/logger.dart';
import 'package:rutorrentflutter/app/app.logger.dart';
Expand All @@ -11,26 +10,37 @@ Logger log = getLogger("MockIOClientExtention");
/// The [MockIOClientExtention] class helps in mocking API calls
/// and returning the proper response.
class MockIOClientExtention extends MockIOClient {
@override
post(Uri? url,
{Map<String, String>? headers, Object? body, Encoding? encoding}) async {
log.e(url.toString());
log.e(TestData.historyPluginUrl);
log.e(TestData.diskSpacePluginUrl);
log.e(headers);
log.e(body);

switch (url.toString()) {
case (TestData.historyPluginUrl):
return Response(TestData.updateHistoryJSONReponse, 200);

case (TestData.httpRpcPluginUrl):
log.e(body, TestData.getAllAccountsTorrentListBody);
log.e(body.toString() ==
TestData.getAllAccountsTorrentListBody.toString());
return body.toString() ==
TestData.getAllAccountsTorrentListBody.toString()
? Response(TestData.getAllAccountsTorrentListResponse, 200)
: Response("", 404);
if (body.toString() ==
TestData.getAllAccountsTorrentListBody.toString())
return Response(TestData.getAllAccountsTorrentListResponse, 200);
else if (body.toString() == TestData.getFilesBody.toString())
return Response(jsonEncode(TestData.getFilesResponse), 200);
else if (body.toString() == TestData.getTrackersBody.toString())
return Response(jsonEncode(TestData.getTrackersResponse), 200);

return Response("", 404);

case (TestData.explorerPluginUrl):
if (body.toString() == TestData.getDiskFilesBody.toString())
return Response(TestData.getDiskFilesResponse.toString(), 200);

return Response("", 404);

case (TestData.rssPluginUrl):
if (body == null)
return Response(jsonEncode(TestData.loadRSSResponse), 200);
else if (body.toString() == TestData.getRSSFiltersBody.toString())
return Response(jsonEncode(TestData.getRSSFiltersResponse), 200);

return Response("", 404);

case "":
return Response("", 200);
Expand All @@ -42,11 +52,6 @@ class MockIOClientExtention extends MockIOClient {

@override
Future<Response> get(Uri? url, {Map<String, String>? headers}) async {
log.e(url.toString());
log.e(TestData.historyPluginUrl);
log.e(TestData.diskSpacePluginUrl);
log.e(headers);

switch (url.toString()) {
case (TestData.diskSpacePluginUrl):
return Response(TestData.updateDiskSpaceResponse, 200);
Expand Down
3 changes: 3 additions & 0 deletions test/helpers/test_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
import 'package:flutter/foundation.dart';
import 'package:rutorrentflutter/models/account.dart';
import 'package:rutorrentflutter/models/history_item.dart';
import 'package:rutorrentflutter/models/rss_filter.dart';
import 'package:rutorrentflutter/models/torrent.dart';
import 'package:rutorrentflutter/services/services_info.dart';

/// This class contains the test data used in tests to remove non-deterministic behaviour
class TestData {
static const url = "http://localhost:8080";
static const String hash = "EB25F7EC8FDE4DA888C197DB0975FFF549C9D7FB";

static ValueNotifier<List<Account>> accounts = ValueNotifier([
Account(username: "test", password: "test", url: "http://localhost:8080")
Expand All @@ -24,6 +26,7 @@ class TestData {
];

static Torrent get torrent => Torrent("dddd");
static RSSFilter get rssFilter => RSSFilter("", 0, "", "", "", "");

static const httpRpcPluginUrl = url + '/plugins/httprpc/action.php';

Expand Down
Loading

0 comments on commit 5fab0be

Please sign in to comment.