test: espandi copertura a 110 test e organizza in gruppi

- Aggiunto converter_provider_test.dart (nuovo): stato iniziale, select,
  setGrams, result, swapDirection, reset, search
- Aggiunto qr_test.dart (nuovo): buildQrPayload e parseMealPlanFromQr
  con round-trip e casi di errore
- meal_planner_provider_test: group(), importPlan(), fallback JSON corrotto
- shopping_list_provider_test: group(), addAll con aggregazione quantity,
  fallback JSON corrotto
- shopping_item_test: campi quantity (default, copyWith, JSON round-trip)
- shopping_item_tile_test: group(), visualizzazione (xN)
- conversion_entry_test: caso limite yieldFactor=0
- meal_card_test: group()
- Rimosso widget_test.dart (boilerplate obsoleto)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-17 23:27:19 +02:00
parent 9fcaae9687
commit 65214ac34e
8 changed files with 703 additions and 259 deletions
@@ -61,5 +61,14 @@ void main() {
expect(entry.rawToCooked(0), 0.0);
expect(entry.cookedToRaw(0), 0.0);
});
test('yield = 0: rawToCooked restituisce 0', () {
const entry = ConversionEntry(
food: 'test',
method: 'test',
yieldFactor: 0.0,
);
expect(entry.rawToCooked(100), 0.0);
});
});
}
@@ -0,0 +1,191 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:biteplan/features/converter/providers/converter_provider.dart';
import 'package:biteplan/features/converter/models/conversion_entry.dart';
void main() {
group('ConverterProvider', () {
late ConverterProvider provider;
setUp(() {
provider = ConverterProvider();
});
group('stato iniziale', () {
test('results è vuoto', () {
expect(provider.results, isEmpty);
});
test('selected è null', () {
expect(provider.selected, isNull);
});
test('grams è null', () {
expect(provider.grams, isNull);
});
test('rawToCooked è true', () {
expect(provider.rawToCooked, true);
});
test('result è null', () {
expect(provider.result, isNull);
});
});
group('select()', () {
const entry = ConversionEntry(food: 'riso', method: 'bollitura', yieldFactor: 3.0);
test('imposta l\'alimento selezionato', () {
provider.select(entry);
expect(provider.selected, entry);
});
test('azzera i grammi', () {
provider.setGrams(100);
provider.select(entry);
expect(provider.grams, isNull);
});
test('svuota i risultati', () {
provider.select(entry);
expect(provider.results, isEmpty);
});
test('notifica i listener', () {
var notified = false;
provider.addListener(() => notified = true);
provider.select(entry);
expect(notified, true);
});
});
group('setGrams()', () {
test('aggiorna il valore', () {
provider.setGrams(150.0);
expect(provider.grams, 150.0);
});
test('accetta null', () {
provider.setGrams(100.0);
provider.setGrams(null);
expect(provider.grams, isNull);
});
test('notifica i listener', () {
var notified = false;
provider.addListener(() => notified = true);
provider.setGrams(100.0);
expect(notified, true);
});
});
group('result', () {
const entry = ConversionEntry(food: 'riso', method: 'bollitura', yieldFactor: 3.0);
test('null se nessun alimento selezionato', () {
provider.setGrams(100.0);
expect(provider.result, isNull);
});
test('null se grammi non impostati', () {
provider.select(entry);
expect(provider.result, isNull);
});
test('null se grammi sono 0', () {
provider.select(entry);
provider.setGrams(0.0);
expect(provider.result, isNull);
});
test('null se grammi sono negativi', () {
provider.select(entry);
provider.setGrams(-10.0);
expect(provider.result, isNull);
});
test('calcola crudo→cotto', () {
provider.select(entry);
provider.setGrams(100.0);
expect(provider.result, closeTo(300.0, 0.05));
});
test('calcola cotto→crudo dopo swapDirection', () {
provider.select(entry);
provider.swapDirection();
provider.setGrams(300.0);
expect(provider.result, closeTo(100.0, 0.05));
});
test('arrotonda a 1 decimale', () {
const e = ConversionEntry(food: 'pollo', method: 'forno', yieldFactor: 0.67);
provider.select(e);
provider.setGrams(33.0);
// 33 * 0.67 = 22.11 → arrotondato a 22.1
expect(provider.result, closeTo(22.1, 0.05));
});
});
group('swapDirection()', () {
test('inverte la direzione', () {
expect(provider.rawToCooked, true);
provider.swapDirection();
expect(provider.rawToCooked, false);
provider.swapDirection();
expect(provider.rawToCooked, true);
});
test('azzera i grammi', () {
provider.setGrams(100.0);
provider.swapDirection();
expect(provider.grams, isNull);
});
test('notifica i listener', () {
var notified = false;
provider.addListener(() => notified = true);
provider.swapDirection();
expect(notified, true);
});
});
group('reset()', () {
test('azzera tutti i campi', () {
provider.select(const ConversionEntry(food: 'riso', method: 'bollitura', yieldFactor: 3.0));
provider.setGrams(100.0);
provider.swapDirection();
provider.reset();
expect(provider.selected, isNull);
expect(provider.grams, isNull);
expect(provider.rawToCooked, true);
expect(provider.results, isEmpty);
});
test('notifica i listener', () {
var notified = false;
provider.addListener(() => notified = true);
provider.reset();
expect(notified, true);
});
});
group('search()', () {
test('risultati vuoti con query vuota', () {
provider.search('');
expect(provider.results, isEmpty);
});
test('risultati vuoti con solo spazi', () {
provider.search(' ');
expect(provider.results, isEmpty);
});
test('notifica i listener', () {
var notified = false;
provider.addListener(() => notified = true);
provider.search('riso');
expect(notified, true);
});
});
});
}