openfoodfacts / openfoodfacts-dart Goto Github PK
View Code? Open in Web Editor NEWOpen Food Facts API Wrapper
Home Page: https://pub.dev/packages/openfoodfacts
License: Apache License 2.0
Open Food Facts API Wrapper
Home Page: https://pub.dev/packages/openfoodfacts
License: Apache License 2.0
Big news. Flutter 2.0.0 has just entered the stable channel.
There are a lot of big changes. 💯
Here all the release notes and the annauncment.
The most important thing for the package, null safety, is now also stable. As I already noted in #90 , all packages we use are ready for null safety. That means we are now ready to upgrade.
Add support for the new "Image Refresh" API
Ensure we can request photo updates for select products to users for images which should be taken or re-taken (because they are too old, or possibly too small / blurry).
It returns a hash of image types + language code (only for the requested language code which should be the language of the app). The value is 0 for images we don't have, or the age of the image (in seconds) for apps that want to add some context like "Our photo of the ingredients is 14 months old, could you take a new one?"
.
product: {
images_to_update_fr: {
packaging_fr: 0,
front_fr: 83734290,
ingredients_fr: 83734290
}
},
for field in images_to_update_fr:
if field.value=0
verb = "take"
else:
verb = "refresh"
field_name = field.split.before("")
field_language = field.split.after("")
button_text = fetch_button_text(field_name, field_language, verb)
"Take %s picture"
"Refresh %s picture"
"ingredients"
"front"
"nutrition"
"packaging"
How to convert seconds in human readable format: 83734290 = 2 years and 7 months (example routine to convert) - https://stackoverflow.com/questions/29681328/convert-seconds-into-years-months-weeks-hours-minutes-and-seconds
(adapted from the original issue @ openfoodfacts/api-documentation#15 )
Hi! :)
When a product is requested from Rest API of OFF, the response contains vegan/vegetarian status for each ingredient of the product.
But the Ingredient
class from Dart SDK doesn't include the veg-status for some reason.
It seems that adding the fields wouldn't be too hard as Ingredient extends JsonObject and is parsed automatically.
Abstract the HTML form we currently have to enable simple OFF account creation for apps.
openfoodfacts/openfoodfacts-androidapp#3737
I'm getting this error when I call addProductmage:
2021-03-14 21:58:10.234 3827-4274/org.openfoodfacts.app E/flutter: [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: Null check operator used on a null value
#0 HttpHelper.doMultipartRequest (package:openfoodfacts/utils/HttpHelper.dart:66:65)
#1 OpenFoodAPIClient.addProductImage (package:openfoodfacts/openfoodfacts.dart:108:12)
#2 _ImageUploadCardState._getImage (package:smooth_app/cards/data_cards/image_upload_card.dart:77:13)
ProductQueryConfiguration configuration = ProductQueryConfiguration(barcode);
Tested with openfoodfacts: ^0.3.14+1 dart package,
As I want to get all field from all languages I was expecting that doing this is enough:
ProductQueryConfiguration configuration = ProductQueryConfiguration(barcode);
But this throw an exception:
NoSuchMethodError: The method 'contains' was called on null. Receiver: null Tried calling: contains(Instance of 'ProductField')
Maybe adding a default values can help?
ProductQueryConfiguration(this.barcode, {this.language = OpenFoodFactsLanguage.WORLD, this.fields=[ProductField.ALL]});
The Product JSON generation is broken. In particular, the ecoscore_data
field is not converted into JSON when the Product.toJson
method is called.
The problem can be demonstrated using the following test, which is expected to pass but currently doesn't with version 0.3.14+1 of the openfoodfacts-dart SDK.
import 'package:flutter_test/flutter_test.dart';
import 'package:openfoodfacts/model/EcoscoreData.dart';
import 'package:openfoodfacts/model/Product.dart';
void main() {
test('Product/EcoscoreData Json bug', () {
final product = Product();
product.productName = 'TestProduct';
final ecoscoreData = EcoscoreData();
ecoscoreData.grade = 'x';
product.ecoscoreData = ecoscoreData;
final productJson = product.toJson();
assert(!(productJson['ecoscore_data'] is EcoscoreData));
});
}
I expect this to be related to #63. @FredJul do you know what is up?
Some values returned by the API depend on the country of the user (e.g. the availability of the Eco-Score product attribute). We currently can set the language code (lc) parameter for the query, but not the country code (cc).
We added a new image type for the packaging information and/or recycling instructions. It works in the same way as the ingredients and nutrition images.
Hi everyone! I’m using open food facts api in my flutter app, it works fine and return the product name, but the image of the product or nutrient levels is always null or empty list. e.g: Shiitake Pastete (Barcode: 4104420173194), I can get all the info about this product by the website or open food facts application , but I get this when I use the api :
(keys are :[code, product_name, brands, lang, selected_images, images, nutriments, additives_tags, allergens_tags, nutrient_levels, ingredients_analysis_tags]....... values are :[null, Shiitake Pastete, null, -, {}, {}, {}, [], [], {}, [en:maybe-vegan, en:maybe-vegetarian, en:maybe-palm-oil-free]])
I'm trying to use OpenFoodAPIClient.addProductImage
to upload an image but I keep receiving errors like "field imgupload_front_xx not set" despite following the examples in the documentation. I've tried to change the image fields but without luck so I suspect this to be a problem with the SDK. The problem can be demonstrated using the following test, which fails:
test('add ingredients image test', () async {
SendImage image = new SendImage(
lang: OpenFoodFactsLanguage.DANISH,
barcode: "5722970900207",
imageField: ImageField.FRONT,
imageUrl: Uri.parse("assets/corn_da.jpg"), // Use attached image
);
Status status = await OpenFoodAPIClient.addProductImage(
TestConstants.TEST_USER, image);
expect(status != null, true);
assert(status.error != "field imgupload_front_xx not set");
});
For testing purposes, here is the image I'm trying to upload
The Product class has fields like:
this.productName,
this.productNameDE,
this.productNameEN,
this.productNameFR,
this.brands,
this.lang,
this.quantity,
this.imgSmallUrl,
this.ingredientsText,
this.ingredientsTextDE,
this.ingredientsTextEN,
productNameDE is mapped to the product_name_de field we retrieve from the API.
But in practice, OFF contains product data in 200 languages, it doesn't make sense to have 200 fields for product name, for ingredients, for packagings, for generic name etc.
We could change the Product class so that all language specific fields are a map, with language code as keys. But that would mean we would need to check if "product_name_[language code]" exists in the JSON to populate the map, and most of them won't exist.
Instead, I think we could just remove the productNameDE etc. fields and just provide getter functions that will check in the json object whenever they get called. Something like getFieldInLanguage(PRODUCT_NAME, "de") that we could call on all language specific fields, (with PRODUCT_NAME a constant for "product_name", that we can concatenate with the language to access the right field in the JSON)
There is a similar issue for images.
...
add_categories
add_labels
add_brands
...
Using these fields the requests adds a new value but doesn't replace the previous ones.
Examples:
https://world.openfoodfacts.net/cgi/product_jqm2.pl?code=0048151621226&user_id=username&password=*****&add_brands=Brand%203
Getting suggestions for states
https://world.openfoodfacts.org/cgi/suggest.pl?lc=fr&tagtype=states&string=a
Getting suggestions for languages
https://world.openfoodfacts.org/cgi/suggest.pl?lc=fr&tagtype=languages&string=a
Getting suggestions for labels
https://world.openfoodfacts.org/cgi/suggest.pl?lc=fr&tagtype=labels&string=a
Getting suggestions for categories
https://world.openfoodfacts.org/cgi/suggest.pl?lc=fr&tagtype=categories&string=a
Getting suggestions for Countries
https://world.openfoodfacts.org/cgi/suggest.pl?lc=fr&tagtype=countries&string=f
Getting suggestions for ingredients
https://world.openfoodfacts.org/cgi/suggest.pl?lc=fr&tagtype=ingredients&string=f
Getting suggestions for traces
https://world.openfoodfacts.org/cgi/suggest.pl?lc=fr&tagtype=traces&string=m
Getting suggestions for additives
https://world.openfoodfacts.org/cgi/suggest.pl?lc=fr&tagtype=additives&string=e
Getting suggestions for allergens
https://world.openfoodfacts.org/cgi/suggest.pl?lc=fr&tagtype=allergens&string=a
Getting suggestions for packager codes
https://world.openfoodfacts.org/cgi/suggest.pl?lc=en&tagtype=emb_codes&EM
Generally chatty tests/code should be avoided. This issue suggests getting rid of all the print statements in order to improve the test output.
IngredientsAnalysisTags.dart
currently have next enums:
enum VeganStatus { IS_VEGAN, IS_NOT_VEGAN, MAYBE }
enum VegetarianStatus { IS_VEGETARIAN, IS_NOT_VEGETARIAN, MAYBE }
enum PalmOilFreeStatus { IS_PALM_OIL_FREE, IS_NOT_PALM_OIL_FREE, MAYBE }
Neither of them have an unknown
element, but the statuses can have such a value:
Looking at the code, seems like currently the IngredientsAnalysisTags
structure assigns the maybe
value to the statuses when an unknown
status is received from server.
Since unknown
and maybe
actually mean different things, an unknown
element should be added.
all the search tests are failing with an error message like this:
_CastError (type 'int' is not a subtype of type 'String' in type cast) #0 _$ProductFromJson (package:openfoodfacts/model/Product.g.dart:39:47) #1 new Product.fromJson (package:openfoodfacts/model/Product.dart:132:7) #2 _$SearchResultFromJson.<anonymous closure> (package:openfoodfacts/model/SearchResult.g.dart:17:40) #3 MappedListIterable.elementAt (dart:_internal/iterable.dart:417:31) #4 ListIterable.toList (dart:_internal/iterable.dart:221:19) #5 _$SearchResultFromJson (package:openfoodfacts/model/SearchResult.g.dart:18:11) #6 new SearchResult.fromJson (package:openfoodfacts/model/SearchResult.dart:28:7) #7 OpenFoodAPIClient.searchProducts (package:openfoodfacts/openfoodfacts.dart:167:31) <asynchronous suspension> #8 _SearchRouteState._search (package:fit_app/search.dart:43:35) #9 _SearchRouteState.build.<anonymous closure> (package:fit_app/search.dart:77:29) #10 EditableTextState._finalizeEditing (package:flutter/src/widgets/editable_text.dart:1380:25) #11 EditableTextState.performAction (package:flutter/src/widgets/editable_text.dart:1283:9) #12 TextInput._handleTextInputInvocation (package:flutter/src/services/text_input.dart:1070:36) #13 MethodChannel._handleAsMethodCall (package:flutter/src/services/platform_channel.dart:409:55) #14 MethodChannel.setMethodCallHandler.<anonymous closure> (package:flutter/src/services/platform_channel.dart:377:54) #15 _DefaultBinaryMessenger.handlePlatformMessage (package:flutter/src/services/binding.dart:199:33) #16 _invoke3.<anonymous closure> (dart:ui/hooks.dart:290:15) #17 _rootRun (dart:async/zone.dart:1184:13) #18 _CustomZone.run (dart:async/zone.dart:1077:19) #19 _CustomZone.runGuarded (dart:async/zone.dart:979:7) #20 _invoke3 (dart:ui/hooks.dart:289:10) #21 _dispatchPlatformMessage (dart:ui/hooks.dart:164:5)
the problem may relate to version 0.3.4
The OFF API, website and apps allow users to upload product photos even if they are not logged in.
In the Flutter package, we currently require an OFF username and password for all edits, including uploading photos. It would be a good thing to remove that restriction.
I pass in the barcode and am of course returned a ProductResult which I can drill through to find the nutriments. However the nutriments are per 100g but I need per serving. How do I obtain the serving size of the product using getProductRaw so I can do the math to get the nutriments per serving as opposed to per 100g?
I'm experiencing an issue with the way products are constructed from JSON. The issue can be demonstrated using the following test, which currently fails, but which I'd expect to pass. I'm using openfoodfacts: 0.3.5
.
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:openfoodfacts/model/Product.dart';
void main() {
test('Deserialize', () {
var product = Product();
product.productName = 'Oatmeal';
String jsonString = jsonEncode(product.toJson());
Map<String, dynamic> productMap = json.decode(jsonString);
expect(Product.fromJson(productMap).productName, 'Oatmeal');
});
}
Test error:
NoSuchMethodError: The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
dart:core Object.noSuchMethod
package:openfoodfacts/utils/JsonHelper.dart 45:36 JsonHelper.selectedImagesToJson
package:openfoodfacts/model/Product.g.dart 91:18 _$ProductToJson
package:openfoodfacts/model/Product.dart 135:36 Product.toJson
test/serialize-json_test.dart 12:44 main.<fn>```
Whatever the image requested on the PROD query, the returned URL is https://static.openfoodfacts.org/images/products/
This should be fixed on the ImageHelper here:
return queryType == QueryType.PROD
? IMAGE_PROD_URL_BASE
: IMAGE_TEST_URL_BASE +
barcodeUrl +
"/" +
image.field.value +
"_" +
image.language.code +
"." +
image.rev.toString() +
"." +
image.size.toNumber() +
".jpg";
Today the tests are using products from the OFF DB. And with time those products are getting updated by the community, which lead to instable tests.
Maybe using mock data, a test DB if it existe or a Read-Only products to make the tests stable.
Add support for list queries
Example
https://world.openfoodfacts.dev/products/8024884500403,3263855093192,3045320001570,3021762383344,4008400402222,3330720237255,3608580823513,3700278403936,3302747010029,3608580823490,3250391660995,3760020506605,8722700202387,3330720237330,3535800940005,20000691,3270190127512.json?fields=code,product_name
Thanks for the great work !!
Quick question, how can I find the allergens from the response ?
We need Product
to host eco score fields, to be used by "smoothie" for instance.
Hello,
is there a reason why the kcal value is not present in the nutriments class?
I saw that one can convert from KJ to kcal.
Is it a better option do to the conversion, or to add this value into the nutriment class to access the value returned by OFF API?
Thank you,
Adrien
Health suggestions
Fix lib/interface/JsonObject.dart. (-0.50 points)
Analysis of lib/interface/JsonObject.dart reported 1 hint:
line 1 col 8: Unused import: 'dart:ffi'.
Fix lib/openfoodfacts.dart. (-0.50 points)
Analysis of lib/openfoodfacts.dart reported 1 hint:
line 161 col 25: The declaration '_login' isn't referenced.
Fix lib/utils/HttpHelper.dart. (-0.50 points)
Analysis of lib/utils/HttpHelper.dart reported 1 hint:
line 70 col 47: This function has a return type of 'Future
Fix lib/utils/ImageHelper.dart. (-0.50 points)
Analysis of lib/utils/ImageHelper.dart reported 1 hint:
line 2 col 8: Unused import: '../model/ProductImage.dart'.
There is an issue with generation of JSON from Product
objects. The issue seems to related to product images.
The issue can be demonstrated using the following test:
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:openfoodfacts/model/Product.dart';
import 'package:openfoodfacts/model/ProductResult.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:openfoodfacts/utils/LanguageHelper.dart';
import 'package:openfoodfacts/utils/ProductFields.dart';
import 'package:openfoodfacts/utils/ProductQueryConfigurations.dart';
import 'test_constants.dart';
void main() {
test('Generate JSON - database example', () async {
String barcode = '0030000010204';
ProductQueryConfiguration configurations = ProductQueryConfiguration(
barcode,
language: OpenFoodFactsLanguage.ENGLISH,
fields: [ProductField.ALL]);
ProductResult result = await OpenFoodAPIClient.getProduct(configurations,
user: TestConstants.TEST_USER);
expect(result.status, 1);
Product product = result.product;
Map<String, dynamic> productMap = product.toJson();
String json = jsonEncode(productMap);
assert(json is String);
});
}
This test prduces the following error:
Converting object to an encodable object failed: _LinkedHashMap len:5
dart:convert jsonEncode
test/json_test.dart 25:19 main.<fn>
Hint: the problem seems to be the selectedImages
defined in the Product
class. In particular, if you remove the content of this field by setting it to null
then the JSON is generated without errors:
....
Product product = result.product;
product.selectedImages = null;
....
The assets images on the package are only used for the tests, and this is raising the package memory.
As I solution we can replace those files with "online" images that can be called while the tests are running.
Open Food Facts uses optical character recognition (OCR) to retrieve nutritional data and other information from the product labels.
Process
Notes: * The OCR may contain errors. Encourage your users to correct the output using the ingredients WRITE API. * You can also use your own OCR, especially if to plan to send a high number of queries.
Parameters
Test server: https://world.openfoodfacts.org/cgi/ingredients.pl
code=code
id=imagefield
process_image=1
I found what seems to be a critical bug in OpenFoodAPIClient.saveProduct
that prevents nutriments from being saved.
Specify working user credentials and run the following code to add/edit a (real) product to the database:
import 'package:openfoodfacts/model/Nutriments.dart';
import 'package:openfoodfacts/model/Product.dart';
import 'package:openfoodfacts/model/Status.dart';
import 'package:openfoodfacts/model/User.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
void main() async {
// TODO: specify user credentials
User myUser = User(userId: 'user', password: 'secret-password');
var nutriments = Nutriments();
nutriments.energy = 365;
nutriments.carbohydrates = 12;
nutriments.proteins = 6;
nutriments.fat = 0.1;
var newProduct = Product(
barcode: "7340011364184",
productName: "Chili beans",
nutrimentDataPer: "100g",
nutriments: nutriments);
Status result = await OpenFoodAPIClient.saveProduct(myUser, newProduct);
print(result.statusVerbose);
}
Next, look up the product by the barcode by entering https://world.openfoodfacts.org/api/v0/product/7340011364184.json into your browser.
I'd expect the values of the code
, product_name
, nutrition_data_per
and nutriments
fields in 7340011364184.json
to match those in the code snippet above.
You'll see that the code
, product_name
and nutrition_data_per
fields have the correct values but nutriments
is empty, i.e. "nutriments":{}
. So for some reason nutriments are not saved.
Produced using version 0.3.10 of the API.
There shouldn't be a need for special classes and methods to make search queries for a specific PNNS group. Those queries can be supported by the normal search queries, by specifying a tag filter on pnns_groups_1 or pnns_groups_2
e.g. https://world.openfoodfacts.org/pnns-group-2/biscuits-and-cakes is the same as https://world.openfoodfacts.org/search?pnns_groups_2_tags=biscuits-and-cakes
I doubt that any app is using those PNNS queries (except for Smoothie), but it will be a breaking change, so we should update the version to from 0.3.something to 0.4.0 when we do that.
In the mean time, maybe we could display some kind of warning to indicate that those functions are deprecated.
something like this should work:
var parameters = <Parameter>[
const OutputFormat(format: Format.JSON),
const Page(page: 5),
const PageSize(size: 10),
const SearchSimple(active: true),
const SortBy(option: SortOption.PRODUCT_NAME),
const TagFilter(
tagType: "pnns_groups_2",
contains: true,
tagName: "biscuits-and-cakes"),
];
ProductSearchQueryConfiguration configuration =
ProductSearchQueryConfiguration(
parametersList: parameters,
fields: [ProductField.ALL],
language: OpenFoodFactsLanguage.FRENCH);
SearchResult result = await OpenFoodAPIClient.searchProducts(
TestConstants.TEST_USER, configuration,
queryType: QueryType.TEST);
The test files are not named according to the recommended convention. In consequence the tests do not run when you execute flutter test
. Example:
$ flutter test
....
Test directory "test" does not appear to contain any test files.
Test files must be in that directory and end with the pattern "_test.dart".
Solution/suggestion: rename the test as follows:
api_addProductImage_test.dart
api_getProductRaw_test.dart
api_getProduct_test.dart
api_getRobotoff_test.dart
api_postRobotoff_test.dart
api_saveProduct_test.dart
api_searchProducts_test.dart
recommended_daily_intake_test.dart
test_constants.dart
I'm at this commit: 21df57e
The current version has the following score
Maybe we can improve the score, by following pub.dev recommandations.
Tested with openfoodfacts: ^0.3.14+1 dart package, and I was looking for the novascore of the scanned product, but this result is not handled by product.dart.
Maybe adding this info could be helpful.
Many packages need to be updated with the latest versions.
See https://wiki.openfoodfacts.org/Product_Attributes for a description of product attributes.
It looks like @PrimaelQuemerais added some support for product attributes already:
https://github.com/openfoodfacts/openfoodfacts-dart/blob/master/lib/model/AttributeGroups.dart
But we should remove the harcoded names for attribute groups (nutritional_quality, processing, labels etc.): the server will add new attribute groups and attributes, and clients / libraries should not need to be updated.
bla bla
After renaming the tests according according to the recommended conventions (see #31), I find that 10 of them fail.
The tests:
peter@peter-laptop:~/git/openfoodfacts-dart (master)
λ ls test/
api_addProductImage_test.dart
api_getProductRaw_test.dart
api_getProduct_test.dart
api_getRobotoff_test.dart
api_postRobotoff_test.dart
api_saveProduct_test.dart
api_searchProducts_test.dart
recommended_daily_intake_test.dart
test_constants.dart
Executing the tests:
flutter test
....
00:08 +20 -10: Some tests failed.
The tests are noisy too, i.e. they generate a lot of console output, which is should be avoided.
The complete test log:
00:01 +0: /home/peter/git/openfoodfacts-dart/test/api_addProductImage_test.dart: OpenFoodAPIClient add product images add front image test
TEST-MODE
00:01 +0 -1: /home/peter/git/openfoodfacts-dart/test/api_addProductImage_test.dart: OpenFoodAPIClient add product images add front image test [E]
FileSystemException: Cannot open file, path = 'assets/front_de.jpg' (OS Error: No such file or directory, errno = 2)
dart:io _File.readAsBytes
package:openfoodfacts/utils/HttpHelper.dart 60:61 HttpHelper.doMultipartRequest
package:openfoodfacts/openfoodfacts.dart 96:10 OpenFoodAPIClient.addProductImage
api_addProductImage_test.dart 25:47 main.<fn>.<fn>
00:01 +0 -1: /home/peter/git/openfoodfacts-dart/test/api_addProductImage_test.dart: OpenFoodAPIClient add product images add ingredients image test
TEST-MODE
00:01 +0 -2: /home/peter/git/openfoodfacts-dart/test/api_addProductImage_test.dart: OpenFoodAPIClient add product images add ingredients image test [E]
FileSystemException: Cannot open file, path = 'assets/ingredients_en.jpg' (OS Error: No such file or directory, errno = 2)
dart:io _File.readAsBytes
package:openfoodfacts/utils/HttpHelper.dart 60:61 HttpHelper.doMultipartRequest
package:openfoodfacts/openfoodfacts.dart 96:10 OpenFoodAPIClient.addProductImage
api_addProductImage_test.dart 40:47 main.<fn>.<fn>
00:02 +1 -2: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search favorite products
URI: https://world.openfoodfacts.org/cgi/search.pl?json=1&page=1&page_size=10&search_type=1&sort_by=unique_scans_n&search_terms&lc=de
TEST-MODE
00:02 +1 -3: /home/peter/git/openfoodfacts-dart/test/api_saveProduct_test.dart: OpenFoodAPIClient add new products add new product test 1 [E]
NoSuchMethodError: The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
dart:core Object.noSuchMethod
package:openfoodfacts/utils/JsonHelper.dart 45:36 JsonHelper.selectedImagesToJson
package:openfoodfacts/model/Product.g.dart 91:18 _$ProductToJson
package:openfoodfacts/model/Product.dart 135:36 Product.toJson
package:openfoodfacts/interface/JsonObject.dart 7:45 JsonObject.toData
package:openfoodfacts/openfoodfacts.dart 67:33 OpenFoodAPIClient.saveProduct
api_saveProduct_test.dart 30:35 main.<fn>.<fn>
00:02 +1 -4: /home/peter/git/openfoodfacts-dart/test/api_saveProduct_test.dart: OpenFoodAPIClient add new products add new product test 2 [E]
NoSuchMethodError: The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
dart:core Object.noSuchMethod
package:openfoodfacts/utils/JsonHelper.dart 45:36 JsonHelper.selectedImagesToJson
package:openfoodfacts/model/Product.g.dart 91:18 _$ProductToJson
package:openfoodfacts/model/Product.dart 135:36 Product.toJson
package:openfoodfacts/interface/JsonObject.dart 7:45 JsonObject.toData
package:openfoodfacts/openfoodfacts.dart 67:33 OpenFoodAPIClient.saveProduct
api_saveProduct_test.dart 46:35 main.<fn>.<fn>
00:02 +1 -5: /home/peter/git/openfoodfacts-dart/test/api_saveProduct_test.dart: OpenFoodAPIClient add new products add new product test 3 [E]
NoSuchMethodError: The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
dart:core Object.noSuchMethod
package:openfoodfacts/utils/JsonHelper.dart 45:36 JsonHelper.selectedImagesToJson
package:openfoodfacts/model/Product.g.dart 91:18 _$ProductToJson
package:openfoodfacts/model/Product.dart 135:36 Product.toJson
package:openfoodfacts/interface/JsonObject.dart 7:45 JsonObject.toData
package:openfoodfacts/openfoodfacts.dart 67:33 OpenFoodAPIClient.saveProduct
api_saveProduct_test.dart 64:35 main.<fn>.<fn>
00:02 +1 -6: /home/peter/git/openfoodfacts-dart/test/api_postRobotoff_test.dart: OpenFoodAPIClient answer robotoff question get questions for Noix de Saint-Jacques EN and answer
TEST-MODE
00:02 +1 -6: /home/peter/git/openfoodfacts-dart/test/api_saveProduct_test.dart: OpenFoodAPIClient add new products add new product test 4 [E]
NoSuchMethodError: The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
dart:core Object.noSuchMethod
package:openfoodfacts/utils/JsonHelper.dart 45:36 JsonHelper.selectedImagesToJson
package:openfoodfacts/model/Product.g.dart 91:18 _$ProductToJson
package:openfoodfacts/model/Product.dart 135:36 Product.toJson
package:openfoodfacts/interface/JsonObject.dart 7:45 JsonObject.toData
package:openfoodfacts/openfoodfacts.dart 67:33 OpenFoodAPIClient.saveProduct
api_saveProduct_test.dart 82:35 main.<fn>.<fn>
00:02 +1 -6: /home/peter/git/openfoodfacts-dart/test/api_getProductRaw_test.dart: OpenFoodAPIClient get raw products get product test 1
TEST-MODE
00:03 +1 -6: /home/peter/git/openfoodfacts-dart/test/api_postRobotoff_test.dart: OpenFoodAPIClient answer robotoff question get questions for Noix de Saint-Jacques EN and answer
No question found for this product
00:03 +2 -6: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search favorite products
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
{code: 5449000000996, product_name: Coca Cola, product_name_de: Cola-Erfrischungsgetränk, product_name_en: Coca Cola, product_name_fr: Coca-Cola, brands: Coca-Cola, brands_tags: [coca-cola], lang: en, quantity: 330 ml, image_small_url: https://static.openfoodfacts.org/images/products/544/900/000/0996/front_de.169.200.jpg, serving_size: 330ml, serving_quantity: 330.0, product_quantity: 330, selected_images: {front: {thumb: {de: https://static.openfoodfacts.org/images/products/544/900/000/0996/front_de.169.100.jpg}, small: {de: https://static.openfoodfacts.org/images/products/544/900/000/0996/front_de.169.200.jpg}, display: {de: https://static.openfoodfacts.org/images/products/544/900/000/0996/front_de.169.400.jpg}, original: {}, null: {}}, ingredients: {thumb: {de: https://static.openfoodfacts.org/images/products/544/900/000/0996/ingredients_de.487.100.jpg}, small: {de: https://static.openfoodfacts.org/images/products/544/900/000/0996/ingredients_de.487.200.jpg}, display: {de: https://static.openfoodfacts.org/images/products/544/900/000/0996/ingredients_de.487.400.jpg}, original: {}, null: {}}, nutrition: {thumb: {en: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_en.402.100.jpg, es: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_es.218.100.jpg, fr: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_fr.346.100.jpg, pl: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_pl.369.100.jpg}, small: {en: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_en.402.200.jpg, es: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_es.218.200.jpg, fr: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_fr.346.200.jpg, pl: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_pl.369.200.jpg}, display: {en: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_en.402.400.jpg, es: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_es.218.400.jpg, fr: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_fr.346.400.jpg, pl: https://static.openfoodfacts.org/images/products/544/900/000/0996/nutrition_pl.369.400.jpg}, original: {}, null: {}}, other: {thumb: {}, small: {}, display: {}, original: {}, null: {}}}, images: {}, ingredients: [Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient'], nutriments: {salt_100g: 0.0, sugars_100g: 10.6, fat_100g: 0.0, saturated-fat_100g: 0.0, proteins_100g: 0.0, nova-group_100g: 4, energy_100g: 180.0, carbohydrates_100g: 10.6, salt_serving: 0.0, sugars_serving: 35.0, fat_serving: 0.0, saturated-fat_serving: 0.0, proteins_serving: 0.0, nova-group_serving: 4, energy_serving: 594.0, carbohydrates_serving: 35.0, energy_unit: KJ}, additives_tags: Instance of 'Additives', nutrient_levels: Instance of 'NutrientLevels', ingredients_text: water, sugar, carbon dioxide, dye e150d, acidifier e338, natural flavors including caffeine,, ingredients_text_de: Wasser, Zucker, Kohlensäure, Farbstoff E 150d, Säuerungsmittel: E 338, natürliche Aromen inklusive Koffein. Ingrédients: eau, sucre, acide carbonique, colorant E 150d, acidifiant E 338, arômes naturels incl. caféine., ingredients_text_en: water, sugar, carbon dioxide, dye e150d, acidifier e338, natural flavors including caffeine,, ingredients_text_fr: Eau gazéifiée, sucre, colorant : E150d, acidifiant : acide phosphorique, arômes naturels (extraits végétaux), dont caféine., ingredients_analysis_tags: [en:maybe-vegan, en:maybe-vegetarian, en:maybe-palm-oil-free], nutrition_data_per: 100g, nutrition_grade_fr: e, categories: Bevande,Bevande effervescente,Bevande zuccherate,en:boissons-boissons-gazeuses-sodas-boissons-sans-alcool-sodas-au-cola-boissons-avec-sucre-ajoute-pl-zawiera-kofeinę, categories_tags: [en:beverages, en:carbonated-drinks, en:sweetened-beverages, en:boissons-boissons-gazeuses-sodas-boissons-sans-alcool-sodas-au-cola-boissons-avec-sucre-ajoute-pl-zawiera-kofeinę], labels_tags: [en:verified], states_tags: [en:to-be-checked, en:complete, en:nutrition-facts-completed, en:ingredients-completed, en:expiration-date-to-be-completed, en:packaging-code-to-be-completed, en:characteristics-completed, en:categories-completed, en:brands-completed, en:packaging-completed, en:quantity-completed, en:product-name-completed, en:photos-validated, en:photos-uploaded], traces_tags: []}
Sucre
huile de palme
huile de noisettes
lait écrémé en poudre
cacao maigre
émulsifiants
vanilline
lécithines de soja
00:03 +3 -6: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search favorite products EN
URI: https://world.openfoodfacts.org/cgi/search.pl?json=1&page=14&page_size=3&search_type=1&sort_by=last_modified_t&search_terms&lc=en
TEST-MODE
00:03 +3 -6: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff questions get questions for Noix de Saint-Jacques EN
TEST-MODE
00:03 +4 -6: /home/peter/git/openfoodfacts-dart/test/api_getProductRaw_test.dart: OpenFoodAPIClient get raw products get product tiny twists - Rold Gold Pretzels - 16 OZ. (1 LB) 453.6g
https://world.openfoodfacts.org/api/v0/product/0028400047685.json?lc=en
TEST-MODE
00:03 +4 -6: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff questions get questions for Noix de Saint-Jacques EN
No question found for this product, please try with another barcode
00:03 +5 -6: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product Coca Cola Light
https://world.openfoodfacts.org/api/v0/product/5000112548167.json?lc=de
00:03 +5 -6: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff questions get questions for Noix de Saint-Jacques FR
TEST-MODE
00:03 +5 -6: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product Coca Cola Light
TEST-MODE
00:03 +6 -6: /home/peter/git/openfoodfacts-dart/test/api_getProductRaw_test.dart: OpenFoodAPIClient get raw products get product test 2
TEST-MODE
00:03 +6 -6: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search favorite products EN
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
{code: 3250390796633, product_name: P'tites Ailes rôties, product_name_fr: P'tites Ailes rôties, brands: Netto, brands_tags: [netto], lang: fr, quantity: 250 g, image_small_url: https://static.openfoodfacts.org/images/products/325/039/079/6633/front_fr.8.200.jpg, serving_size: 90 g, serving_quantity: 90.0, product_quantity: 250, selected_images: {front: {thumb: {fr: https://static.openfoodfacts.org/images/products/325/039/079/6633/front_fr.8.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/325/039/079/6633/front_fr.8.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/325/039/079/6633/front_fr.8.400.jpg}, original: {}, null: {}}, ingredients: {thumb: {fr: https://static.openfoodfacts.org/images/products/325/039/079/6633/ingredients_fr.14.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/325/039/079/6633/ingredients_fr.14.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/325/039/079/6633/ingredients_fr.14.400.jpg}, original: {}, null: {}}, nutrition: {thumb: {fr: https://static.openfoodfacts.org/images/products/325/039/079/6633/nutrition_fr.11.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/325/039/079/6633/nutrition_fr.11.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/325/039/079/6633/nutrition_fr.11.400.jpg}, original: {}, null: {}}, other: {thumb: {}, small: {}, display: {}, original: {}, null: {}}}, images: {}, ingredients: [Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient'], nutriments: {salt_100g: 1.44, sugars_100g: 0.6, fat_100g: 10.7, saturated-fat_100g: 3.5, proteins_100g: 20.1, nova-group_100g: 4, energy_100g: 792.0, carbohydrates_100g: 3.1, salt_serving: 1.3, sugars_serving: 0.54, fat_serving: 9.63, saturated-fat_serving: 3.15, proteins_serving: 18.1, nova-group_serving: 4, energy_serving: 713.0, carbohydrates_serving: 2.79, energy_unit: KJ}, additives_tags: Instance of 'Additives', nutrient_levels: Instance of 'NutrientLevels', ingredients_text: Manchons de poulet (UE) (85%), sirop de glucose, amidon transformé de tapioca, sel, arôme (contient _gluten_ ), épaississant: carraghénanes. Peut contenir des traces de céréales, soja, oeuf, lait, céleri et moutarde., ingredients_text_fr: Manchons de poulet (UE) (85%), sirop de glucose, amidon transformé de tapioca, sel, arôme (contient _gluten_ ), épaississant: carraghénanes. Peut contenir des traces de céréales, soja, oeuf, lait, céleri et moutarde., ingredients_analysis_tags: [en:non-vegan, en:non-vegetarian, en:palm-oil-free], nutrition_data_per: 100g, nutrition_grade_fr: d, categories: Viandes, Volailles, Poulets, Poulets cuisinés, Manchons de poulet, categories_tags: [en:meats, en:poultries, en:chickens, en:cooked-chicken, en:chicken-drumsticks], labels_tags: [en:no-flavour-enhancer, en:green-dot, en:no-preservatives], states_tags: [en:to-be-checked, en:complete, en:nutrition-facts-completed, en:ingredients-completed, en:expiration-date-completed, en:packaging-code-to-be-completed, en:characteristics-completed, en:categories-completed, en:brands-completed, en:packaging-completed, en:quantity-completed, en:product-name-completed, en:photos-validated, en:photos-uploaded], traces_tags: [en:celery, en:eggs, en:fish, en:gluten, en:milk, en:molluscs, en:mustard, en:soybeans]}
00:03 +7 -6: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products type bug : ingredient percent int vs String
URI: https://world.openfoodfacts.org/cgi/search.pl?json=1&page=16&page_size=5&search_type=1&sort_by=unique_scans_n&search_terms&lc=de
TEST-MODE
00:03 +7 -6: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff questions get questions for Noix de Saint-Jacques FR
No question found for this product, please try with another barcode
00:03 +8 -6: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff questions get 2 random questions
https://robotoff.openfoodfacts.org/api/v1/questions/random?lang=fr&count=2&insight_types=category
TEST-MODE
00:03 +8 -6: /home/peter/git/openfoodfacts-dart/test/api_getProductRaw_test.dart: OpenFoodAPIClient get raw products get product test 2
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
00:03 +9 -6: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product Coca Cola Light
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Wasser, Kohlensäure, Farbstoff E 150d, Säuerungsmittel Phosphorsäure und Citronensäure, Süßungsmittel (Natriumcyclamat, Acesulfam K, Aspartam), Aroma, Aroma Koffein.
{rank: 1, id: en:water, text: Wasser, bold: null}
{rank: 2, id: en:e290, text: Kohlensäure, bold: null}
{rank: 3, id: en:colour, text: Farbstoff, bold: null}
{rank: 4, id: en:acid, text: Säuerungsmittel, bold: null}
{rank: 5, id: en:sweetener, text: Süßungsmittel, bold: null}
{rank: 6, id: en:flavouring, text: Aroma, bold: null}
{rank: 7, id: de:aroma-koffein, text: Aroma Koffein, bold: null}
{id: en:e150d, text: e150d, bold: null}
{id: en:e338, text: Phosphorsäure, bold: null}
{id: en:e330, text: Citronensäure, bold: null}
{id: en:e952, text: Natriumcyclamat, bold: null}
{id: en:e950, text: Acesulfam K, bold: null}
{id: en:e951, text: Aspartam, bold: null}
00:03 +10 -6: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product tiny twists - Rold Gold Pretzels - 16 OZ. (1 LB) 453.6g
https://world.openfoodfacts.org/api/v0/product/0028400047685.json?lc=en
TEST-MODE
23.0
00:03 +11 -6: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product Danish Butter Cookies & Chocolate Chip Cookies
https://world.openfoodfacts.org/api/v0/product/5701184005007.json?lc=de
TEST-MODE
00:03 +11 -6: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products type bug : ingredient percent int vs String
Instance of 'SearchResult'
{code: 5449000232250, product_name: Thé glacé pêche intense, product_name_en: , product_name_fr: Thé glacé pêche intense, brands: Fuze Tea, brands_tags: [fuze-tea], lang: fr, quantity: 1.25L, image_small_url: https://static.openfoodfacts.org/images/products/544/900/023/2250/front_fr.184.200.jpg, serving_size: 250ml, serving_quantity: 250.0, product_quantity: 1250, selected_images: {front: {thumb: {fr: https://static.openfoodfacts.org/images/products/544/900/023/2250/front_fr.184.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/544/900/023/2250/front_fr.184.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/544/900/023/2250/front_fr.184.400.jpg}, original: {}, null: {}}, ingredients: {thumb: {fr: https://static.openfoodfacts.org/images/products/544/900/023/2250/ingredients_fr.174.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/544/900/023/2250/ingredients_fr.174.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/544/900/023/2250/ingredients_fr.174.400.jpg}, original: {}, null: {}}, nutrition: {thumb: {fr: https://static.openfoodfacts.org/images/products/544/900/023/2250/nutrition_fr.185.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/544/900/023/2250/nutrition_fr.185.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/544/900/023/2250/nutrition_fr.185.400.jpg}, original: {}, null: {}}, other: {thumb: {}, small: {}, display: {}, original: {}, null: {}}}, images: {}, ingredients: [Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient'], nutriments: {salt_100g: 0.03, sugars_100g: 4.3, fat_100g: 0.0, saturated-fat_100g: 0.0, proteins_100g: 0.0, nova-group_100g: 4, energy_100g: 79.0, carbohydrates_100g: 4.4, salt_serving: 0.075, sugars_serving: 10.8, fat_serving: 0.0, saturated-fat_serving: 0.0, proteins_serving: 0.0, nova-group_serving: 4, energy_serving: 198.0, carbohydrates_serving: 11.0, energy_unit: KJ}, additives_tags: Instance of 'Additives', nutrient_levels: Instance of 'NutrientLevels', ingredients_text: Eau, sucre, jus de pêche à base de concentré (1%), acidifiants : acide citrique, citrate de sodium, acide malique, extraits de thé (0,12 %), arômes naturels de pêche et thé avec autres arômes naturels, antioxydant : acide ascorbique, édulcorant : glycosides de stéviol., ingredients_text_en: , ingredients_text_fr: Eau, sucre, jus de pêche à base de concentré (1%), acidifiants : acide citrique, citrate de sodium, acide malique, extraits de thé (0,12 %), arômes naturels de pêche et thé avec autres arômes naturels, antioxydant : acide ascorbique, édulcorant : glycosides de stéviol., ingredients_analysis_tags: [en:maybe-vegan, en:maybe-vegetarian, en:palm-oil-free], nutrition_data_per: 100g, nutrition_grade_fr: d, categories: Beverages,Artificially sweetened beverages,Non-Alcoholic beverages,Tea-based beverages,Iced teas,Peach flavored iced teas,Sweetened beverages, categories_tags: [en:beverages, en:artificially-sweetened-beverages, en:non-alcoholic-beverages, en:tea-based-beverages, en:iced-teas, en:peach-flavored-iced-teas, en:sweetened-beverages], labels_tags: [en:with-sweeteners], states_tags: [en:to-be-checked, en:complete, en:nutrition-facts-completed, en:ingredients-completed, en:expiration-date-completed, en:packaging-code-completed, en:characteristics-completed, en:categories-completed, en:brands-completed, en:packaging-completed, en:quantity-completed, en:product-name-completed, en:photos-validated, en:photos-uploaded], traces_tags: []}
null
null
1.0
null
null
null
0.12
null
null
null
null
null
null
null
null
{code: 7613035866386, product_name: Eau, product_name_fr: Eau, brands: Contrex, brands_tags: [contrex], lang: fr, quantity: 1,5 l, image_small_url: https://static.openfoodfacts.org/images/products/761/303/586/6386/front_fr.101.200.jpg, serving_size: 1 l, serving_quantity: 1000.0, product_quantity: 1500, selected_images: {front: {thumb: {fr: https://static.openfoodfacts.org/images/products/761/303/586/6386/front_fr.101.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/761/303/586/6386/front_fr.101.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/761/303/586/6386/front_fr.101.400.jpg}, original: {}, null: {}}, ingredients: {thumb: {fr: https://static.openfoodfacts.org/images/products/761/303/586/6386/ingredients_fr.42.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/761/303/586/6386/ingredients_fr.42.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/761/303/586/6386/ingredients_fr.42.400.jpg}, original: {}, null: {}}, nutrition: {thumb: {fr: https://static.openfoodfacts.org/images/products/761/303/586/6386/nutrition_fr.54.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/761/303/586/6386/nutrition_fr.54.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/761/303/586/6386/nutrition_fr.54.400.jpg}, original: {}, null: {}}, other: {thumb: {}, small: {}, display: {}, original: {}, null: {}}}, images: {}, ingredients: [Instance of 'Ingredient', Instance of 'Ingredient'], nutriments: {salt_100g: 0.002, sugars_100g: 0.0, fat_100g: 0.0, saturated-fat_100g: 0.0, proteins_100g: 0.0, nova-group_100g: 1, energy_100g: 0.0, carbohydrates_100g: 0.0, salt_serving: 0.02, sugars_serving: 0.0, fat_serving: 0.0, saturated-fat_serving: 0.0, proteins_serving: 0.0, nova-group_serving: 1, energy_serving: 0.0, carbohydrates_serving: 0.0, energy_unit: KCAL}, additives_tags: Instance of 'Additives', nutrient_levels: Instance of 'NutrientLevels', ingredients_text: Eau minérale naturelle (source Contrex), ingredients_text_fr: Eau minérale naturelle (source Contrex), ingredients_analysis_tags: [en:maybe-vegan, en:maybe-vegetarian, en:maybe-palm-oil-free], nutrition_data_per: serving, nutrition_grade_fr: a, categories: Beverages, Dairies, Waters, Spring waters, Mineral waters, Natural mineral waters, en:unsweetened-beverages, categories_tags: [en:beverages, en:dairies, en:waters, en:spring-waters, en:mineral-waters, en:natural-mineral-waters, en:unsweetened-beverages], labels_tags: [en:green-dot, en:low-sodium], states_tags: [en:to-be-checked, en:complete, en:nutrition-facts-completed, en:ingredients-completed, en:expiration-date-completed, en:packaging-code-to-be-completed, en:characteristics-completed, en:categories-completed, en:brands-completed, en:packaging-completed, en:quantity-completed, en:product-name-completed, en:photos-validated, en:photos-uploaded], traces_tags: []}
null
null
{code: 5010477348678, product_name: Muesli 30% fruits & noix céréales complètes, product_name_en: Mueslis, product_name_fr: Muesli 30% fruits & noix céréales complètes, brands: Jordans, brands_tags: [jordans], lang: fr, quantity: 750 g, image_small_url: https://static.openfoodfacts.org/images/products/501/047/734/8678/front_fr.148.200.jpg, serving_size: 45g, serving_quantity: 45.0, product_quantity: 750, selected_images: {front: {thumb: {fr: https://static.openfoodfacts.org/images/products/501/047/734/8678/front_fr.148.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/501/047/734/8678/front_fr.148.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/501/047/734/8678/front_fr.148.400.jpg}, original: {}, null: {}}, ingredients: {thumb: {fr: https://static.openfoodfacts.org/images/products/501/047/734/8678/ingredients_fr.149.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/501/047/734/8678/ingredients_fr.149.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/501/047/734/8678/ingredients_fr.149.400.jpg}, original: {}, null: {}}, nutrition: {thumb: {fr: https://static.openfoodfacts.org/images/products/501/047/734/8678/nutrition_fr.153.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/501/047/734/8678/nutrition_fr.153.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/501/047/734/8678/nutrition_fr.153.400.jpg}, original: {}, null: {}}, other: {thumb: {}, small: {}, display: {}, original: {}, null: {}}}, images: {}, ingredients: [Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient'], nutriments: {salt_100g: 0.03, fiber_100g: 8.8, sugars_100g: 17.2, fat_100g: 7.2, saturated-fat_100g: 2.0, proteins_100g: 10.2, nova-group_100g: 1, energy_100g: 1523.0, carbohydrates_100g: 59.6, salt_serving: 0.0135, fiber_serving: 3.96, sugars_serving: 7.74, fat_serving: 3.24, saturated-fat_serving: 0.9, proteins_serving: 4.59, nova-group_serving: 1, energy_serving: 685.0, carbohydrates_serving: 26.8, energy_unit: KJ}, additives_tags: Instance of 'Additives', nutrient_levels: Instance of 'NutrientLevels', ingredients_text: Céréales Complètes (59%) (Flocons d'Avoine, Flocons de Blé, Flocons de Blé Grillés), Fruits Secs & Noix (30%) (Raisins Secs, Abricots secs hachés, Tranches de Pommes Séchées, Éclats de Noix de Coco Grillés, Noisettes Hachées Grillées, Amandes Effilées), Flocons d'Orge, Graines de Tournesol., ingredients_text_en: , ingredients_text_fr: Céréales Complètes (59%) (Flocons d'Avoine, Flocons de Blé, Flocons de Blé Grillés), Fruits Secs & Noix (30%) (Raisins Secs, Abricots secs hachés, Tranches de Pommes Séchées, Éclats de Noix de Coco Grillés, Noisettes Hachées Grillées, Amandes Effilées), Flocons d'Orge, Graines de Tournesol., ingredients_analysis_tags: [en:maybe-vegan, en:maybe-vegetarian, en:maybe-palm-oil-free], nutrition_data_per: 100g, nutrition_grade_fr: a, categories: Aliments et boissons à base de végétaux,Aliments d'origine végétale,Petit-déjeuners,Céréales et pommes de terre,Céréales et dérivés,Céréales pour petit-déjeuner,Mueslis,Mueslis aux fruits,Mueslis aux noix, categories_tags: [en:plant-based-foods-and-beverages, en:plant-based-foods, en:cereals-and-potatoes, en:breakfasts, en:cereals-and-their-products, en:breakfast-cereals, en:mueslis, en:mueslis-with-fruits, fr:mueslis-aux-noix], labels_tags: [en:new-recipe, en:no-added-sugar, en:no-colorings, en:no-preservatives], states_tags: [en:to-be-checked, en:complete, en:nutrition-facts-completed, en:ingredients-completed, en:expiration-date-completed, en:packaging-code-to-be-completed, en:characteristics-completed, en:categories-completed, en:brands-completed, en:packaging-completed, en:quantity-completed, en:product-name-completed, en:photos-validated, en:photos-uploaded], traces_tags: [en:gluten, en:nuts]}
59.0
30.0
30.0
null
null
null
null
null
null
null
null
null
null
null
{code: 3664346305990, product_name: Grand Arôme 32% de Cacao, product_name_fr: Grand Arôme 32% de Cacao, brands: Poulain, brands_tags: [poulain], lang: fr, quantity: 450 g, image_small_url: https://static.openfoodfacts.org/images/products/366/434/630/5990/front_fr.56.200.jpg, serving_size: 20 g + 200 ml, serving_quantity: 20.0, product_quantity: 450, selected_images: {front: {thumb: {fr: https://static.openfoodfacts.org/images/products/366/434/630/5990/front_fr.56.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/366/434/630/5990/front_fr.56.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/366/434/630/5990/front_fr.56.400.jpg}, original: {}, null: {}}, ingredients: {thumb: {fr: https://static.openfoodfacts.org/images/products/366/434/630/5990/ingredients_fr.51.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/366/434/630/5990/ingredients_fr.51.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/366/434/630/5990/ingredients_fr.51.400.jpg}, original: {}, null: {}}, nutrition: {thumb: {fr: https://static.openfoodfacts.org/images/products/366/434/630/5990/nutrition_fr.52.100.jpg}, small: {fr: https://static.openfoodfacts.org/images/products/366/434/630/5990/nutrition_fr.52.200.jpg}, display: {fr: https://static.openfoodfacts.org/images/products/366/434/630/5990/nutrition_fr.52.400.jpg}, original: {}, null: {}}, other: {thumb: {}, small: {}, display: {}, original: {}, null: {}}}, images: {}, ingredients: [Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient'], nutriments: {salt_100g: 0.03, fiber_100g: 10.5, sugars_100g: 67.0, fat_100g: 3.9, saturated-fat_100g: 2.4, proteins_100g: 7.5, nova-group_100g: 4, energy_100g: 1575.0, carbohydrates_100g: 71.0, salt_serving: 0.006, fiber_serving: 2.1, sugars_serving: 13.4, fat_serving: 0.78, saturated-fat_serving: 0.48, proteins_serving: 1.5, nova-group_serving: 4, energy_serving: 315.0, carbohydrates_serving: 14.2, energy_unit: KJ}, additives_tags: Instance of 'Additives', nutrient_levels: Instance of 'NutrientLevels', ingredients_text: Sucre, cacao maigre (11 % de beurre de cacao) en poudre, arôme., ingredients_text_fr: Sucre, cacao maigre (11 % de beurre de cacao) en poudre, arôme., ingredients_analysis_tags: [en:maybe-vegan, en:maybe-vegetarian, en:maybe-palm-oil-free], nutrition_data_per: 100g, nutrition_grade_fr: e, categories: Boissons,Petit-déjeuners,Produits déshydratés,Produits lyophilisés à reconstituer,Boissons instantanées,Cacaos et chocolats en poudre,Chocolats en poudre, categories_tags: [en:beverages, en:breakfasts, en:dried-products, en:dried-products-to-be-rehydrated, en:instant-beverages, en:cocoa-and-chocolate-powders, en:chocolate-powders], labels_tags: [en:green-dot, en:made-in-france], states_tags: [en:checked, en:complete, en:nutrition-facts-completed, en:ingredients-completed, en:expiration-date-to-be-completed, en:packaging-code-to-be-completed, en:characteristics-completed, en:categories-completed, en:brands-completed, en:packaging-completed, en:quantity-completed, en:product-name-completed, en:photos-validated, en:photos-uploaded], traces_tags: [en:milk, en:soybeans]}
null
null
null
null
11.0
{code: 5410041001204, product_name: TUC Original, product_name_de: TUC Original, product_name_en: TUC Original, product_name_fr: TUC original, brands: LU, brands_tags: [lu], lang: en, quantity: 100 g, image_small_url: https://static.openfoodfacts.org/images/products/541/004/100/1204/front_de.167.200.jpg, serving_size: 3 g, serving_quantity: 3.0, product_quantity: 100, selected_images: {front: {thumb: {de: https://static.openfoodfacts.org/images/products/541/004/100/1204/front_de.167.100.jpg}, small: {de: https://static.openfoodfacts.org/images/products/541/004/100/1204/front_de.167.200.jpg}, display: {de: https://static.openfoodfacts.org/images/products/541/004/100/1204/front_de.167.400.jpg}, original: {}, null: {}}, ingredients: {thumb: {de: https://static.openfoodfacts.org/images/products/541/004/100/1204/ingredients_de.168.100.jpg}, small: {de: https://static.openfoodfacts.org/images/products/541/004/100/1204/ingredients_de.168.200.jpg}, display: {de: https://static.openfoodfacts.org/images/products/541/004/100/1204/ingredients_de.168.400.jpg}, original: {}, null: {}}, nutrition: {thumb: {de: https://static.openfoodfacts.org/images/products/541/004/100/1204/nutrition_de.169.100.jpg}, small: {de: https://static.openfoodfacts.org/images/products/541/004/100/1204/nutrition_de.169.200.jpg}, display: {de: https://static.openfoodfacts.org/images/products/541/004/100/1204/nutrition_de.169.400.jpg}, original: {}, null: {}}, other: {thumb: {}, small: {}, display: {}, original: {}, null: {}}}, images: {}, ingredients: [Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient'], nutriments: {salt_100g: 1.75, fiber_100g: 2.4, sugars_100g: 7.1, fat_100g: 19.0, saturated-fat_100g: 1.9, proteins_100g: 8.3, nova-group_100g: 4, energy_100g: 2006.0, carbohydrates_100g: 67.0, salt_serving: 0.0525, fiber_serving: 0.072, sugars_serving: 0.213, fat_serving: 0.57, saturated-fat_serving: 0.057, proteins_serving: 0.249, nova-group_serving: 4, energy_serving: 60.2, carbohydrates_serving: 2.01, energy_unit: KJ}, additives_tags: Instance of 'Additives', nutrient_levels: Instance of 'NutrientLevels', ingredients_text: wheat flour, palm fat, barley malt extract, glucose syrup, raising agents (ammonium hydrogen carbonate, sodium hydrogen carbonate), eggs , salt, flavouring, flour treatment agent (sodium sulphite ), emulsifier (sunflower lecithin), ingredients_text_de: _Weizenmehl_, Sonnenblumenöl (17%), _Gerstenmalzextrakt_, Glukosesirup, Backtriebmittel (Ammoniumcarbonate, Natriumcarbonate), Speisesalz, _Ei_, Aroma, Mehlbehandlungsmittel (_Natriumsulfit_), Emulgator (Sonnenblumenlecithin)., ingredients_text_en: wheat flour, palm fat, barley malt extract, glucose syrup, raising agents (ammonium hydrogen carbonate, sodium hydrogen carbonate), eggs , salt, flavouring, flour treatment agent (sodium sulphite ), emulsifier (sunflower lecithin), ingredients_text_fr: Farine de blé, huile de tournesol 17%, extrait de malt d'orge, sirop de glucose, poudre à lever (carbonates d’ammonium, carbonate de sodium), sel, œufs, arôme, agent de traitement de la farine (sulfite de sodium), émulsifiant (lécithine de tournesol). Peut contenir lait, soja, sésame., ingredients_analysis_tags: [en:non-vegan, en:maybe-vegetarian, en:maybe-palm-oil-free], nutrition_data_per: 100g, nutrition_grade_fr: d, categories: Imbiss,Salzige Snacks,Süßwaren,Vorspeisen,Fertiggerichte,Kekse und Kuchen,Kekse,Crackers, categories_tags: [en:snacks, en:salty-snacks, en:sweet-snacks, en:appetizers, en:meals, en:biscuits-and-cakes, en:biscuits, en:crackers, en:starters], labels_tags: [], states_tags: [en:checked, en:complete, en:nutrition-facts-completed, en:ingredients-completed, en:expiration-date-completed, en:packaging-code-to-be-completed, en:characteristics-completed, en:categories-completed, en:brands-completed, en:packaging-completed, en:quantity-completed, en:product-name-completed, en:photos-validated, en:photos-uploaded], traces_tags: [en:milk, en:sesame-seeds, en:soybeans]}
null
null
null
null
null
null
null
null
null
null
null
null
null
null
00:03 +12 -6: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search products by keywords
URI: https://world.openfoodfacts.org/cgi/search.pl?json=1&page=5&page_size=10&search_type=1&sort_by=product_name&search_terms=Fruit&lc=fr
TEST-MODE
00:03 +12 -6: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product Danish Butter Cookies & Chocolate Chip Cookies
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Buttergebäck (_Weizenmehl_, Zucker, _Butter_ 26%, Speisesalz, Backtriebmittel (Ammouniumhydrogencarbonat), Invertzuckersirup, natürliches Aroma),
Schokolade Mürbegebäck (_Weizenmehl_, Pflanzenfett (Palm), Zucker, Schokoladenstückchen 10% (Zucker, Kakaomasse, Kakaobutter, Emulgator (Lecithin)), Backtriebmittel (Ammouniumhydrogencarbonat), fettarmes Kakaopulver, Speisesalz)
00:03 +12 -7: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product Danish Butter Cookies & Chocolate Chip Cookies [E]
Expected: <18>
Actual: <24>
package:test_api expect
package:flutter_test/src/widget_tester.dart 348:3 expect
api_getProduct_test.dart 152:7 main.<fn>.<fn>
00:03 +12 -7: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product Pâte brisée
https://world.openfoodfacts.org/api/v0/product/20004361.json?lc=fr
TEST-MODE
00:04 +12 -7: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search products by keywords
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
00:04 +13 -7: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search products filter additives
URI: https://world.openfoodfacts.org/cgi/search.pl?json=1&page=5&page_size=10&search_type=1&sort_by=product_name&search_terms=Fruit+%C3%A0+coques&additives&lc=fr
TEST-MODE
00:04 +13 -8: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product Pâte brisée [E]
Expected: 'Pâte brisée'
Actual: 'Ice Cream, Dulce De Leche'
Which: is different.
Expected: Pâte brisé ...
Actual: Ice Cream, ...
^
Differ at offset 0
package:test_api expect
package:flutter_test/src/widget_tester.dart 348:3 expect
api_getProduct_test.dart 230:7 main.<fn>.<fn>
00:04 +13 -8: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products product not available
https://world.openfoodfacts.org/api/v0/product/11111111111111111111111111.json?lc=de
TEST-MODE
00:04 +14 -8: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products product ingredients
https://world.openfoodfacts.org/api/v0/product/4316268596299.json?lc=de
TEST-MODE
00:04 +14 -8: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search products filter additives
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
URI: https://world.openfoodfacts.org/cgi/search.pl?json=1&page=5&page_size=10&search_type=1&sort_by=product_name&search_terms=Fruit+%C3%A0+coques&additives=without&lc=fr
TEST-MODE
00:04 +14 -8: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products product ingredients
number of ingredients: 27
00:04 +16 -8: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products product fields
https://world.openfoodfacts.org/api/v0/product/20004361.json?lc=de&fields=product_name%2Cbrands_tags
TEST-MODE
00:04 +16 -8: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff insights get random insight
https://robotoff.openfoodfacts.org/api/v1/insights/random/?type=category
TEST-MODE
00:04 +16 -8: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search products filter additives
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Total product count : 2912; Filtered count : 1494
00:04 +17 -8: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search products with filter on tags
URI: https://world.openfoodfacts.org/cgi/search.pl?json=1&page=5&page_size=10&search_type=1&sort_by=product_name&tagtype_0=categories&tag_contains_0=contains&tag_0=breakfast_cereals&tagtype_1=nutrition_grades&tag_contains_1=contains&tag_1=A&search_terms&lc=fr
TEST-MODE
00:04 +17 -8: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products product fields
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
00:04 +17 -9: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products product fields [E]
NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
dart:core Object.noSuchMethod
api_getProduct_test.dart 361:41 main.<fn>.<fn>
00:04 +17 -9: /home/peter/git/openfoodfacts-dart/test/api_searchProducts_test.dart: OpenFoodAPIClient search products search products with filter on tags
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
Unable to parse data to double : NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
{code: 50167862010002, product_name: Alara Gluten Free Fruity Oats Muesli, product_name_en: Alara Gluten Free Fruity Oats Muesli, brands: Alara, brands_tags: [alara], lang: en, quantity: 500 g, image_small_url: https://static.openfoodfacts.org/images/products/501/678/620/10002/front_en.3.200.jpg, serving_size: null, serving_quantity: null, product_quantity: 500, selected_images: {front: {thumb: {en: https://static.openfoodfacts.org/images/products/501/678/620/10002/front_en.3.100.jpg}, small: {en: https://static.openfoodfacts.org/images/products/501/678/620/10002/front_en.3.200.jpg}, display: {en: https://static.openfoodfacts.org/images/products/501/678/620/10002/front_en.3.400.jpg}, original: {}, null: {}}, ingredients: {thumb: {}, small: {}, display: {}, original: {}, null: {}}, nutrition: {thumb: {}, small: {}, display: {}, original: {}, null: {}}, other: {thumb: {}, small: {}, display: {}, original: {}, null: {}}}, images: {}, ingredients: [Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient', Instance of 'Ingredient'], nutriments: {salt_100g: 0.0, fiber_100g: 8.9, sugars_100g: 20.3, fat_100g: 8.4, saturated-fat_100g: 1.1, proteins_100g: 10.1, nova-group_100g: 1, energy_100g: 1549.0, carbohydrates_100g: 65.6, nova-group_serving: 1, energy_unit: KJ}, additives_tags: Instance of 'Additives', nutrient_levels: Instance of 'NutrientLevels', ingredients_text: _Oat_ Flakes 57%, Sultanas 18%, Sunflower Seeds 7%, Dates Chopped 5.7%, Raisins 5.7%, Linseeds 3.5%, Apricots Chopped 3%, ingredients_text_en: _Oat_ Flakes 57%, Sultanas 18%, Sunflower Seeds 7%, Dates Chopped 5.7%, Raisins 5.7%, Linseeds 3.5%, Apricots Chopped 3%, ingredients_analysis_tags: [en:vegan, en:vegetarian, en:palm-oil-free], nutrition_data_per: 100g, nutrition_grade_fr: a, categories: Plant-based foods and beverages, Plant-based foods, Breakfasts, Cereals and potatoes, Cereals and their products, Breakfast cereals, Flakes, Cereal flakes, Mixed cereal flakes, Mueslis, Wholegrains, categories_tags: [en:plant-based-foods-and-beverages, en:plant-based-foods, en:breakfasts, en:cereals-and-potatoes, en:cereals-and-their-products, en:breakfast-cereals, en:flakes, en:cereal-flakes, en:mixed-cereal-flakes, en:mueslis, en:wholegrains], labels_tags: [en:low-or-no-salt, en:low-or-no-sugar, en:vegetarian, en:gluten-free, en:vegan, en:high-fibres, en:high-proteins, en:no-milk, en:no-salt, en:no-sugar, en:nut-free, en:wheat-free, en:wholegrains], states_tags: [en:to-be-completed, en:nutrition-facts-completed, en:ingredients-completed, en:expiration-date-completed, en:packaging-code-to-be-completed, en:characteristics-completed, en:categories-completed, en:brands-completed, en:packaging-completed, en:quantity-completed, en:product-name-completed, en:photos-to-be-validated, en:photos-uploaded], traces_tags: [en:sodium]}
00:05 +19 -9: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff insights get product insights
https://robotoff.openfoodfacts.org/api/v1/insights/8025386005564
TEST-MODE
00:05 +20 -9: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff ingredient spelling corrections get farine de blé spelling corrections
TEST-MODE
00:08 +20 -10: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff ingredient spelling corrections get farine de blé spelling corrections [E]
NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length
dart:core Object.noSuchMethod
api_getRobotoff_test.dart 129:52 main.<fn>.<fn>
00:08 +20 -10: Some tests failed
\```
</p>
</details>
Request for comments:
Is there any way to add support for Open Food Facts variants such as ?
Is there a way to do it that would not break existing apps ? Or would we need to clone the package ?
We currently have this in Product.json
@jsonkey(name: 'image_small_url', includeIfNull: false)
String imgSmallUrl;
Which corresponds to the image_small_url field. But the API can return also images for ingredients, nutrition and packaging, in small and normal size (e.g. image_ingredients_small_url / image_ingredients_url).
I'd like to add corresponding fields, and also to rename imgSmallUrl to imageSmallUrl so that the class names match the API names. (we can keep imgSmallUrl for a while and mark it as deprecated).
There are a few things that could be simplified / removed from the definition of search queries:
e.g.
var parameters = <Parameter>[
const OutputFormat(format: Format.JSON),
const Page(page: 5),
const PageSize(size: 10),
const SearchSimple(active: true),
const SortBy(option: SortOption.PRODUCT_NAME),
const TagFilter(
tagType: "categories",
contains: true,
tagName: "breakfast_cereals"),
const TagFilter(
tagType: "nutrition_grades", contains: true, tagName: "A")
];
const OutputFormat(format: Format.JSON) --> we just need JSON, the other formats like XML or JSONP are not needed, they are only available for clients that do not understand JSON
const SearchSimple(active: true), --> this has absolutely no effect, it can be removed
I think we should remove all associated code. That means it would be a breaking change, and clients would have to remove it.
Three tests are currently failing in the master branch. I'm running the test from this commit fa0950b.
To produce the test errors run
flutter test test/
Relevant output:
TEST-MODE
00:03 +5 -1: /home/peter/git/openfoodfacts-dart/test/api_getProductRaw_test.dart: OpenFoodAPIClient get raw products get product test 1 [E]
Expected: 'Maisstärke'
Actual: 'corn starch'
Which: is different.
Expected: Maisstärke ...
Actual: corn starc ...
^
Differ at offset 0
package:test_api expect
package:flutter_test/src/widget_tester.dart 348:3 expect
test/api_getProductRaw_test.dart 35:7 main.<fn>.<fn>
...
0:04 +12 -2: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product Coca Cola Light [E]
Expected: <0.02>
Actual: <0.01>
package:test_api expect
package:flutter_test/src/widget_tester.dart 348:3 expect
test/api_getProduct_test.dart 74:7 main.<fn>.<fn>
00:04 +12 -2: /home/peter/git/openfoodfacts-dart/test/api_getProduct_test.dart: OpenFoodAPIClient get products get product tiny twists - Rold Gold Pretzels - 16 OZ. (1 LB) 453.6g
....
00:31 +29 -3: /home/peter/git/openfoodfacts-dart/test/api_getRobotoff_test.dart: OpenFoodAPIClient get robotoff ingredient spelling corrections get farine de blé spelling corrections [E]
FormatException: Unexpected character (at character 1)
<html>
^
dart:convert JsonCodec.decode
package:openfoodfacts/openfoodfacts.dart 369:14 OpenFoodAPIClient.getIngredientSpellingCorrection
00:31 +29 -3: Some tests failed.
The first two errors are probably just a consequence of changes in the database. So probably the tests should be rewritten in a way to avoid this issue. The last error ("get robotoff ingredient..") is different because the error only happens occasionally (it does not produce every time).
So in short the problem might not be the SDK itself but rather the tests. Nevertheless, this definitely complicates enabling CI (#3).
The productResult doesn't contain nutriment energy info. It's always null value.
I found an issue with construction of Product
objects from JSON. The issue can be demonstrated using the following test:
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:openfoodfacts/model/Product.dart';
import 'package:openfoodfacts/model/ProductResult.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:openfoodfacts/utils/LanguageHelper.dart';
import 'package:openfoodfacts/utils/ProductFields.dart';
import 'package:openfoodfacts/utils/ProductQueryConfigurations.dart';
import 'test_constants.dart';
void main() {
test('Construct Product from JSON - database example', () async {
String barcode = '0030000010204';
ProductQueryConfiguration configurations = ProductQueryConfiguration(
barcode,
language: OpenFoodFactsLanguage.ENGLISH,
fields: [ProductField.ALL]);
ProductResult result = await OpenFoodAPIClient.getProduct(configurations,
user: TestConstants.TEST_USER);
expect(result.status, 1);
Product product = result.product;
Map<String, dynamic> productMap = product.toJson();
String json = jsonEncode(productMap);
assert(json is String);
Map<String, dynamic> productRestoredMap = jsonDecode(json);
Product productRestored = Product.fromJson(productRestoredMap);
expect(productRestored.productName, "Quaker Oats Old Fashioned Oatmeal 18 Ounce Paper Cannister");
});
}
When you execute this test you get the following error:
Converting object to an encodable object failed: _LinkedHashMap len:5
dart:convert jsonEncode
test/json_test.dart 25:19 main.<fn>
The problem is related to the selectedImages
and additives
fields in the Product
class. If you assign these fields to null
then the test passes:
...
Product product = result.product;
product.selectedImages = null;
product.additives = null;
...
The title is a little confusing but what I mean. When I built my app with off integrated. I was very confused because I got the image url, but this photo was very small / pixelated. After a while I found out that a list of images with different sizes was returned.
At the time it's:
result.product.images[2].url
It would be much easier to understand to access the image by calling
result.product.images.small.url
We have CI for Open Food Facts to run tests on all repos. It could be nice to enable in the future.
There's a problem with converting EcoScoreData
objects to JSON, which can be demonstrated using the following test, which is expected to pass but currently does not:
test('EcoscoreData JSON generation', () {
final product = _createProductWithEcoscoreData();
var productJson = product.toJson();
final ecoscoreDataJson = productJson['ecoscore_data'];
assert(ecoscoreDataJson is Map);
final adjustmentsJson = ecoscoreDataJson['adjustments'];
assert(adjustmentsJson is Map);
final packagingJson = adjustmentsJson['packaging'];
assert(packagingJson is Map);
final originJson = adjustmentsJson['origins_of_ingredients'];
assert(originJson is Map);
product.ecoscoreData = null;
productJson = product.toJson();
assert(productJson['ecoscore_data'] == null);
});
Product _createProductWithEcoscoreData() {
final packaging = Packaging(score: 1.2, value: 4.1);
final originOfIngredients = OriginsOfIngredients(
epiScore: 1.2,
epiValue: 3.1,
transportationScore: 1.1,
transportationValue: 6.7);
final adjustments = EcoscoreAdjustments(
packaging: packaging, originsOfIngredients: originOfIngredients);
final ecoscoreData = EcoscoreData(
grade: 'x',
score: 1.2,
status: EcoscoreStatus.KNOWN,
adjustments: adjustments);
final product = Product(productName: 'TestProduct');
product.ecoscoreData = ecoscoreData;
return product;
}
the ingredient percentage attribute could not be mappend, cause double could not be parsed as int.
Steps to reproduce: start api_test_searchProducts.dart - search by keyword
`package:openfoodfacts/interface/JsonObject.dart 19:7 JsonObject.parseInt
package:openfoodfacts/model/Ingredient.g.dart 14:25 _$IngredientFromJson
package:openfoodfacts/model/Ingredient.dart 22:7 new Ingredient.fromJson
package:openfoodfacts/model/Product.g.dart 46:43 _$ProductFromJson.
dart:_internal ListIterable.toList
package:openfoodfacts/model/Product.g.dart 47:11 _$ProductFromJson
package:openfoodfacts/model/Product.dart 99:7 new Product.fromJson
package:openfoodfacts/model/SearchResult.g.dart 17:40 _$SearchResultFromJson.
dart:_internal ListIterable.toList
package:openfoodfacts/model/SearchResult.g.dart 18:11 _$SearchResultFromJson
package:openfoodfacts/model/SearchResult.dart 28:7 new SearchResult.fromJson
package:openfoodfacts/openfoodfacts.dart 149:31 OpenFoodAPIClient.searchProducts
type 'double' is not a subtype of type 'int'`
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.