lchrusciel / ApiTestCase

Handy PHPUnit test case for testing JSON APIs in your Symfony applications.
MIT License
410 stars 35 forks source link

Too much false positives in diffs #166

Closed ostrolucky closed 3 years ago

ostrolucky commented 4 years ago

Every time test case fails, it's massive PITA to figure out which field is actually different when using @integer@ notations, because during diffs (which is triggered on failure only) it uses them as literals. So output is like following. So bad in figuring out what is actually different:

@@ -1,51 +1,51 @@
 {
-    "id": @integer@,
+    "id": 3,
     "method": {
         "name": "MangoPay Credit Card",
-        "id": @integer@,
+        "id": 1,
         "code": "mangopay_credit_card",
-        "position": @integer@,
-        "createdAt": "@string@.isDateTime()",
-        "updatedAt": "@string@.isDateTime()",
+        "position": 0,
+        "createdAt": "2020-01-14T15:57:51+01:00",
+        "updatedAt": "2020-01-14T15:57:51+01:00",
         "_links": {
             "self": {
-                "href": @string@
+                "href": "/api/v1/payment-methods/mangopay_credit_card"
             }
         }
     },
-    "amount": @integer@,
+    "amount": 1490,
     "state": "failed",
     "details": {
-        "id": @string@,
+        "resultCode": "101304",
+        "resultMessage": "Secure mode: The 3DSecure authentication session has expired",
         "status": "FAILED",
-        "resultCode": "101304",
-        "resultMessage": "Secure mode: The 3DSecure authentication session has expired"
+        "id": "1234567"
     },
-    "createdAt": "@string@.isDateTime()",
-    "updatedAt": "@string@.isDateTime()",
+    "createdAt": "2020-01-14T15:57:51+01:00",
+    "updatedAt": "2020-01-14T15:57:51+01:00",
     "order": {
-        "id": @integer@,
+        "id": 3,
         "checkoutCompletedAt": null,
         "number": null,
         "items": [
             {
-                "id": @integer@,
-                "quantity": @integer@,
-                "unitPrice": @integer@,
-                "total": @integer@,
+                "id": 6,
+                "quantity": 1,
+                "unitPrice": 8099,
+                "total": 8099,
                 "units": [
                     {
-                        "id": @integer@,
+                        "id": 18,
                         "orderItem": null,
                         "adjustments": [],
-                        "adjustmentsTotal": @integer@,
+                        "adjustmentsTotal": 0,
                         "shipment": null,
                         "returnState": null
                     }
                 ],
-                "unitsTotal": @integer@,
+                "unitsTotal": 8099,
                 "adjustments": [],
-                "adjustmentsTotal": @integer@,
+                "adjustmentsTotal": 0,
                 "product": {
                     "name": "Jean Paul Gaultier Le Male",
                     "description": "ean Paul Gaultier pays tribute to a symbolic figure who has long been a source of inspiration for him: the sailor. Le Male, as virile as it is sexy, is a fragrance which offers a nonconformist view of masculinity… a reassuring fragrance with an extremely modern trail. Lavender, evoking the familiar, comforting scent of shaving soap, is enhanced by the sensuality of vanilla.\n",
@@ -53,12 +53,12 @@
                         {
                             "name": "Mug 5",
                             "descriptor": "Mug 5 (GAULTIER_LE_MALE)",
-                            "id": @integer@,
+                            "id": 5,
                             "code": "GAULTIER_LE_MALE",
                             "optionValues": [],
-                            "position": @integer@,
-                            "onHold": @integer@,
-                            "onHand": @integer@,
+                            "position": 0,
+                            "onHold": 31,
+                            "onHand": 2806,
                             "tracked": true,
                             "channelPricings": {
                                 "EUR": {
@@ -73,9 +73,10 @@
                                 }
                             },
                             "shippingRequired": true,
-                            "buyableStock": @integer@,
+                            "buyableStock": 2775,
                             "sizeValue": null,
                             "colorValue": null,
+                            "isolatedPreviewImage": null,
                             "previewImage": null,
                             "designer": {
                                 "billingAddress": {
@@ -86,7 +87,7 @@
                                     "region": null,
                                     "country": "FR"
                                 },
-                                "id": @string@,
+                                "id": "0123456789abcdef76543210",
                                 "name": "Jean-Paul Gaultier",
                                 "canonicalName": "jean-paulgaultier",
                                 "displayName": "Jean-Paul Gaultier",
@@ -95,44 +96,43 @@
                                 "hasAvatar": false,
                                 "vatRegistrationNumber": "VAT1338",
                                 "taxIdentificationNumber": null,
-                                "createdAt": "@string@.isDateTime()",
-                                "updatedAt": "@string@.isDateTime()",
+                                "createdAt": "2020-01-14T15:57:51+01:00",
+                                "updatedAt": "2020-01-14T15:57:51+01:00",
                                 "enabled": true,
-                                "shippingOthersMaxDeliveryDays": @integer@,
+                                "shippingOthersMaxDeliveryDays": 17,
                                 "shippingOriginCountry": "FR",
-                                "shippingOriginMaxDeliveryDays": @integer@,
+                                "shippingOriginMaxDeliveryDays": 4,
                                 "type": "designer"
                             },
                             "sku": null,
                             "_links": {
                                 "self": {
-                                    "href": @string@
+                                    "href": "/api/v1/products/GAULTIER-LE-MALE/variants/GAULTIER_LE_MALE"
                                 },
                                 "product": {
-                                    "href": @string@
+                                    "href": "/api/v1/products/GAULTIER-LE-MALE"
                                 }
                             },
                             "priceLocalized": "72,95 €",
-                            "originalPriceLocalized": "72,95 €",
-                            "isolatedPreviewImage": null
+                            "originalPriceLocalized": "72,95 €"
                         }
                     ],
                     "slug": "gaultier-le-male",
                     "options": [],
-                    "id": @integer@,
+                    "id": 5,
                     "code": "GAULTIER-LE-MALE",
                     "attributes": [],
-                    "createdAt": "@string@.isDateTime()",
-                    "updatedAt": "@string@.isDateTime()",
+                    "createdAt": "2013-10-10T08:26:00+02:00",
+                    "updatedAt": "2015-10-05T08:26:00+02:00",
                     "enabled": true,
                     "productTaxons": [],
                     "mainTaxon": null,
                     "images": [],
                     "similarProducts": [],
+                    "isolatedPreviewImage": null,
                     "previewImage": null,
                     "size": null,
                     "color": null,
-                    "topics": [],
                     "designer": {
                         "billingAddress": {
                             "addressLine1": "Street 2",
@@ -142,7 +142,7 @@
                             "region": null,
                             "country": "FR"
                         },
-                        "id": @string@,
+                        "id": "0123456789abcdef76543210",
                         "name": "Jean-Paul Gaultier",
                         "canonicalName": "jean-paulgaultier",
                         "displayName": "Jean-Paul Gaultier",
@@ -151,35 +151,34 @@
                         "hasAvatar": false,
                         "vatRegistrationNumber": "VAT1338",
                         "taxIdentificationNumber": null,
-                        "createdAt": "@string@.isDateTime()",
-                        "updatedAt": "@string@.isDateTime()",
+                        "createdAt": "2020-01-14T15:57:51+01:00",
+                        "updatedAt": "2020-01-14T15:57:51+01:00",
                         "enabled": true,
-                        "shippingOthersMaxDeliveryDays": @integer@,
+                        "shippingOthersMaxDeliveryDays": 17,
                         "shippingOriginCountry": "FR",
-                        "shippingOriginMaxDeliveryDays": @integer@,
+                        "shippingOriginMaxDeliveryDays": 4,
                         "type": "designer"
                     },
                     "_links": {
                         "self": {
-                            "href": @string@
+                            "href": "/api/v1/products/GAULTIER-LE-MALE"
                         },
                         "variants": {
-                            "href": @string@
+                            "href": "/api/v1/products/GAULTIER-LE-MALE/variants/"
                         }
                     },
                     "lowestPriceLocalized": "72,95 €",
-                    "originalLowestPriceLocalized": "72,95 €",
-                    "isolatedPreviewImage": null
+                    "originalLowestPriceLocalized": "72,95 €"
                 },
                 "variant": {
                     "name": "Mug 5",
                     "descriptor": "Mug 5 (GAULTIER_LE_MALE)",
-                    "id": @integer@,
+                    "id": 5,
                     "code": "GAULTIER_LE_MALE",
                     "optionValues": [],
-                    "position": @integer@,
-                    "onHold": @integer@,
-                    "onHand": @integer@,
+                    "position": 0,
+                    "onHold": 31,
+                    "onHand": 2806,
                     "tracked": true,
                     "channelPricings": {
                         "EUR": {
@@ -194,9 +193,10 @@
                         }
                     },
                     "shippingRequired": true,
-                    "buyableStock": @integer@,
+                    "buyableStock": 2775,
                     "sizeValue": null,
                     "colorValue": null,
+                    "isolatedPreviewImage": null,
                     "previewImage": null,
                     "designer": {
                         "billingAddress": {
@@ -207,7 +207,7 @@
                             "region": null,
                             "country": "FR"
                         },
-                        "id": @string@,
+                        "id": "0123456789abcdef76543210",
                         "name": "Jean-Paul Gaultier",
                         "canonicalName": "jean-paulgaultier",
                         "displayName": "Jean-Paul Gaultier",
@@ -216,76 +216,75 @@
                         "hasAvatar": false,
                         "vatRegistrationNumber": "VAT1338",
                         "taxIdentificationNumber": null,
-                        "createdAt": "@string@.isDateTime()",
-                        "updatedAt": "@string@.isDateTime()",
+                        "createdAt": "2020-01-14T15:57:51+01:00",
+                        "updatedAt": "2020-01-14T15:57:51+01:00",
                         "enabled": true,
-                        "shippingOthersMaxDeliveryDays": @integer@,
+                        "shippingOthersMaxDeliveryDays": 17,
                         "shippingOriginCountry": "FR",
-                        "shippingOriginMaxDeliveryDays": @integer@,
+                        "shippingOriginMaxDeliveryDays": 4,
                         "type": "designer"
                     },
                     "sku": null,
                     "_links": {
                         "self": {
-                            "href": @string@
+                            "href": "/api/v1/products/GAULTIER-LE-MALE/variants/GAULTIER_LE_MALE"
                         },
                         "product": {
-                            "href": @string@
+                            "href": "/api/v1/products/GAULTIER-LE-MALE"
                         }
                     },
                     "priceLocalized": "72,95 €",
-                    "originalPriceLocalized": "72,95 €",
-                    "isolatedPreviewImage": null
+                    "originalPriceLocalized": "72,95 €"
                 },
-                "returnableUnitCount": @integer@,
+                "returnableUnitCount": 1,
                 "affiliateBlogger": null,
                 "hash": null,
                 "_links": {
                     "order": {
-                        "href": @string@
+                        "href": "/api/v1/orders/3"
                     },
                     "product": {
-                        "href": @string@
+                        "href": "/api/v1/products/GAULTIER-LE-MALE"
                     },
                     "variant": {
-                        "href": @string@
+                        "href": "/api/v1/products/GAULTIER-LE-MALE/variants/GAULTIER_LE_MALE"
                     }
                 },
                 "totalLocalized": "80,99 $",
                 "unitPriceLocalized": "80,99 $"
             }
         ],
-        "itemsTotal": @integer@,
+        "itemsTotal": 8099,
         "adjustments": [],
-        "adjustmentsTotal": @integer@,
-        "total": @integer@,
+        "adjustmentsTotal": 0,
+        "total": 8099,
         "state": "new",
         "customer": {
-            "id": @integer@,
+            "id": 6,
             "communityReferenceId": "591af0b9e966af744602c55f",
             "_links": {
                 "self": {
-                    "href": @string@
+                    "href": "/api/v1/customers/6"
                 }
             }
         },
         "channel": {
-            "id": @integer@,
+            "id": 2,
             "code": "USD",
             "name": "USD Channel",
             "description": "Lorem ipsum",
             "hostname": "localhost",
             "color": "red",
-            "createdAt": "@string@.isDateTime()",
-            "updatedAt": "@string@.isDateTime()",
+            "createdAt": "2020-01-14T15:57:51+01:00",
+            "updatedAt": "2020-01-14T15:57:51+01:00",
             "enabled": true,
             "baseCurrencyCode": "USD",
-            "baseCurrencyMinAmount": @integer@,
-            "baseCurrencyMaxAmount": @integer@,
+            "baseCurrencyMinAmount": 10,
+            "baseCurrencyMaxAmount": 133700,
             "taxCalculationStrategy": "order_items_based",
             "_links": {
                 "self": {
-                    "href": @string@
+                    "href": "/api/v1/channels/USD"
                 }
             }
         },
@@ -294,36 +293,36 @@
         "payments": [
             null,
             {
-                "id": @integer@,
+                "id": 6,
                 "method": {
                     "name": "MangoPay Credit Card",
-                    "id": @integer@,
+                    "id": 1,
                     "code": "mangopay_credit_card",
-                    "position": @integer@,
-                    "createdAt": "@string@.isDateTime()",
-                    "updatedAt": "@string@.isDateTime()",
+                    "position": 0,
+                    "createdAt": "2020-01-14T15:57:51+01:00",
+                    "updatedAt": "2020-01-14T15:57:51+01:00",
                     "_links": {
                         "self": {
-                            "href": @string@
+                            "href": "/api/v1/payment-methods/mangopay_credit_card"
                         }
                     }
                 },
-                "amount": @integer@,
+                "amount": 8099,
                 "state": "new",
                 "details": [],
-                "createdAt": "@string@.isDateTime()",
-                "updatedAt": "@string@.isDateTime()",
+                "createdAt": "2020-01-14T15:57:51+01:00",
+                "updatedAt": "2020-01-14T15:57:51+01:00",
                 "order": null,
                 "methodDetails": [],
                 "_links": {
                     "order": {
-                        "href": @string@
+                        "href": "/api/v1/orders/3"
                     },
                     "self": {
-                        "href": @string@
+                        "href": "/api/v1/payments/6"
                     },
                     "payment-method": {
-                        "href": @string@
+                        "href": "/api/v1/payment-methods/mangopay_credit_card"
                     }
                 }
             }
@@ -339,59 +338,59 @@
                 "billingAddress": null,
                 "shippingAddress": null,
                 "checkoutCompletedAt": null,
-                "cancellableAt": "@string@.isDateTime()",
+                "cancellableAt": "2020-01-14T15:56:51+01:00",
                 "paymentCompletedAt": null,
                 "customer": {
-                    "id": @integer@,
+                    "id": 6,
                     "communityReferenceId": "591af0b9e966af744602c55f",
                     "_links": {
                         "self": {
-                            "href": @string@
+                            "href": "/api/v1/customers/6"
                         }
                     }
                 },
                 "deliveryUntil": null,
-                "estimatedDeliveryUntil": "@string@.isDateTime()",
+                "estimatedDeliveryUntil": "2020-01-31T15:57:52+01:00",
                 "deliveryUntilOverdue": false,
                 "number": null,
                 "payments": [
                     null,
                     {
-                        "id": @integer@,
+                        "id": 6,
                         "method": {
                             "name": "MangoPay Credit Card",
-                            "id": @integer@,
+                            "id": 1,
                             "code": "mangopay_credit_card",
-                            "position": @integer@,
-                            "createdAt": "@string@.isDateTime()",
-                            "updatedAt": "@string@.isDateTime()",
+                            "position": 0,
+                            "createdAt": "2020-01-14T15:57:51+01:00",
+                            "updatedAt": "2020-01-14T15:57:51+01:00",
                             "_links": {
                                 "self": {
-                                    "href": @string@
+                                    "href": "/api/v1/payment-methods/mangopay_credit_card"
                                 }
                             }
                         },
-                        "amount": @integer@,
+                        "amount": 8099,
                         "state": "new",
                         "details": [],
-                        "createdAt": "@string@.isDateTime()",
-                        "updatedAt": "@string@.isDateTime()",
+                        "createdAt": "2020-01-14T15:57:51+01:00",
+                        "updatedAt": "2020-01-14T15:57:51+01:00",
                         "order": null,
                         "methodDetails": [],
                         "_links": {
                             "order": {
-                                "href": @string@
+                                "href": "/api/v1/orders/3"
                             },
                             "self": {
-                                "href": @string@
+                                "href": "/api/v1/payments/6"
                             },
                             "payment-method": {
-                                "href": @string@
+                                "href": "/api/v1/payment-methods/mangopay_credit_card"
                             }
                         }
                     }
                 ],
-                "shippedUnitCount": @integer@,
+                "shippedUnitCount": 0,
                 "paymentState": "awaiting_payment",
                 "state": "new",
                 "currencyCode": "USD",
@@ -405,7 +404,7 @@
                         "region": null,
                         "country": "FR"
                     },
-                    "id": @string@,
+                    "id": "0123456789abcdef76543210",
                     "name": "Jean-Paul Gaultier",
                     "canonicalName": "jean-paulgaultier",
                     "displayName": "Jean-Paul Gaultier",
@@ -414,33 +413,33 @@
                     "hasAvatar": false,
                     "vatRegistrationNumber": "VAT1338",
                     "taxIdentificationNumber": null,
-                    "createdAt": "@string@.isDateTime()",
-                    "updatedAt": "@string@.isDateTime()",
+                    "createdAt": "2020-01-14T15:57:51+01:00",
+                    "updatedAt": "2020-01-14T15:57:51+01:00",
                     "enabled": true,
-                    "shippingOthersMaxDeliveryDays": @integer@,
+                    "shippingOthersMaxDeliveryDays": 17,
                     "shippingOriginCountry": "FR",
-                    "shippingOriginMaxDeliveryDays": @integer@,
+                    "shippingOriginMaxDeliveryDays": 4,
                     "type": "designer"
                 },
                 "items": [
                     {
-                        "id": @integer@,
-                        "quantity": @integer@,
-                        "unitPrice": @integer@,
-                        "total": @integer@,
+                        "id": 6,
+                        "quantity": 1,
+                        "unitPrice": 8099,
+                        "total": 8099,
                         "units": [
                             {
-                                "id": @integer@,
+                                "id": 18,
                                 "orderItem": null,
                                 "adjustments": [],
-                                "adjustmentsTotal": @integer@,
+                                "adjustmentsTotal": 0,
                                 "shipment": null,
                                 "returnState": null
                             }
                         ],
-                        "unitsTotal": @integer@,
+                        "unitsTotal": 8099,
                         "adjustments": [],
-                        "adjustmentsTotal": @integer@,
+                        "adjustmentsTotal": 0,
                         "product": {
                             "name": "Jean Paul Gaultier Le Male",
                             "description": "ean Paul Gaultier pays tribute to a symbolic figure who has long been a source of inspiration for him: the sailor. Le Male, as virile as it is sexy, is a fragrance which offers a nonconformist view of masculinity… a reassuring fragrance with an extremely modern trail. Lavender, evoking the familiar, comforting scent of shaving soap, is enhanced by the sensuality of vanilla.\n",
@@ -448,12 +447,12 @@
                                 {
                                     "name": "Mug 5",
                                     "descriptor": "Mug 5 (GAULTIER_LE_MALE)",
-                                    "id": @integer@,
+                                    "id": 5,
                                     "code": "GAULTIER_LE_MALE",
                                     "optionValues": [],
-                                    "position": @integer@,
-                                    "onHold": @integer@,
-                                    "onHand": @integer@,
+                                    "position": 0,
+                                    "onHold": 31,
+                                    "onHand": 2806,
                                     "tracked": true,
                                     "channelPricings": {
                                         "EUR": {
@@ -468,9 +467,10 @@
                                         }
                                     },
                                     "shippingRequired": true,
-                                    "buyableStock": @integer@,
+                                    "buyableStock": 2775,
                                     "sizeValue": null,
                                     "colorValue": null,
+                                    "isolatedPreviewImage": null,
                                     "previewImage": null,
                                     "designer": {
                                         "billingAddress": {
@@ -481,7 +481,7 @@
                                             "region": null,
                                             "country": "FR"
                                         },
-                                        "id": @string@,
+                                        "id": "0123456789abcdef76543210",
                                         "name": "Jean-Paul Gaultier",
                                         "canonicalName": "jean-paulgaultier",
                                         "displayName": "Jean-Paul Gaultier",
@@ -490,44 +490,43 @@
                                         "hasAvatar": false,
                                         "vatRegistrationNumber": "VAT1338",
                                         "taxIdentificationNumber": null,
-                                        "createdAt": "@string@.isDateTime()",
-                                        "updatedAt": "@string@.isDateTime()",
+                                        "createdAt": "2020-01-14T15:57:51+01:00",
+                                        "updatedAt": "2020-01-14T15:57:51+01:00",
                                         "enabled": true,
-                                        "shippingOthersMaxDeliveryDays": @integer@,
+                                        "shippingOthersMaxDeliveryDays": 17,
                                         "shippingOriginCountry": "FR",
-                                        "shippingOriginMaxDeliveryDays": @integer@,
+                                        "shippingOriginMaxDeliveryDays": 4,
                                         "type": "designer"
                                     },
                                     "sku": null,
                                     "_links": {
                                         "self": {
-                                            "href": @string@
+                                            "href": "/api/v1/products/GAULTIER-LE-MALE/variants/GAULTIER_LE_MALE"
                                         },
                                         "product": {
-                                            "href": @string@
+                                            "href": "/api/v1/products/GAULTIER-LE-MALE"
                                         }
                                     },
                                     "priceLocalized": "72,95 €",
-                                    "originalPriceLocalized": "72,95 €",
-                                    "isolatedPreviewImage": null
+                                    "originalPriceLocalized": "72,95 €"
                                 }
                             ],
                             "slug": "gaultier-le-male",
                             "options": [],
-                            "id": @integer@,
+                            "id": 5,
                             "code": "GAULTIER-LE-MALE",
                             "attributes": [],
-                            "createdAt": "@string@.isDateTime()",
-                            "updatedAt": "@string@.isDateTime()",
+                            "createdAt": "2013-10-10T08:26:00+02:00",
+                            "updatedAt": "2015-10-05T08:26:00+02:00",
                             "enabled": true,
                             "productTaxons": [],
                             "mainTaxon": null,
                             "images": [],
                             "similarProducts": [],
+                            "isolatedPreviewImage": null,
                             "previewImage": null,
                             "size": null,
                             "color": null,
-                            "topics": [],
                             "designer": {
                                 "billingAddress": {
                                     "addressLine1": "Street 2",
@@ -537,7 +536,7 @@
                                     "region": null,
                                     "country": "FR"
                                 },
-                                "id": @string@,
+                                "id": "0123456789abcdef76543210",
                                 "name": "Jean-Paul Gaultier",
                                 "canonicalName": "jean-paulgaultier",
                                 "displayName": "Jean-Paul Gaultier",
@@ -546,35 +545,34 @@
                                 "hasAvatar": false,
                                 "vatRegistrationNumber": "VAT1338",
                                 "taxIdentificationNumber": null,
-                                "createdAt": "@string@.isDateTime()",
-                                "updatedAt": "@string@.isDateTime()",
+                                "createdAt": "2020-01-14T15:57:51+01:00",
+                                "updatedAt": "2020-01-14T15:57:51+01:00",
                                 "enabled": true,
-                                "shippingOthersMaxDeliveryDays": @integer@,
+                                "shippingOthersMaxDeliveryDays": 17,
                                 "shippingOriginCountry": "FR",
-                                "shippingOriginMaxDeliveryDays": @integer@,
+                                "shippingOriginMaxDeliveryDays": 4,
                                 "type": "designer"
                             },
                             "_links": {
                                 "self": {
-                                    "href": @string@
+                                    "href": "/api/v1/products/GAULTIER-LE-MALE"
                                 },
                                 "variants": {
-                                    "href": @string@
+                                    "href": "/api/v1/products/GAULTIER-LE-MALE/variants/"
                                 }
                             },
                             "lowestPriceLocalized": "72,95 €",
-                            "originalLowestPriceLocalized": "72,95 €",
-                            "isolatedPreviewImage": null
+                            "originalLowestPriceLocalized": "72,95 €"
                         },
                         "variant": {
                             "name": "Mug 5",
                             "descriptor": "Mug 5 (GAULTIER_LE_MALE)",
-                            "id": @integer@,
+                            "id": 5,
                             "code": "GAULTIER_LE_MALE",
                             "optionValues": [],
-                            "position": @integer@,
-                            "onHold": @integer@,
-                            "onHand": @integer@,
+                            "position": 0,
+                            "onHold": 31,
+                            "onHand": 2806,
                             "tracked": true,
                             "channelPricings": {
                                 "EUR": {
@@ -589,9 +587,10 @@
                                 }
                             },
                             "shippingRequired": true,
-                            "buyableStock": @integer@,
+                            "buyableStock": 2775,
                             "sizeValue": null,
                             "colorValue": null,
+                            "isolatedPreviewImage": null,
                             "previewImage": null,
                             "designer": {
                                 "billingAddress": {
@@ -602,7 +601,7 @@
                                     "region": null,
                                     "country": "FR"
                                 },
-                                "id": @string@,
+                                "id": "0123456789abcdef76543210",
                                 "name": "Jean-Paul Gaultier",
                                 "canonicalName": "jean-paulgaultier",
                                 "displayName": "Jean-Paul Gaultier",
@@ -611,46 +610,45 @@
                                 "hasAvatar": false,
                                 "vatRegistrationNumber": "VAT1338",
                                 "taxIdentificationNumber": null,
-                                "createdAt": "@string@.isDateTime()",
-                                "updatedAt": "@string@.isDateTime()",
+                                "createdAt": "2020-01-14T15:57:51+01:00",
+                                "updatedAt": "2020-01-14T15:57:51+01:00",
                                 "enabled": true,
-                                "shippingOthersMaxDeliveryDays": @integer@,
+                                "shippingOthersMaxDeliveryDays": 17,
                                 "shippingOriginCountry": "FR",
-                                "shippingOriginMaxDeliveryDays": @integer@,
+                                "shippingOriginMaxDeliveryDays": 4,
                                 "type": "designer"
                             },
                             "sku": null,
                             "_links": {
                                 "self": {
-                                    "href": @string@
+                                    "href": "/api/v1/products/GAULTIER-LE-MALE/variants/GAULTIER_LE_MALE"
                                 },
                                 "product": {
-                                    "href": @string@
+                                    "href": "/api/v1/products/GAULTIER-LE-MALE"
                                 }
                             },
                             "priceLocalized": "72,95 €",
-                            "originalPriceLocalized": "72,95 €",
-                            "isolatedPreviewImage": null
-                        },
-                        "returnableUnitCount": @integer@,
+                            "originalPriceLocalized": "72,95 €"
+                        },
+                        "returnableUnitCount": 1,
                         "affiliateBlogger": null,
                         "hash": null,
                         "_links": {
                             "order": {
-                                "href": @string@
+                                "href": "/api/v1/orders/3"
                             },
                             "product": {
-                                "href": @string@
+                                "href": "/api/v1/products/GAULTIER-LE-MALE"
                             },
                             "variant": {
-                                "href": @string@
+                                "href": "/api/v1/products/GAULTIER-LE-MALE/variants/GAULTIER_LE_MALE"
                             }
                         },
                         "totalLocalized": "80,99 $",
                         "unitPriceLocalized": "80,99 $"
                     }
                 ],
