Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increasing Unit Test Coverage and adding Firebase Analytics and Crashlytics #169

Merged
merged 4 commits into from
Sep 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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