forked from eatvio/eatvio_app
286 lines
9.0 KiB
Dart
286 lines
9.0 KiB
Dart
import 'package:eatvio_app/features/insights/domain/insights_text_builder.dart';
|
||
import 'package:eatvio_app/features/insights/models/insights_period.dart';
|
||
import 'package:eatvio_app/features/profile/models/circumference_model.dart';
|
||
import 'package:eatvio_app/features/profile/models/weight_model.dart';
|
||
import 'package:eatvio_app/generated/l10n.dart';
|
||
import 'package:flutter/widgets.dart';
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
|
||
WeightModel _weight(double weight, {double? bmi, int day = 1}) {
|
||
final date = DateTime(2026, 11, day, 12);
|
||
return WeightModel(
|
||
id: day,
|
||
userId: 1,
|
||
weight: weight,
|
||
createdAt: date,
|
||
updatedAt: date,
|
||
bmi: bmi,
|
||
);
|
||
}
|
||
|
||
CircumferenceModel _circumference({
|
||
double waist = 80,
|
||
double chest = 95,
|
||
double hips = 100,
|
||
int day = 1,
|
||
}) {
|
||
final date = DateTime(2026, 11, day, 12);
|
||
return CircumferenceModel(
|
||
id: day,
|
||
userId: 1,
|
||
chestCircumference: chest,
|
||
waistCircumference: waist,
|
||
hipCircumference: hips,
|
||
createdAt: date,
|
||
updatedAt: date,
|
||
);
|
||
}
|
||
|
||
void main() {
|
||
late InsightsTextBuilder builder;
|
||
|
||
setUpAll(() async {
|
||
final s = await S.load(const Locale('ru'));
|
||
builder = InsightsTextBuilder(s);
|
||
});
|
||
|
||
group('форматирование', () {
|
||
test('formatNumber: один знак без хвостового нуля', () {
|
||
expect(builder.formatNumber(3), '3');
|
||
expect(builder.formatNumber(3.5), '3.5');
|
||
expect(builder.formatNumber(3.04), '3');
|
||
expect(builder.formatNumber(3.26), '3.3');
|
||
});
|
||
|
||
test('formatLabel: dd.MM', () {
|
||
expect(builder.formatLabel(DateTime(2026, 11, 9, 12)), '09.11');
|
||
});
|
||
|
||
test('periodLabel: все периоды', () {
|
||
expect(builder.periodLabel(BodyPeriod.month), 'месяц');
|
||
expect(builder.periodLabel(BodyPeriod.threeMonths), '3 месяца');
|
||
expect(builder.periodLabel(BodyPeriod.sixMonths), '6 месяцев');
|
||
expect(builder.periodLabel(BodyPeriod.year), 'год');
|
||
expect(builder.periodLabel(BodyPeriod.all), 'всё время');
|
||
});
|
||
});
|
||
|
||
group('вес', () {
|
||
test('снижение', () {
|
||
final model = builder.buildWeight([
|
||
_weight(74.5),
|
||
_weight(73.2, day: 9),
|
||
], BodyPeriod.month);
|
||
|
||
expect(model.deltaText, 'Снизили на 1.3 кг за месяц');
|
||
expect(model.delta, -1.3);
|
||
expect(model.last, 73.2);
|
||
expect(model.headline, '73.2');
|
||
expect(model.unit, 'кг');
|
||
expect(model.labels, ['01.11', '09.11']);
|
||
expect(model.values, [74.5, 73.2]);
|
||
});
|
||
|
||
test('набор', () {
|
||
final model = builder.buildWeight([
|
||
_weight(70),
|
||
_weight(72, day: 3),
|
||
], BodyPeriod.threeMonths);
|
||
|
||
expect(model.deltaText, 'Набрали 2 кг за 3 месяца');
|
||
expect(model.delta, 2);
|
||
});
|
||
|
||
test('порог 0.05: меньше — не изменился', () {
|
||
final model = builder.buildWeight([
|
||
_weight(70),
|
||
_weight(70.04, day: 3),
|
||
], BodyPeriod.year);
|
||
|
||
expect(model.deltaText, 'Вес не изменился за год');
|
||
});
|
||
|
||
test('порог 0.05: ровно 0.25 — уже изменение', () {
|
||
final model = builder.buildWeight([
|
||
_weight(70),
|
||
_weight(70.25, day: 3),
|
||
], BodyPeriod.all);
|
||
|
||
expect(model.deltaText, 'Набрали 0.3 кг за всё время');
|
||
});
|
||
|
||
test('одна точка: недостаточно данных, но headline есть', () {
|
||
final model = builder.buildWeight([_weight(72)], BodyPeriod.month);
|
||
|
||
expect(model.deltaText, 'Недостаточно данных');
|
||
expect(model.delta, isNull);
|
||
expect(model.headline, '72.0');
|
||
});
|
||
|
||
test('нет точек', () {
|
||
final model = builder.buildWeight([], BodyPeriod.month);
|
||
|
||
expect(model.deltaText, 'Недостаточно данных');
|
||
expect(model.last, isNull);
|
||
expect(model.headline, '—');
|
||
expect(model.values, isEmpty);
|
||
});
|
||
});
|
||
|
||
group('категории ИМТ (границы)', () {
|
||
final cases = <double, String>{
|
||
15.9: 'выраженный дефицит массы',
|
||
16.0: 'недостаточная масса',
|
||
18.4: 'недостаточная масса',
|
||
18.5: 'норма',
|
||
24.9: 'норма',
|
||
25.0: 'избыточная масса',
|
||
29.9: 'избыточная масса',
|
||
30.0: 'ожирение I ст.',
|
||
34.9: 'ожирение I ст.',
|
||
35.0: 'ожирение II ст.',
|
||
39.9: 'ожирение II ст.',
|
||
40.0: 'ожирение III ст.',
|
||
55.0: 'ожирение III ст.',
|
||
};
|
||
|
||
cases.forEach((bmi, expected) {
|
||
test('$bmi → $expected', () {
|
||
expect(builder.bmiCategory(bmi), expected);
|
||
});
|
||
});
|
||
});
|
||
|
||
group('ИМТ', () {
|
||
test('без роста: пусто и подсказка', () {
|
||
final model = builder.buildBmi(
|
||
[_weight(70, bmi: 22)],
|
||
BodyPeriod.month,
|
||
null,
|
||
);
|
||
|
||
expect(model.values, isEmpty);
|
||
expect(model.headline, '—');
|
||
expect(model.hint, 'Укажите рост, чтобы посчитать ИМТ.');
|
||
expect(model.deltaText, 'Укажите рост, чтобы посчитать ИМТ.');
|
||
expect(model.category, isNull);
|
||
});
|
||
|
||
test('нулевой рост считается отсутствующим', () {
|
||
final model = builder.buildBmi(
|
||
[_weight(70, bmi: 22)],
|
||
BodyPeriod.month,
|
||
0,
|
||
);
|
||
|
||
expect(model.values, isEmpty);
|
||
});
|
||
|
||
test('ИМТ ниже', () {
|
||
final model = builder.buildBmi(
|
||
[_weight(80, bmi: 26.5), _weight(75, bmi: 24.2, day: 5)],
|
||
BodyPeriod.threeMonths,
|
||
176,
|
||
);
|
||
|
||
expect(model.deltaText, 'ИМТ ниже на 2.3 за 3 месяца · норма');
|
||
expect(model.category, 'норма');
|
||
expect(model.headline, '24.2');
|
||
expect(model.last, 24.2);
|
||
expect(model.delta, -2.3);
|
||
expect(model.hint, contains('Считаем при росте 176 см.'));
|
||
});
|
||
|
||
test('ИМТ выше', () {
|
||
final model = builder.buildBmi(
|
||
[_weight(70, bmi: 24), _weight(80, bmi: 27, day: 5)],
|
||
BodyPeriod.month,
|
||
170,
|
||
);
|
||
|
||
expect(model.deltaText, 'ИМТ выше на 3 за месяц · избыточная масса');
|
||
});
|
||
|
||
test('ИМТ не изменился', () {
|
||
final model = builder.buildBmi(
|
||
[_weight(70, bmi: 22), _weight(70, bmi: 22.01, day: 5)],
|
||
BodyPeriod.year,
|
||
170,
|
||
);
|
||
|
||
expect(model.deltaText, 'ИМТ не изменился за год · норма');
|
||
});
|
||
|
||
test('точки с bmi = null пропускаются', () {
|
||
final model = builder.buildBmi(
|
||
[_weight(70, bmi: null), _weight(71, bmi: 22, day: 3)],
|
||
BodyPeriod.month,
|
||
170,
|
||
);
|
||
|
||
expect(model.values, [22]);
|
||
expect(model.labels, ['03.11']);
|
||
expect(model.deltaText, 'Недостаточно данных');
|
||
});
|
||
|
||
test('рост есть, точек нет', () {
|
||
final model = builder.buildBmi([], BodyPeriod.month, 170);
|
||
|
||
expect(model.values, isEmpty);
|
||
expect(model.deltaText, 'Недостаточно данных');
|
||
expect(model.hint, contains('170'));
|
||
});
|
||
});
|
||
|
||
group('замеры', () {
|
||
test('по каждой части: меньше / больше / без изменений', () {
|
||
final model = builder.buildMeasure([
|
||
_circumference(waist: 82, chest: 96, hips: 100),
|
||
_circumference(waist: 80.5, chest: 98, hips: 100, day: 9),
|
||
], BodyPeriod.month);
|
||
|
||
expect(
|
||
model.deltaText,
|
||
'Талия меньше на 1.5 см, Грудь больше на 2 см, Бёдра без изменений за месяц',
|
||
);
|
||
expect(model.headline, '81');
|
||
expect(model.waist, [82, 80.5]);
|
||
expect(model.labels, ['01.11', '09.11']);
|
||
});
|
||
|
||
test('одна точка — недостаточно данных', () {
|
||
final model = builder.buildMeasure([_circumference()], BodyPeriod.month);
|
||
|
||
expect(model.deltaText, 'Недостаточно данных');
|
||
expect(model.headline, '80');
|
||
});
|
||
|
||
test('нет точек', () {
|
||
final model = builder.buildMeasure([], BodyPeriod.month);
|
||
|
||
expect(model.headline, '—');
|
||
expect(model.deltaText, 'Недостаточно данных');
|
||
});
|
||
});
|
||
|
||
group('build', () {
|
||
test('сортирует по дате, daily/intra = null', () {
|
||
final payload = builder.build(
|
||
weights: [_weight(73, bmi: 23, day: 9), _weight(75, bmi: 24, day: 1)],
|
||
circumferences: [
|
||
_circumference(waist: 79, day: 9),
|
||
_circumference(waist: 81),
|
||
],
|
||
period: BodyPeriod.month,
|
||
heightCm: 175,
|
||
);
|
||
|
||
expect(payload.weight.values, [75, 73]);
|
||
expect(payload.bmi.values, [24, 23]);
|
||
expect(payload.measure.waist, [81, 79]);
|
||
expect(payload.daily, isNull);
|
||
expect(payload.intra, isNull);
|
||
});
|
||
});
|
||
}
|