-                "itemsTotal": @integer@,
+                "itemsTotal": 8099,
                 "shippingState": "ready",
                 "shipments": [],
                 "totalLocalized": "80,99 $"
@@ -666,7 +664,7 @@
                     "region": null,
                     "country": "FR"
                 },
-                "id": @string@,
+                "id": "0123456789abcdef76543210",
                 "name": "Jean-Paul Gaultier",
                 "canonicalName": "jean-paulgaultier",
                 "displayName": "Jean-Paul Gaultier",
@@ -675,21 +673,21 @@
                 "hasAvatar": false,
                 "vatRegistrationNumber": "VAT1338",
                 "taxIdentificationNumber": null,
-                "createdAt": "@string@.isDateTime()",
-                "updatedAt": "@string@.isDateTime()",
+                "createdAt": "2020-01-14T15:57:51+01:00",
+                "updatedAt": "2020-01-14T15:57:51+01:00",
                 "enabled": true,
-                "shippingOthersMaxDeliveryDays": @integer@,
+                "shippingOthersMaxDeliveryDays": 17,
                 "shippingOriginCountry": "FR",
-                "shippingOriginMaxDeliveryDays": @integer@,
+                "shippingOriginMaxDeliveryDays": 4,
                 "type": "designer"
             }
         ],
         "paymentCompletedAt": null,
