Merge branch 'master' into fork/dhituval/issue852/hide-diet-plan

This commit is contained in:
Roland Geider
2026-01-16 23:06:11 +01:00
88 changed files with 4421 additions and 753 deletions

View File

@@ -0,0 +1,107 @@
/*
* This file is part of wger Workout Manager <https://github.com/wger-project>.
* Copyright (c) 2020 - 2026 wger Team
*
* wger Workout Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:wger/core/exceptions/http_exception.dart';
void main() {
group('WgerHttpException', () {
test('parses valid JSON response', () {
// Arrange
final resp = http.Response(
'{"foo":"bar"}',
400,
headers: {HttpHeaders.contentTypeHeader: 'application/json'},
);
// Act
final ex = WgerHttpException(resp);
// Assert
expect(ex.type, ErrorType.json);
expect(ex.errors['foo'], 'bar');
expect(ex.toString(), contains('WgerHttpException'));
});
test('falls back on malformed JSON', () {
// Arrange
const body = '{"foo":';
final resp = http.Response(
body,
500,
headers: {HttpHeaders.contentTypeHeader: 'application/json'},
);
// Act
final ex = WgerHttpException(resp);
// Assert
expect(ex.type, ErrorType.json);
expect(ex.errors['unknown_error'], body);
});
test('detects HTML response from headers', () {
// Arrange
const body = '<html lang="en"><body>Error</body></html>';
final resp = http.Response(
body,
500,
headers: {HttpHeaders.contentTypeHeader: 'text/html; charset=utf-8'},
);
// Act
final ex = WgerHttpException(resp);
// Assert
expect(ex.type, ErrorType.html);
expect(ex.htmlError, body);
});
test('detects HTML response from content', () {
// Arrange
const body = '<html lang="en"><body>Error</body></html>';
final resp = http.Response(
body,
500,
headers: {HttpHeaders.contentTypeHeader: 'text/foo; charset=utf-8'},
);
// Act
final ex = WgerHttpException(resp);
// Assert
expect(ex.type, ErrorType.html);
expect(ex.htmlError, body);
});
test('fromMap sets errors and type', () {
// Arrange
final map = <String, dynamic>{'field': 'value'};
// Act
final ex = WgerHttpException.fromMap(map);
// Assert
expect(ex.type, ErrorType.json);
expect(ex.errors, map);
});
});
}

View File

@@ -1100,9 +1100,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i2.WgerBaseProvider {
as Uri);
@override
_i18.Future<dynamic> fetch(Uri? uri) =>
_i18.Future<dynamic> fetch(
Uri? uri, {
int? maxRetries = 3,
Duration? initialDelay = const Duration(milliseconds: 250),
}) =>
(super.noSuchMethod(
Invocation.method(#fetch, [uri]),
Invocation.method(
#fetch,
[uri],
{#maxRetries: maxRetries, #initialDelay: initialDelay},
),
returnValue: _i18.Future<dynamic>.value(),
)
as _i18.Future<dynamic>);

View File

@@ -20,6 +20,7 @@ import 'package:wger/l10n/generated/app_localizations.dart' as _i2;
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
// ignore_for_file: invalid_use_of_internal_member
/// A class which mocks [AppLocalizations].
///
@@ -919,6 +920,39 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations {
)
as String);
@override
String get impressionGood =>
(super.noSuchMethod(
Invocation.getter(#impressionGood),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#impressionGood),
),
)
as String);
@override
String get impressionNeutral =>
(super.noSuchMethod(
Invocation.getter(#impressionNeutral),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#impressionNeutral),
),
)
as String);
@override
String get impressionBad =>
(super.noSuchMethod(
Invocation.getter(#impressionBad),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#impressionBad),
),
)
as String);
@override
String get impression =>
(super.noSuchMethod(
@@ -1095,6 +1129,105 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations {
)
as String);
@override
String get gymModeTimerType =>
(super.noSuchMethod(
Invocation.getter(#gymModeTimerType),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#gymModeTimerType),
),
)
as String);
@override
String get gymModeTimerTypeHelText =>
(super.noSuchMethod(
Invocation.getter(#gymModeTimerTypeHelText),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#gymModeTimerTypeHelText),
),
)
as String);
@override
String get countdown =>
(super.noSuchMethod(
Invocation.getter(#countdown),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#countdown),
),
)
as String);
@override
String get stopwatch =>
(super.noSuchMethod(
Invocation.getter(#stopwatch),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#stopwatch),
),
)
as String);
@override
String get gymModeDefaultCountdownTime =>
(super.noSuchMethod(
Invocation.getter(#gymModeDefaultCountdownTime),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#gymModeDefaultCountdownTime),
),
)
as String);
@override
String get gymModeNotifyOnCountdownFinish =>
(super.noSuchMethod(
Invocation.getter(#gymModeNotifyOnCountdownFinish),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#gymModeNotifyOnCountdownFinish),
),
)
as String);
@override
String get duration =>
(super.noSuchMethod(
Invocation.getter(#duration),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#duration),
),
)
as String);
@override
String get volume =>
(super.noSuchMethod(
Invocation.getter(#volume),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#volume),
),
)
as String);
@override
String get workoutCompleted =>
(super.noSuchMethod(
Invocation.getter(#workoutCompleted),
returnValue: _i3.dummyValue<String>(
this,
Invocation.getter(#workoutCompleted),
),
)
as String);
@override
String get plateCalculator =>
(super.noSuchMethod(
@@ -3677,6 +3810,17 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations {
)
as String);
@override
String durationHoursMinutes(int? hours, int? minutes) =>
(super.noSuchMethod(
Invocation.method(#durationHoursMinutes, [hours, minutes]),
returnValue: _i3.dummyValue<String>(
this,
Invocation.method(#durationHoursMinutes, [hours, minutes]),
),
)
as String);
@override
String chartAllTimeTitle(String? name) =>
(super.noSuchMethod(
@@ -3765,6 +3909,17 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations {
)
as String);
@override
String formMinMaxValues(int? min, int? max) =>
(super.noSuchMethod(
Invocation.method(#formMinMaxValues, [min, max]),
returnValue: _i3.dummyValue<String>(
this,
Invocation.method(#formMinMaxValues, [min, max]),
),
)
as String);
@override
String enterMinCharacters(String? min) =>
(super.noSuchMethod(