diff --git a/lib/providers/input_provider.dart b/lib/providers/input_provider.dart index b8aed63..01ab835 100644 --- a/lib/providers/input_provider.dart +++ b/lib/providers/input_provider.dart @@ -22,7 +22,9 @@ class InputProvider extends ChangeNotifier { TextEditingController get textController => _textController; set sliderValue(double newValue) { - _sliderValue = newValue; + if (_sliderValue > 0 && _sliderValue < 100) { + _sliderValue = newValue; + } notifyListeners(); } diff --git a/lib/services/date_service.dart b/lib/services/date_service.dart index 79bdd37..e4a9617 100644 --- a/lib/services/date_service.dart +++ b/lib/services/date_service.dart @@ -3,7 +3,7 @@ import 'package:timezone/timezone.dart'; import 'pages_service.dart'; -const int trainingTime = 40; +const int trainingTime = 6 * 7; const weekDays = { "Montag": 1, diff --git a/lib/utils/timer_util.dart b/lib/utils/timer_util.dart index 57b9f9c..9fba645 100644 --- a/lib/utils/timer_util.dart +++ b/lib/utils/timer_util.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; String formatTime(int seconds) { + if (seconds < 0) { + return '00:00'; + } Duration duration = Duration(seconds: seconds); String formattedTime = ''; String twoDigits(int n) => n.toString().padLeft(2, "0"); @@ -9,7 +12,7 @@ String formatTime(int seconds) { String minutes = twoDigits(duration.inMinutes.remainder(60)); String formattedSeconds = twoDigits(duration.inSeconds.remainder(60)); if (duration.inDays != 0) { - formattedTime += '$days Tag ${duration.inDays > 1 ? "e" : ""}, '; + formattedTime += '$days Tag${duration.inDays > 1 ? "e" : ""}, '; } if (duration.inHours != 0) formattedTime += '$hours:'; formattedTime += '$minutes:'; diff --git a/test/unit_tests/date_service_test.dart b/test/unit_tests/date_service_test.dart new file mode 100644 index 0000000..9afba5e --- /dev/null +++ b/test/unit_tests/date_service_test.dart @@ -0,0 +1,37 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:timezone/data/latest.dart' as tz; +import 'package:smoke_cess_app/services/date_service.dart'; +import 'package:timezone/timezone.dart'; + +void main() { + tz.initializeTimeZones(); + test('IsSameDay: false', () { + bool result = + isSameDay(DateTime.now(), DateTime.now().add(const Duration(days: 1))); + expect(result, false); + }); + test('IsSameDay: true', () { + bool result = isSameDay(DateTime.now(), DateTime.now()); + expect(result, true); + }); + test('CreateTZDateTimes: all the same days as today in next 6 weeks at 23:59', + () { + List selectedDays = [ + weekDays.keys.elementAt(DateTime.now().weekday - 1) + ]; + List expected = []; + DateTime now = DateTime.now(); + final Duration offset = now.timeZoneOffset; + final DateTime date = + DateTime(now.year, now.month, now.day, 23, 59, 0, 0, 0); + for (int i = 0; i <= trainingTime; i = i + 7) { + expected.add( + TZDateTime.local(date.year, date.month, date.day, 23, 59, 0, 0, 0) + .add(Duration(days: i)) + // subtract offset since TZDateTime uses the UTC Timezone + .subtract(offset)); + } + List result = createTZDateTimes(selectedDays, 23, 59); + expect(result, expected); + }); +} diff --git a/test/unit_tests/timer_util_test.dart b/test/unit_tests/timer_util_test.dart new file mode 100644 index 0000000..50fe28f --- /dev/null +++ b/test/unit_tests/timer_util_test.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:smoke_cess_app/utils/timer_util.dart'; + +void main() { + test('FormatTime: Seconds', () { + String result = formatTime(1); + expect(result, '00:01'); + }); + test('FormatTime: Minutes', () { + String result = formatTime(61); + expect(result, '01:01'); + }); + test('FormatTime: Hours', () { + String result = formatTime(3661); + expect(result, '01:01:01'); + }); + test('FormatTime: Day', () { + String result = formatTime(90061); + expect(result, '1 Tag, 01:01:01'); + }); + test('FormatTime: Days', () { + String result = formatTime(176461); + expect(result, '2 Tage, 01:01:01'); + }); + test('FormatTime: Negativ Value', () { + String result = formatTime(-1); + expect(result, '00:00'); + }); + + test('DurationBetween: 0', () { + TimeOfDay start = const TimeOfDay(hour: 12, minute: 0); + TimeOfDay end = const TimeOfDay(hour: 12, minute: 0); + TimeOfDay result = start.durationBetween(end); + expect(result, const TimeOfDay(hour: 0, minute: 0)); + }); + test('DurationBetween: 23h 59min', () { + TimeOfDay start = const TimeOfDay(hour: 0, minute: 0); + TimeOfDay end = const TimeOfDay(hour: 23, minute: 59); + TimeOfDay result = start.durationBetween(end); + expect(result, const TimeOfDay(hour: 23, minute: 59)); + }); + test('DurationBetween: 12h 34min', () { + TimeOfDay start = const TimeOfDay(hour: 2, minute: 12); + TimeOfDay end = const TimeOfDay(hour: 14, minute: 46); + TimeOfDay result = start.durationBetween(end); + expect(result, const TimeOfDay(hour: 12, minute: 34)); + }); +} diff --git a/test/widget_tests/widget_entry_detail_test.dart b/test/widget_tests/widget_entry_detail_test.dart new file mode 100644 index 0000000..0eed669 --- /dev/null +++ b/test/widget_tests/widget_entry_detail_test.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:smoke_cess_app/widgets/entry_detail_widget.dart'; + +void main() { + initializeDateFormatting('de'); + testWidgets('Entry Detail should use ExpansionTile if Comments is set', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: EntryDetail( + date: DateTime.now(), + entryComment: 'A comment', + entryData: 'Test', + iconData: Icons.plus_one, + ), + )), + ); + + expect(find.byType(ExpansionTile), findsOneWidget); + }); + + testWidgets('Entry Detail should use ListTile if Comments is null', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: EntryDetail( + date: DateTime.now(), + entryComment: 'A comment', + entryData: 'Test', + iconData: Icons.plus_one, + ), + )), + ); + + expect(find.byType(ListTile), findsOneWidget); + }); +} diff --git a/test/widget_tests/widget_slider_test.dart b/test/widget_tests/widget_slider_test.dart new file mode 100644 index 0000000..1dc470d --- /dev/null +++ b/test/widget_tests/widget_slider_test.dart @@ -0,0 +1,117 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; +import 'package:smoke_cess_app/widgets/slider.dart'; + +void main() { + testWidgets('Slider starts at 50', (WidgetTester tester) async { + // Create an instance of the InputProvider and add it to the widget tree + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + // Verify that the Slider displays 50 + expect(find.text('50'), findsOneWidget); + }); + + testWidgets('Slider puts 51 after Tap on plus in InputProvider', + (WidgetTester tester) async { + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + await tester.tap(find.byIcon(Icons.add_outlined)); + await tester.pump(); + + expect(inputProvider.sliderValue, equals(51)); + }); + + testWidgets('Slider puts 49 after Tap on subtract in InputProvider', + (WidgetTester tester) async { + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + await tester.tap(find.byIcon(Icons.remove_outlined)); + await tester.pump(); + + expect(inputProvider.sliderValue, equals(49)); + }); + + testWidgets('Slider doesnt go higher than 100', (WidgetTester tester) async { + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + for (int i = 0; i < 100; i++) { + await tester.tap(find.byIcon(Icons.add_outlined)); + await tester.pump(); + } + + expect(inputProvider.sliderValue, equals(100)); + }); + + testWidgets('Slider doesnt go lower than 0', (WidgetTester tester) async { + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MySlider(), + ), + ), + ), + ); + + for (int i = 0; i < 100; i++) { + await tester.tap(find.byIcon(Icons.remove_outlined)); + await tester.pump(); + } + + expect(inputProvider.sliderValue, equals(0)); + }); +} diff --git a/test/widget_tests/widget_text_formfield_test.dart b/test/widget_tests/widget_text_formfield_test.dart new file mode 100644 index 0000000..84aa134 --- /dev/null +++ b/test/widget_tests/widget_text_formfield_test.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:provider/provider.dart'; +import 'package:smoke_cess_app/providers/input_provider.dart'; +import 'package:smoke_cess_app/widgets/text_formfield.dart'; + +void main() { + testWidgets('TextFormField initial Value is correct', + (WidgetTester tester) async { + const String testText = 'Its a test'; + // Create an instance of the InputProvider and add it to the widget tree + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MyTextFormField(testText), + ), + ), + ), + ); + + // Verify that the Slider displays 50 + expect(find.text(testText), findsOneWidget); + }); + + testWidgets('TextFormField inputs correctly to Provider', + (WidgetTester tester) async { + const String testText = 'Its a test'; + // Create an instance of the InputProvider and add it to the widget tree + final inputProvider = InputProvider(); + await tester.pumpWidget( + MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: inputProvider), + ], + child: const MaterialApp( + home: Scaffold( + body: MyTextFormField(testText), + ), + ), + ), + ); + + await tester.enterText(find.byType(TextField), testText); + expect(inputProvider.textController.text, testText); + }); +}