-        "cancellableAt": "@string@.isDateTime()",
-        "cancellable": true,
-        "shippedUnitCount": @integer@,
+        "cancellableAt": "2020-01-14T15:56:51+01:00",
+        "shippedUnitCount": 0,
         "shippingState": "ready",
         "deliveryUntilOverdue": false,
+        "cancellable": true,
         "removedItems": [],
         "totalLocalized": "80,99 $",
         "limitLocalized": "1.337,00 $",
@@ -698,13 +696,13 @@
     "methodDetails": [],
     "_links": {
         "order": {
-            "href": @string@
+            "href": "/api/v1/orders/3"
         },
         "self": {
-            "href": @string@
+            "href": "/api/v1/payments/3"
         },
         "payment-method": {
-            "href": @string@
+            "href": "/api/v1/payment-methods/mangopay_credit_card"
         }
     }
 }

It's a big pain for us with this library. Anything we can do clean output out of false positives?

lchrusciel commented 4 years ago

PHP Matcher has a backtrace feature added recently. I will take a look at what I can do about it

ostrolucky commented 4 years ago

Can you go into more details how would that feature help here? What's your idea?

pbowyer commented 4 years ago

If we could pass options into \Diff() - or our own instance of \Diff - that would help. I get lots of false positives because the indentation of my JSON files is different to PHP's JSON_PRETTY_PRINT output (2 spaces vs 4). Being able to tell the diff to ignore whitespace would be helpful in my case.

