Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature_2/#210 - add nutrient order and list #272

Merged
merged 3 commits into from
Nov 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lib/openfoodfacts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:http/http.dart';
import 'package:openfoodfacts/interface/JsonObject.dart';
import 'package:openfoodfacts/model/KnowledgePanels.dart';
import 'package:openfoodfacts/model/OcrIngredientsResult.dart';
import 'package:openfoodfacts/model/OrderedNutrients.dart';
import 'package:openfoodfacts/model/TaxonomyAdditive.dart';
import 'package:openfoodfacts/model/TaxonomyAllergen.dart';
import 'package:openfoodfacts/model/TaxonomyCategory.dart';
Expand Down Expand Up @@ -855,4 +856,29 @@ class OpenFoodAPIClient {
return KnowledgePanels.empty();
}
}

/// Returns the nutrient hierarchy specific to a country, localized.
///
/// [cc] is the country code, as ISO 3166-1 alpha-2
static Future<OrderedNutrients> getOrderedNutrients({
required final String cc,
required final OpenFoodFactsLanguage language,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we keep all the features in sync and allow to pass a list instead. Is a list of languages even supported on the server

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In first approach I don't think it would make sense to support several languages at the same time: here we're talking about nutrients, not localized food or ingredient names where we would need fallbacks.

Copy link
Member

@M123-dev M123-dev Nov 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay makes sense

final QueryType? queryType,
}) async {
final Uri uri = UriHelper.getUri(
path: 'cgi/nutrients.pl',
queryType: queryType,
queryParameters: <String, String>{'cc': cc, 'lc': language.code},
);

final Response response = await HttpHelper().doGetRequest(
uri,
userAgent: OpenFoodAPIConfiguration.userAgent,
);
if (response.statusCode != 200) {
throw Exception('Could not retrieve ordered nutrients!');
}
final json = jsonDecode(response.body);
return OrderedNutrients.fromJson(json);
}
}
96 changes: 47 additions & 49 deletions test/ordered_nutrient_test.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
import 'dart:convert';

import 'package:openfoodfacts/model/OrderedNutrient.dart';
import 'package:openfoodfacts/model/OrderedNutrients.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:openfoodfacts/utils/OpenFoodAPIConfiguration.dart';
import 'package:openfoodfacts/utils/QueryType.dart';
import 'package:test/test.dart';
import 'package:http/http.dart' as http;
import 'package:openfoodfacts/utils/HttpHelper.dart';

/// Tests related to [OrderedNutrient] and [OrderedNutrients]
void main() {
OpenFoodAPIConfiguration.globalQueryType = QueryType.TEST;

OrderedNutrient? _findOrderedNutrient(
final List<OrderedNutrient>? list,
final String nutrientId,
) {
if (list == null) {
return null;
}
for (final OrderedNutrient item in list) {
if (item.id == nutrientId) {
return item;
}
final OrderedNutrient? found =
_findOrderedNutrient(item.subNutrients, nutrientId);
if (found != null) {
return found;
}
}
return null;
}

group('$OpenFoodAPIClient ordered nutrients', () {
test('find expected nutrients', () async {
// Very long list, experimentally created from the 3 initial URLs.
Expand Down Expand Up @@ -126,65 +142,47 @@ void main() {
'zinc',
};

const List<String> urls = [
'https://fr.openfoodfacts.org/cgi/nutrients.pl',
'https://us.openfoodfacts.org/cgi/nutrients.pl',
'https://us-es.openfoodfacts.org/cgi/nutrients.pl',
];
for (final String url in urls) {
final http.Response response =
await HttpHelper().doGetRequest(Uri.parse(url));
final json = jsonDecode(response.body);
const Set<String> countries = {'fr', 'br', 'us'};
const OpenFoodFactsLanguage language = OpenFoodFactsLanguage.AFRIKAANS;
for (final String country in countries) {
final OrderedNutrients orderedNutrients =
OrderedNutrients.fromJson(json);
await OpenFoodAPIClient.getOrderedNutrients(
cc: country,
language: language,
);
for (final String expectedNutrient in expectedNutrients) {
expect(
_findOrderedNutrient(orderedNutrients.nutrients, expectedNutrient),
isNotNull,
reason: 'Could not find $expectedNutrient in $url',
reason:
'Could not find nutrient $expectedNutrient for country $country',
);
}
}
});

test('check localized "energy"', () async {
const String nutrientId = 'energy';
const Map<String, String> energies = {
'https://fr.openfoodfacts.org/cgi/nutrients.pl': 'Énergie',
'https://us.openfoodfacts.org/cgi/nutrients.pl': 'Energy',
'https://us-es.openfoodfacts.org/cgi/nutrients.pl': 'Energía',
const Map<OpenFoodFactsLanguage, String> energies = {
OpenFoodFactsLanguage.FRENCH: 'Énergie',
OpenFoodFactsLanguage.SPANISH: 'Energía',
OpenFoodFactsLanguage.ENGLISH: 'Energy',
OpenFoodFactsLanguage.PORTUGUESE: 'Energia',
};
for (final String url in energies.keys) {
final http.Response response =
await HttpHelper().doGetRequest(Uri.parse(url));
final json = jsonDecode(response.body);
final OrderedNutrients orderedNutrients =
OrderedNutrients.fromJson(json);
final OrderedNutrient? found =
_findOrderedNutrient(orderedNutrients.nutrients, nutrientId);
expect(found, isNotNull);
expect(found!.name, energies[url]);
const Set<String> countries = {'us', 'it', 'br'};
for (final OpenFoodFactsLanguage language in energies.keys) {
for (final String country in countries) {
final OrderedNutrients orderedNutrients =
await OpenFoodAPIClient.getOrderedNutrients(
cc: country,
language: language,
);
final OrderedNutrient? found =
_findOrderedNutrient(orderedNutrients.nutrients, nutrientId);
expect(found, isNotNull);
expect(found!.name, energies[language]);
}
}
});
});
}

OrderedNutrient? _findOrderedNutrient(
final List<OrderedNutrient>? list,
final String nutrientId,
) {
if (list == null) {
return null;
}
for (final OrderedNutrient item in list) {
if (item.id == nutrientId) {
return item;
}
final OrderedNutrient? found =
_findOrderedNutrient(item.subNutrients, nutrientId);
if (found != null) {
return found;
}
}
return null;
}