mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Add some tests
This commit is contained in:
@@ -13,11 +13,12 @@ const DEFAULT_LB_PLATES = [2.5, 5, 10, 25, 35, 45];
|
||||
|
||||
const PREFS_KEY_PLATES = 'selectedPlates';
|
||||
|
||||
final plateWeightsProvider = StateNotifierProvider<PlateWeightsNotifier, PlateWeightsState>((ref) {
|
||||
return PlateWeightsNotifier();
|
||||
final plateCalculatorProvider =
|
||||
StateNotifierProvider<PlateCalculatorNotifier, PlateCalculatorState>((ref) {
|
||||
return PlateCalculatorNotifier();
|
||||
});
|
||||
|
||||
class PlateWeightsState {
|
||||
class PlateCalculatorState {
|
||||
final _logger = Logger('PlateWeightsState');
|
||||
|
||||
final barWeightKg = 20;
|
||||
@@ -53,7 +54,7 @@ class PlateWeightsState {
|
||||
final List<num> availablePlatesKg = const [0.5, 1, 1.25, 2, 2.5, 5, 10, 15, 20, 25];
|
||||
final List<num> availablePlatesLb = const [2.5, 5, 10, 25, 35, 45];
|
||||
|
||||
PlateWeightsState({
|
||||
PlateCalculatorState({
|
||||
this.isMetric = true,
|
||||
this.totalWeight = 0,
|
||||
List<num>? selectedPlates,
|
||||
@@ -90,12 +91,12 @@ class PlateWeightsState {
|
||||
return {'isMetric': isMetric, 'selectedPlates': selectedPlates};
|
||||
}
|
||||
|
||||
PlateWeightsState copyWith({
|
||||
PlateCalculatorState copyWith({
|
||||
bool? isMetric,
|
||||
num? totalWeight,
|
||||
List<num>? selectedPlates,
|
||||
}) {
|
||||
return PlateWeightsState(
|
||||
return PlateCalculatorState(
|
||||
isMetric: isMetric ?? this.isMetric,
|
||||
totalWeight: totalWeight ?? this.totalWeight,
|
||||
selectedPlates: selectedPlates ?? this.selectedPlates,
|
||||
@@ -103,21 +104,23 @@ class PlateWeightsState {
|
||||
}
|
||||
}
|
||||
|
||||
class PlateWeightsNotifier extends StateNotifier<PlateWeightsState> {
|
||||
final _logger = Logger('PlateWeightsNotifier');
|
||||
class PlateCalculatorNotifier extends StateNotifier<PlateCalculatorState> {
|
||||
final _logger = Logger('PlateCalculatorNotifier');
|
||||
|
||||
late SharedPreferencesAsync prefs;
|
||||
|
||||
PlateWeightsNotifier({SharedPreferencesAsync? prefs}) : super(PlateWeightsState()) {
|
||||
PlateCalculatorNotifier({SharedPreferencesAsync? prefs}) : super(PlateCalculatorState()) {
|
||||
this.prefs = prefs ?? PreferenceHelper.asyncPref;
|
||||
_readDataFromSharedPrefs();
|
||||
}
|
||||
|
||||
Future<void> saveToSharedPrefs() async {
|
||||
_logger.fine('Saving plate data to SharedPreferences');
|
||||
await prefs.setString(PREFS_KEY_PLATES, jsonEncode(state.toJson()));
|
||||
}
|
||||
|
||||
Future<void> _readDataFromSharedPrefs() async {
|
||||
_logger.fine('Reading plate data from SharedPreferences');
|
||||
final prefsData = await prefs.getString(PREFS_KEY_PLATES);
|
||||
|
||||
if (prefsData != null) {
|
||||
|
||||
@@ -22,7 +22,7 @@ class _AddPlateWeightsState extends ConsumerState<AddPlateWeights>
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(plateWeightsProvider.notifier);
|
||||
ref.read(plateCalculatorProvider.notifier);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ class _AddPlateWeightsState extends ConsumerState<AddPlateWeights>
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = AppLocalizations.of(context);
|
||||
|
||||
final plateWeightsState = ref.watch(plateWeightsProvider);
|
||||
final plateWeightsNotifier = ref.read(plateWeightsProvider.notifier);
|
||||
final plateWeightsState = ref.watch(plateCalculatorProvider);
|
||||
final plateWeightsNotifier = ref.read(plateCalculatorProvider.notifier);
|
||||
final userProvider = provider.Provider.of<UserProvider>(context);
|
||||
|
||||
return Scaffold(
|
||||
|
||||
@@ -166,7 +166,7 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
setState(() {
|
||||
widget._log.weight = newValue;
|
||||
_weightController.text = newValue.toString();
|
||||
ref.read(plateWeightsProvider.notifier).setWeight(
|
||||
ref.read(plateCalculatorProvider.notifier).setWeight(
|
||||
_weightController.text == '' ? 0 : double.parse(_weightController.text),
|
||||
);
|
||||
});
|
||||
@@ -189,7 +189,7 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
num.parse(value);
|
||||
setState(() {
|
||||
widget._log.weight = num.parse(value);
|
||||
ref.read(plateWeightsProvider.notifier).setWeight(
|
||||
ref.read(plateCalculatorProvider.notifier).setWeight(
|
||||
_weightController.text == '' ? 0 : double.parse(_weightController.text),
|
||||
);
|
||||
});
|
||||
@@ -218,7 +218,7 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
setState(() {
|
||||
widget._log.weight = newValue;
|
||||
_weightController.text = newValue.toString();
|
||||
ref.read(plateWeightsProvider.notifier).setWeight(
|
||||
ref.read(plateCalculatorProvider.notifier).setWeight(
|
||||
_weightController.text == '' ? 0 : double.parse(_weightController.text),
|
||||
);
|
||||
});
|
||||
@@ -379,7 +379,7 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
}
|
||||
|
||||
Widget getPlates() {
|
||||
final plateWeightsState = ref.watch(plateWeightsProvider);
|
||||
final plateWeightsState = ref.watch(plateCalculatorProvider);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
@@ -414,7 +414,7 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
size: 37,
|
||||
padding: 2,
|
||||
margin: 0,
|
||||
color: ref.read(plateWeightsProvider).getColor(entry.key),
|
||||
color: ref.read(plateCalculatorProvider).getColor(entry.key),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
],
|
||||
|
||||
108
test/providers/plate_calculator_test.dart
Normal file
108
test/providers/plate_calculator_test.dart
Normal file
@@ -0,0 +1,108 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart'; // Added for annotations
|
||||
import 'package:mockito/mockito.dart'; // Added for mockito
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:wger/helpers/consts.dart';
|
||||
import 'package:wger/providers/plate_weights.dart';
|
||||
|
||||
import 'plate_calculator_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([SharedPreferencesAsync])
|
||||
void main() {
|
||||
group('PlateWeightsNotifier', () {
|
||||
late PlateCalculatorNotifier notifier;
|
||||
late MockSharedPreferencesAsync mockPrefs;
|
||||
|
||||
setUp(() {
|
||||
mockPrefs = MockSharedPreferencesAsync();
|
||||
when(mockPrefs.getString(PREFS_KEY_PLATES)).thenAnswer((_) async => null);
|
||||
when(mockPrefs.setString(any, any)).thenAnswer((_) async => true);
|
||||
|
||||
notifier = PlateCalculatorNotifier(prefs: mockPrefs);
|
||||
});
|
||||
|
||||
test('toggleSelection adds and removes plates', () async {
|
||||
// Test adding a plate
|
||||
await notifier.toggleSelection(0.5);
|
||||
expect(notifier.state.selectedPlates.contains(0.5), true);
|
||||
|
||||
// Test removing a plate
|
||||
await notifier.toggleSelection(0.5);
|
||||
expect(notifier.state.selectedPlates.contains(0.5), false);
|
||||
});
|
||||
|
||||
test('unitChange updates state correctly', () {
|
||||
// Change to imperial
|
||||
notifier.setWeight(123);
|
||||
notifier.unitChange(unit: WeightUnitEnum.lb);
|
||||
expect(notifier.state.isMetric, false);
|
||||
expect(notifier.state.totalWeight, 0);
|
||||
expect(notifier.state.selectedPlates, DEFAULT_LB_PLATES);
|
||||
expect(notifier.state.barWeight, notifier.state.barWeightLb);
|
||||
expect(notifier.state.availablePlates, notifier.state.availablePlatesLb);
|
||||
|
||||
// Change back to metric
|
||||
notifier.setWeight(123);
|
||||
notifier.unitChange(unit: WeightUnitEnum.kg);
|
||||
expect(notifier.state.isMetric, true);
|
||||
expect(notifier.state.totalWeight, 0);
|
||||
expect(notifier.state.selectedPlates, DEFAULT_KG_PLATES);
|
||||
expect(notifier.state.barWeight, notifier.state.barWeightKg);
|
||||
expect(notifier.state.availablePlates, notifier.state.availablePlatesKg);
|
||||
});
|
||||
|
||||
test('setWeight updates totalWeight', () {
|
||||
notifier.setWeight(100);
|
||||
expect(notifier.state.totalWeight, 100);
|
||||
});
|
||||
});
|
||||
|
||||
group('PlateWeightsState', () {
|
||||
test('copyWith creates a new instance with updated values', () {
|
||||
final initialState = PlateCalculatorState();
|
||||
final updatedState = initialState.copyWith(
|
||||
isMetric: false,
|
||||
totalWeight: 100,
|
||||
selectedPlates: [1, 2, 3],
|
||||
);
|
||||
|
||||
expect(updatedState.isMetric, false);
|
||||
expect(updatedState.totalWeight, 100);
|
||||
expect(updatedState.selectedPlates, [1, 2, 3]);
|
||||
});
|
||||
|
||||
test('toJson returns correct map', () {
|
||||
final state = PlateCalculatorState(isMetric: false, selectedPlates: [10, 20]);
|
||||
final json = state.toJson();
|
||||
expect(json['isMetric'], false);
|
||||
expect(json['selectedPlates'], [10, 20]);
|
||||
});
|
||||
|
||||
test('barWeight returns correct value based on isMetric', () {
|
||||
final metricState = PlateCalculatorState(isMetric: true);
|
||||
expect(metricState.barWeight, metricState.barWeightKg);
|
||||
|
||||
final imperialState = PlateCalculatorState(isMetric: false);
|
||||
expect(imperialState.barWeight, imperialState.barWeightLb);
|
||||
});
|
||||
|
||||
test('availablePlates returns correct list based on isMetric', () {
|
||||
final metricState = PlateCalculatorState(isMetric: true);
|
||||
expect(metricState.availablePlates, metricState.availablePlatesKg);
|
||||
|
||||
final imperialState = PlateCalculatorState(isMetric: false);
|
||||
expect(imperialState.availablePlates, metricState.availablePlatesLb);
|
||||
});
|
||||
|
||||
test('getColor returns correct color', () {
|
||||
final metricState = PlateCalculatorState(isMetric: true);
|
||||
expect(metricState.getColor(20), Colors.blue);
|
||||
expect(metricState.getColor(0.1), Colors.grey, reason: 'Fallback color');
|
||||
|
||||
final imperialState = PlateCalculatorState(isMetric: false);
|
||||
expect(imperialState.getColor(45), Colors.blue);
|
||||
expect(imperialState.getColor(0.1), Colors.grey, reason: 'Fallback color');
|
||||
});
|
||||
});
|
||||
}
|
||||
213
test/providers/plate_calculator_test.mocks.dart
Normal file
213
test/providers/plate_calculator_test.mocks.dart
Normal file
@@ -0,0 +1,213 @@
|
||||
// Mocks generated by Mockito 5.4.6 from annotations
|
||||
// in wger/test/providers/plate_weights_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i3;
|
||||
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
import 'package:shared_preferences/src/shared_preferences_async.dart' as _i2;
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: avoid_redundant_argument_values
|
||||
// ignore_for_file: avoid_setters_without_getters
|
||||
// ignore_for_file: comment_references
|
||||
// ignore_for_file: deprecated_member_use
|
||||
// ignore_for_file: deprecated_member_use_from_same_package
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||
// ignore_for_file: must_be_immutable
|
||||
// ignore_for_file: prefer_const_constructors
|
||||
// ignore_for_file: unnecessary_parenthesis
|
||||
// ignore_for_file: camel_case_types
|
||||
// ignore_for_file: subtype_of_sealed_class
|
||||
|
||||
/// A class which mocks [SharedPreferencesAsync].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
// ignore: must_be_immutable
|
||||
class MockSharedPreferencesAsync extends _i1.Mock implements _i2.SharedPreferencesAsync {
|
||||
MockSharedPreferencesAsync() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_i3.Future<Set<String>> getKeys({Set<String>? allowList}) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getKeys,
|
||||
[],
|
||||
{#allowList: allowList},
|
||||
),
|
||||
returnValue: _i3.Future<Set<String>>.value(<String>{}),
|
||||
) as _i3.Future<Set<String>>);
|
||||
|
||||
@override
|
||||
_i3.Future<Map<String, Object?>> getAll({Set<String>? allowList}) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getAll,
|
||||
[],
|
||||
{#allowList: allowList},
|
||||
),
|
||||
returnValue: _i3.Future<Map<String, Object?>>.value(<String, Object?>{}),
|
||||
) as _i3.Future<Map<String, Object?>>);
|
||||
|
||||
@override
|
||||
_i3.Future<bool?> getBool(String? key) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getBool,
|
||||
[key],
|
||||
),
|
||||
returnValue: _i3.Future<bool?>.value(),
|
||||
) as _i3.Future<bool?>);
|
||||
|
||||
@override
|
||||
_i3.Future<int?> getInt(String? key) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getInt,
|
||||
[key],
|
||||
),
|
||||
returnValue: _i3.Future<int?>.value(),
|
||||
) as _i3.Future<int?>);
|
||||
|
||||
@override
|
||||
_i3.Future<double?> getDouble(String? key) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getDouble,
|
||||
[key],
|
||||
),
|
||||
returnValue: _i3.Future<double?>.value(),
|
||||
) as _i3.Future<double?>);
|
||||
|
||||
@override
|
||||
_i3.Future<String?> getString(String? key) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getString,
|
||||
[key],
|
||||
),
|
||||
returnValue: _i3.Future<String?>.value(),
|
||||
) as _i3.Future<String?>);
|
||||
|
||||
@override
|
||||
_i3.Future<List<String>?> getStringList(String? key) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getStringList,
|
||||
[key],
|
||||
),
|
||||
returnValue: _i3.Future<List<String>?>.value(),
|
||||
) as _i3.Future<List<String>?>);
|
||||
|
||||
@override
|
||||
_i3.Future<bool> containsKey(String? key) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#containsKey,
|
||||
[key],
|
||||
),
|
||||
returnValue: _i3.Future<bool>.value(false),
|
||||
) as _i3.Future<bool>);
|
||||
|
||||
@override
|
||||
_i3.Future<void> setBool(
|
||||
String? key,
|
||||
bool? value,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#setBool,
|
||||
[
|
||||
key,
|
||||
value,
|
||||
],
|
||||
),
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
|
||||
@override
|
||||
_i3.Future<void> setInt(
|
||||
String? key,
|
||||
int? value,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#setInt,
|
||||
[
|
||||
key,
|
||||
value,
|
||||
],
|
||||
),
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
|
||||
@override
|
||||
_i3.Future<void> setDouble(
|
||||
String? key,
|
||||
double? value,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#setDouble,
|
||||
[
|
||||
key,
|
||||
value,
|
||||
],
|
||||
),
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
|
||||
@override
|
||||
_i3.Future<void> setString(
|
||||
String? key,
|
||||
String? value,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#setString,
|
||||
[
|
||||
key,
|
||||
value,
|
||||
],
|
||||
),
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
|
||||
@override
|
||||
_i3.Future<void> setStringList(
|
||||
String? key,
|
||||
List<String>? value,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#setStringList,
|
||||
[
|
||||
key,
|
||||
value,
|
||||
],
|
||||
),
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
|
||||
@override
|
||||
_i3.Future<void> remove(String? key) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#remove,
|
||||
[key],
|
||||
),
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
|
||||
@override
|
||||
_i3.Future<void> clear({Set<String>? allowList}) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#clear,
|
||||
[],
|
||||
{#allowList: allowList},
|
||||
),
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
}
|
||||
Reference in New Issue
Block a user