lchrusciel commented 4 years ago

For sure it needs some improvement. Backtrace functionality was not that useful (or perhaps I didn't found a proper solution with it). Any ideas are more than welcome :)

norberttech commented 3 years ago

This is known issue of PHPMatcher, as @lchrusciel mentioned there is a Backtrace feature that keeps a record of all actions taken by matcher. The problem is that in case of failure, there is no easy way to say which matcher exactly failed.

Matcher comes with couple predefined matchers that are used recursively. Meaning that there is for example ScalarMatcher, @string@,@integer@, that is also used inside of ArrayMatcher @array@ that is additionally used by @json@ matcher. Beside those obvious matchers, there are also few custom ones.

Matcher internally is iterating over all registered matchers, checking if it can match given pattern. However json patterns for example are perfectly matchable by @string@ and @json@, obviously @string@ matcher will always fail but it comes first so it will be visible in the backtrace.

If you look at default example in the sandbox https://php-matcher.norbert.tech/ (submit) you should be able to find following failures:

#19 Matcher Coduo\PHPMatcher\Matcher\ScalarMatcher failed to match value 
#24 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (scalars) failed to match value
#50 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (scalars) failed to match value
#53 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (array) failed to match value
#76 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (scalars) failed to match value
#79 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (array) failed to match value
#154 Matcher Coduo\PHPMatcher\Matcher\ScalarMatcher failed to match value
#159 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (scalars) failed to match value
#163 Matcher Coduo\PHPMatcher\Matcher\TextMatcher failed to match value
#165 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (array) failed to match value

so as you see, there is no easy way to select the right failure and in this case, nothing even really failed. If you change the @string@.isDateTime() into @integer@ in the same example it will fail but you will find multiple interesting failures:

#142 Matcher Coduo\PHPMatcher\Matcher\ScalarMatcher failed to match value "2014-01-01" with "@integer@" pattern
#143 Matcher Coduo\PHPMatcher\Matcher\ScalarMatcher error: "2014-01-01" does not match "@integer@".
#147 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (scalars) failed to match value "2014-01-01" with "@integer@"
#148 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (scalars) error: "2014-01-01" does not match "@integer@".
#151 Matcher Coduo\PHPMatcher\Matcher\TextMatcher failed to match value "2014-01-01" with "@integer@" pattern
#153 Matcher Coduo\PHPMatcher\Matcher\ChainMatcher (array) failed to match value "2014-01-01" with "@integer@" 
#155 Matcher Coduo\PHPMatcher\Matcher\ArrayMatcher failed to match value "Array(1)" with "Array(1)" pattern

Long Story Short I don't know how to make error messages more detailed in a generic way that would work for all matchers. Backtrace didn't help here but it still brings values since thanks to it I'm able to visualize matching order.

It was already reported some time ago https://github.com/coduo/php-matcher/issues/197 here, and here https://github.com/coduo/php-matcher/issues/191

I'm open for any ideas about how to improve error message verbosity and reduce it only to different values. I'm not even expecting pull requests or fully baked solutions, ideas are more than welcome, thanks in advance!

norberttech commented 3 years ago

actually I think I found a way to make those error messages a bit more descriptive, https://github.com/coduo/php-matcher/pull/225 - please let me know what do you think, thanks!

norberttech commented 3 years ago

It's live, you can play see the results here - guess this issue can be closed now?

ostrolucky commented 3 years ago

You posted link to localhost, did you intend to do that?

norberttech commented 3 years ago

lol of course not, it's fixed :P

ostrolucky commented 3 years ago

Yep looks awesome. Thanks! Indeed I think we can close :)

lchrusciel commented 3 years ago

@ostrolucky have you checked it already on ApiTestCase? I'm wondering if is there anything we need to provide support for it. Perhaps VoidBacktrace will break it.

norberttech commented 3 years ago

Nah, it should be good out of the box, it's not related to the Backtrace at all