mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-09-21 02:38:20 +03:00
Display source request when there are asserts/runtime errors
This commit is contained in:
parent
e8f6e35a94
commit
22ca0ad934
@ -1,6 +1,8 @@
|
||||
error: Assert body value
|
||||
--> tests_failed/assert_base64.hurl:12:8
|
||||
|
|
||||
| GET http://localhost:8000/assert-base64
|
||||
| ...
|
||||
12 | base64,bGluZTEKbGluZTIKbGluZTMK;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ actual value is <hex, 6c696e65310a6c696e65320d0a6c696e65330a;>
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_bytearray.hurl:4:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-bytearray
|
||||
| ...
|
||||
4 | bytes == hex,00;
|
||||
| actual: byte array <ff>
|
||||
| expected: byte array <00>
|
||||
@ -9,6 +11,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_bytearray.hurl:5:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-bytearray
|
||||
| ...
|
||||
5 | sha256 == hex,a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb88;
|
||||
| actual: byte array <a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89>
|
||||
| expected: byte array <a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb88>
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Decompression error
|
||||
--> tests_failed/assert_content_encoding.hurl:4:1
|
||||
|
|
||||
| GET http://localhost:8000/error/content-encoding
|
||||
| ...
|
||||
4 | `Hello World!`
|
||||
| ^ compression unknown is not supported
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Decompression error
|
||||
--> tests_failed/assert_decompress.hurl:3:1
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-decompress
|
||||
| ...
|
||||
3 | `Hello World!`
|
||||
| ^ could not uncompress response with gzip
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert body value
|
||||
--> tests_failed/assert_file.hurl:8:1
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-file
|
||||
| ...
|
||||
8 | file,data.txt;
|
||||
| ^ actual value is <hex, 48656c6c6f;>
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Header not found
|
||||
--> tests_failed/assert_header_not_found.hurl:3:1
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-header-not-found
|
||||
| ...
|
||||
3 | Custom: ???
|
||||
| ^^^^^^ this header has not been found in the response
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert header value
|
||||
--> tests_failed/assert_header_value.hurl:3:15
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-header-value
|
||||
| ...
|
||||
3 | Content-Type: ???
|
||||
| ^^^ actual value is <text/html; charset=utf-8>
|
||||
|
|
||||
|
@ -1,6 +1,7 @@
|
||||
error: Assert HTTP version
|
||||
--> tests_failed/assert_http_version.hurl:2:1
|
||||
|
|
||||
| GET http://localhost:8000/error-assert/http-version
|
||||
2 | HTTP/2 200
|
||||
| ^^^^^^ actual value is <HTTP/1.1>
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_invalid_predicate_type.hurl:4:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-invalid-predicate-type
|
||||
| ...
|
||||
4 | header "content-type" == 1
|
||||
| actual: string <text/html; charset=utf-8>
|
||||
| expected: int <1>
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid decoding
|
||||
--> tests_failed/assert_match_utf8.hurl:4:1
|
||||
|
|
||||
| GET http://localhost:8000/error-assert/match-utf8
|
||||
| ...
|
||||
4 | body matches ".*"
|
||||
| ^^^^ the body can not be decoded with charset 'utf-8'
|
||||
|
|
||||
|
@ -1 +1 @@
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":2,"success":true},{"line":2,"success":true},{"line":4,"message":"Invalid decoding\n --> tests_failed/assert_match_utf8.hurl:4:1\n |\n 4 | body matches \".*\"\n | ^^^^ the body can not be decoded with charset 'utf-8'\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/error-assert/match-utf8"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"1"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":1,"time":~~~}],"filename":"tests_failed/assert_match_utf8.hurl","success":false,"time":~~~}
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":2,"success":true},{"line":2,"success":true},{"line":4,"message":"Invalid decoding\n --> tests_failed/assert_match_utf8.hurl:4:1\n |\n | GET http://localhost:8000/error-assert/match-utf8\n | ...\n 4 | body matches \".*\"\n | ^^^^ the body can not be decoded with charset 'utf-8'\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/error-assert/match-utf8"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"1"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":1,"time":~~~}],"filename":"tests_failed/assert_match_utf8.hurl","success":false,"time":~~~}
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert body value
|
||||
--> tests_failed/assert_newline.hurl:10:1
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-newline
|
||||
| ...
|
||||
10 | <p>Hello</p>
|
||||
| ^ actual value is <<p>Hello</p>
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_query_cookie.hurl:7:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-query-cookie
|
||||
| ...
|
||||
7 | cookie "cookie1[Secure]" == false # This is not valid, Secure attribute exists or not but does have a value
|
||||
| actual: none
|
||||
| expected: bool <false>
|
||||
@ -9,6 +11,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_query_cookie.hurl:11:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-query-cookie
|
||||
| ...
|
||||
11 | cookie "cookie2[Secure]" == true # This is not valid, Secure attribute exists or not but does have a value
|
||||
| actual: unit
|
||||
| expected: bool <true>
|
||||
@ -18,6 +22,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_query_cookie.hurl:12:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-query-cookie
|
||||
| ...
|
||||
12 | cookie "cookie2[Secure]" not == true # This is not valid, Secure attribute exists or not but does have a value
|
||||
| actual: unit
|
||||
| expected: not bool <true>
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid regex
|
||||
--> tests_failed/assert_query_invalid_regex.hurl:4:7
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-query-invalid-regex
|
||||
| ...
|
||||
4 | regex "[x" exists
|
||||
| ^^^^ regex expression is not valid
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid XPath expression
|
||||
--> tests_failed/assert_query_invalid_xpath.hurl:4:7
|
||||
|
|
||||
| GET http://localhost:8000/utf8
|
||||
| ...
|
||||
4 | xpath "//" == 1
|
||||
| ^^^^ the XPath expression is not valid
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert status code
|
||||
--> tests_failed/assert_status.hurl:9:6
|
||||
|
|
||||
| GET http://localhost:8000/not_found
|
||||
| ...
|
||||
9 | HTTP 200
|
||||
| ^^^ actual value is <404>
|
||||
|
|
||||
|
@ -1 +1 @@
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":9,"success":true},{"line":9,"message":"Assert status code\n --> tests_failed/assert_status.hurl:9:6\n |\n 9 | HTTP 200\n | ^^^ actual value is <404>\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/not_found"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"207"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":404},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":7,"time":~~~}],"filename":"tests_failed/assert_status.hurl","success":false,"time":~~~}
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":9,"success":true},{"line":9,"message":"Assert status code\n --> tests_failed/assert_status.hurl:9:6\n |\n | GET http://localhost:8000/not_found\n | ...\n 9 | HTTP 200\n | ^^^ actual value is <404>\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/not_found"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"207"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":404},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":7,"time":~~~}],"filename":"tests_failed/assert_status.hurl","success":false,"time":~~~}
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Undefined variable
|
||||
--> tests_failed/assert_template_variable_not_found.hurl:4:29
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-template-variable-not-found
|
||||
| ...
|
||||
4 | header "content-type" == "{{content_type}}"
|
||||
| ^^^^^^^^^^^^ you must set the variable content_type
|
||||
|
|
||||
|
@ -1 +1 @@
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":2,"success":true},{"line":2,"success":true},{"line":4,"message":"Undefined variable\n --> tests_failed/assert_template_variable_not_found.hurl:4:29\n |\n 4 | header \"content-type\" == \"{{content_type}}\"\n | ^^^^^^^^^^^^ you must set the variable content_type\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/error-assert-template-variable-not-found"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"0"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":1,"time":~~~}],"filename":"tests_failed/assert_template_variable_not_found.hurl","success":false,"time":~~~}
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":2,"success":true},{"line":2,"success":true},{"line":4,"message":"Undefined variable\n --> tests_failed/assert_template_variable_not_found.hurl:4:29\n |\n | GET http://localhost:8000/error-assert-template-variable-not-found\n | ...\n 4 | header \"content-type\" == \"{{content_type}}\"\n | ^^^^^^^^^^^^ you must set the variable content_type\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/error-assert-template-variable-not-found"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"0"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":1,"time":~~~}],"filename":"tests_failed/assert_template_variable_not_found.hurl","success":false,"time":~~~}
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_value_error.hurl:4:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-value
|
||||
| ...
|
||||
4 | header "content-type" == "XXX"
|
||||
| actual: string <text/html; charset=utf-8>
|
||||
| expected: string <XXX>
|
||||
@ -9,6 +11,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_value_error.hurl:5:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-value
|
||||
| ...
|
||||
5 | header "content-type" != "text/html; charset=utf-8"
|
||||
| actual: string <text/html; charset=utf-8>
|
||||
| expected: string <text/html; charset=utf-8>
|
||||
@ -17,6 +21,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_value_error.hurl:6:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-value
|
||||
| ...
|
||||
6 | jsonpath "$.id" == "000001"
|
||||
| actual: none
|
||||
| expected: string <000001>
|
||||
@ -25,6 +31,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_value_error.hurl:7:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-value
|
||||
| ...
|
||||
7 | jsonpath "$.values" includes 100
|
||||
| actual: [int <1>, int <2>, int <3>]
|
||||
| expected: includes int <100>
|
||||
@ -33,6 +41,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_value_error.hurl:8:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-value
|
||||
| ...
|
||||
8 | jsonpath "$.values" not contains "Hello"
|
||||
| actual: [int <1>, int <2>, int <3>]
|
||||
| expected: not contains string <Hello>
|
||||
@ -42,6 +52,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_value_error.hurl:9:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-value
|
||||
| ...
|
||||
9 | jsonpath "$.count" > 5
|
||||
| actual: int <2>
|
||||
| expected: greater than int <5>
|
||||
@ -50,6 +62,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_value_error.hurl:10:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-value
|
||||
| ...
|
||||
10 | jsonpath "$.count" isFloat
|
||||
| actual: int <2>
|
||||
| expected: float
|
||||
@ -58,6 +72,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_value_error.hurl:11:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-value
|
||||
| ...
|
||||
11 | bytes contains hex,00;
|
||||
| actual: byte array <7b202276616c756573223a205b312c322c335d2c2022636f756e74223a20327d>
|
||||
| expected: contains byte array <00>
|
||||
|
@ -1 +1 @@
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":2,"success":true},{"line":2,"success":true},{"line":4,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:4:0\n |\n 4 | header \"content-type\" == \"XXX\"\n | actual: string <text/html; charset=utf-8>\n | expected: string <XXX>\n |","success":false},{"line":5,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:5:0\n |\n 5 | header \"content-type\" != \"text/html; charset=utf-8\"\n | actual: string <text/html; charset=utf-8>\n | expected: string <text/html; charset=utf-8>\n |","success":false},{"line":6,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:6:0\n |\n 6 | jsonpath \"$.id\" == \"000001\"\n | actual: none\n | expected: string <000001>\n |","success":false},{"line":7,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:7:0\n |\n 7 | jsonpath \"$.values\" includes 100\n | actual: [int <1>, int <2>, int <3>]\n | expected: includes int <100>\n |","success":false},{"line":8,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:8:0\n |\n 8 | jsonpath \"$.values\" not contains \"Hello\"\n | actual: [int <1>, int <2>, int <3>]\n | expected: not contains string <Hello>\n | >>> types between actual and expected are not consistent\n |","success":false},{"line":9,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:9:0\n |\n 9 | jsonpath \"$.count\" > 5\n | actual: int <2>\n | expected: greater than int <5>\n |","success":false},{"line":10,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:10:0\n |\n10 | jsonpath \"$.count\" isFloat\n | actual: int <2>\n | expected: float\n |","success":false},{"line":11,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:11:0\n |\n11 | bytes contains hex,00;\n | actual: byte array <7b202276616c756573223a205b312c322c335d2c2022636f756e74223a20327d>\n | expected: contains byte array <00>\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/error-assert-value"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"32"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":1,"time":~~~}],"filename":"tests_failed/assert_value_error.hurl","success":false,"time":~~~}
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":2,"success":true},{"line":2,"success":true},{"line":4,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:4:0\n |\n | GET http://localhost:8000/error-assert-value\n | ...\n 4 | header \"content-type\" == \"XXX\"\n | actual: string <text/html; charset=utf-8>\n | expected: string <XXX>\n |","success":false},{"line":5,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:5:0\n |\n | GET http://localhost:8000/error-assert-value\n | ...\n 5 | header \"content-type\" != \"text/html; charset=utf-8\"\n | actual: string <text/html; charset=utf-8>\n | expected: string <text/html; charset=utf-8>\n |","success":false},{"line":6,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:6:0\n |\n | GET http://localhost:8000/error-assert-value\n | ...\n 6 | jsonpath \"$.id\" == \"000001\"\n | actual: none\n | expected: string <000001>\n |","success":false},{"line":7,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:7:0\n |\n | GET http://localhost:8000/error-assert-value\n | ...\n 7 | jsonpath \"$.values\" includes 100\n | actual: [int <1>, int <2>, int <3>]\n | expected: includes int <100>\n |","success":false},{"line":8,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:8:0\n |\n | GET http://localhost:8000/error-assert-value\n | ...\n 8 | jsonpath \"$.values\" not contains \"Hello\"\n | actual: [int <1>, int <2>, int <3>]\n | expected: not contains string <Hello>\n | >>> types between actual and expected are not consistent\n |","success":false},{"line":9,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:9:0\n |\n | GET http://localhost:8000/error-assert-value\n | ...\n 9 | jsonpath \"$.count\" > 5\n | actual: int <2>\n | expected: greater than int <5>\n |","success":false},{"line":10,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:10:0\n |\n | GET http://localhost:8000/error-assert-value\n | ...\n10 | jsonpath \"$.count\" isFloat\n | actual: int <2>\n | expected: float\n |","success":false},{"line":11,"message":"Assert failure\n --> tests_failed/assert_value_error.hurl:11:0\n |\n | GET http://localhost:8000/error-assert-value\n | ...\n11 | bytes contains hex,00;\n | actual: byte array <7b202276616c756573223a205b312c322c335d2c2022636f756e74223a20327d>\n | expected: contains byte array <00>\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/error-assert-value"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"32"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":1,"time":~~~}],"filename":"tests_failed/assert_value_error.hurl","success":false,"time":~~~}
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_variable.hurl:8:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-variable
|
||||
| ...
|
||||
8 | variable "toto" == "tata"
|
||||
| actual: none
|
||||
| expected: string <tata>
|
||||
@ -9,6 +11,8 @@ error: Assert failure
|
||||
error: Undefined variable
|
||||
--> tests_failed/assert_variable.hurl:9:24
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-variable
|
||||
| ...
|
||||
9 | variable "status" == {{unknown}}
|
||||
| ^^^^^^^ you must set the variable unknown
|
||||
|
|
||||
@ -16,6 +20,8 @@ error: Undefined variable
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_variable.hurl:10:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-variable
|
||||
| ...
|
||||
10 | variable "status" == {{type}}
|
||||
| actual: int <200>
|
||||
| expected: string <text/html; charset=utf-8>
|
||||
@ -24,6 +30,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/assert_variable.hurl:11:0
|
||||
|
|
||||
| GET http://localhost:8000/error-assert-variable
|
||||
| ...
|
||||
11 | variable "status" == {{length}}
|
||||
| actual: int <200>
|
||||
| expected: string <0>
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid JSON
|
||||
--> tests_failed/body_json.hurl:3:18
|
||||
|
|
||||
| POST https://unused
|
||||
| ...
|
||||
3 | "success": {{success}}
|
||||
| ^^^^^^^ actual value is <invalid>
|
||||
|
|
||||
|
@ -1,6 +1,7 @@
|
||||
error: Assert status code
|
||||
--> tests_failed/continue_on_error.hurl:2:6
|
||||
|
|
||||
| GET http://localhost:8000/continue-on-error
|
||||
2 | HTTP 400
|
||||
| ^^^ actual value is <200>
|
||||
|
|
||||
@ -8,6 +9,7 @@ error: Assert status code
|
||||
error: Assert status code
|
||||
--> tests_failed/continue_on_error.hurl:8:6
|
||||
|
|
||||
| GET http://localhost:8000/continue-on-error
|
||||
8 | HTTP 400
|
||||
| ^^^ actual value is <200>
|
||||
|
|
||||
|
@ -11,6 +11,8 @@ Connection: close
|
||||
error: Assert header value
|
||||
--> tests_failed/error_format_long.hurl:7:15
|
||||
|
|
||||
| GET http://localhost:8000/error-format-long/html
|
||||
| ...
|
||||
7 | Content-Type: text/html
|
||||
| ^^^^^^^^^ actual value is <text/html; charset=utf-8>
|
||||
|
|
||||
@ -18,6 +20,8 @@ error: Assert header value
|
||||
error: Assert failure
|
||||
--> tests_failed/error_format_long.hurl:9:0
|
||||
|
|
||||
| GET http://localhost:8000/error-format-long/html
|
||||
| ...
|
||||
9 | xpath "string(//head/title)" == "Welcome!"
|
||||
| actual: string <Test>
|
||||
| expected: string <Welcome!>
|
||||
@ -26,6 +30,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/error_format_long.hurl:11:0
|
||||
|
|
||||
| GET http://localhost:8000/error-format-long/html
|
||||
| ...
|
||||
11 | xpath "//title" count == 2
|
||||
| actual: int <1>
|
||||
| expected: int <2>
|
||||
@ -44,6 +50,8 @@ Connection: close
|
||||
error: Assert failure
|
||||
--> tests_failed/error_format_long.hurl:18:0
|
||||
|
|
||||
| GET http://localhost:8000/error-format-long/json
|
||||
| ...
|
||||
18 | jsonpath "$.books" count == 12
|
||||
| actual: int <2>
|
||||
| expected: int <12>
|
||||
@ -62,6 +70,8 @@ Connection: close
|
||||
error: Assert failure
|
||||
--> tests_failed/error_format_long.hurl:26:0
|
||||
|
|
||||
| GET http://localhost:8000/error-format-long/rfc-7807
|
||||
| ...
|
||||
26 | jsonpath "$.title" == "You have enough credit."
|
||||
| actual: string <You do not have enough credit.>
|
||||
| expected: string <You have enough credit.>
|
||||
|
@ -2,6 +2,7 @@ The option fail-at-end is deprecated. Use continue-on-error instead
|
||||
error: Assert status code
|
||||
--> tests_failed/fail_at_end.hurl:2:6
|
||||
|
|
||||
| GET http://localhost:8000/fail-at-end
|
||||
2 | HTTP 400
|
||||
| ^^^ actual value is <200>
|
||||
|
|
||||
@ -9,6 +10,7 @@ error: Assert status code
|
||||
error: Assert status code
|
||||
--> tests_failed/fail_at_end.hurl:8:6
|
||||
|
|
||||
| GET http://localhost:8000/fail-at-end
|
||||
8 | HTTP 400
|
||||
| ^^^ actual value is <200>
|
||||
|
|
||||
|
@ -1,6 +1,7 @@
|
||||
error: File read access
|
||||
--> tests_failed/file_read_access.hurl:2:6
|
||||
|
|
||||
| POST http://localhost:8000/error-file-read-access
|
||||
2 | file,does_not_exist;
|
||||
| ^^^^^^^^^^^^^^ file does_not_exist can not be read
|
||||
|
|
||||
|
@ -1,6 +1,7 @@
|
||||
error: Unauthorized file access
|
||||
--> tests_failed/file_unauthorized.hurl:2:6
|
||||
|
|
||||
| POST http://localhost:8000/post-file
|
||||
2 | file,/secret.txt;
|
||||
| ^^^^^^^^^^^ unauthorized access to file /secret.txt, check --file-root option
|
||||
|
|
||||
@ -8,6 +9,7 @@ error: Unauthorized file access
|
||||
error: Unauthorized file access
|
||||
--> tests_failed/file_unauthorized.hurl:7:6
|
||||
|
|
||||
| POST http://localhost:8000/post-file
|
||||
7 | file,../secret.txt;
|
||||
| ^^^^^^^^^^^^^ unauthorized access to file ../secret.txt, check --file-root option
|
||||
|
|
||||
@ -15,6 +17,8 @@ error: Unauthorized file access
|
||||
error: Unauthorized file access
|
||||
--> tests_failed/file_unauthorized.hurl:13:13
|
||||
|
|
||||
| POST http://localhost:8000/post-file
|
||||
| ...
|
||||
13 | file1: file,/secret.txt;
|
||||
| ^^^^^^^^^^^ unauthorized access to file /secret.txt, check --file-root option
|
||||
|
|
||||
@ -22,6 +26,8 @@ error: Unauthorized file access
|
||||
error: Unauthorized file access
|
||||
--> tests_failed/file_unauthorized.hurl:19:13
|
||||
|
|
||||
| POST http://localhost:8000/post-file
|
||||
| ...
|
||||
19 | file1: file,../secret.txt;
|
||||
| ^^^^^^^^^^^^^ unauthorized access to file ../secret.txt, check --file-root option
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Filter Error
|
||||
--> tests_failed/filter.hurl:4:17
|
||||
|
|
||||
| GET http://localhost:8000/error-filter
|
||||
| ...
|
||||
4 | jsonpath "$.id" toInt == 123
|
||||
| ^^^^^ invalid filter input: string <123x>
|
||||
|
|
||||
@ -8,6 +10,8 @@ error: Filter Error
|
||||
error: Filter Error
|
||||
--> tests_failed/filter.hurl:5:21
|
||||
|
|
||||
| GET http://localhost:8000/error-filter
|
||||
| ...
|
||||
5 | jsonpath "$.status" toInt == 0
|
||||
| ^^^^^ invalid filter input: bool <true>
|
||||
|
|
||||
@ -15,6 +19,8 @@ error: Filter Error
|
||||
error: Filter Error
|
||||
--> tests_failed/filter.hurl:6:22
|
||||
|
|
||||
| GET http://localhost:8000/error-filter
|
||||
| ...
|
||||
6 | jsonpath "$.unknown" toInt == 1
|
||||
| ^^^^^ missing value to apply filter
|
||||
|
|
||||
@ -22,6 +28,8 @@ error: Filter Error
|
||||
error: Filter Error
|
||||
--> tests_failed/filter.hurl:7:19
|
||||
|
|
||||
| GET http://localhost:8000/error-filter
|
||||
| ...
|
||||
7 | jsonpath "$.list" nth 5 == 3
|
||||
| ^^^^^ invalid filter input: Out of bound - size is 3
|
||||
|
|
||||
@ -29,6 +37,8 @@ error: Filter Error
|
||||
error: Filter Error
|
||||
--> tests_failed/filter.hurl:8:17
|
||||
|
|
||||
| GET http://localhost:8000/error-filter
|
||||
| ...
|
||||
8 | jsonpath "$.id" toDate "%a, %d %b %Y %H:%M:%S GMT" == "unused"
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid filter input: string <123x>
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Filter Error
|
||||
--> tests_failed/filter_decode.hurl:6:7
|
||||
|
|
||||
| GET http://localhost:8000/filter-decode
|
||||
| ...
|
||||
6 | bytes decode "unknown" == "café" # <unknown> encoding is not supported
|
||||
| ^^^^^^^^^^^^^^^^ <unknown> encoding is not supported
|
||||
|
|
||||
@ -8,6 +10,8 @@ error: Filter Error
|
||||
error: Filter Error
|
||||
--> tests_failed/filter_decode.hurl:7:7
|
||||
|
|
||||
| GET http://localhost:8000/filter-decode
|
||||
| ...
|
||||
7 | bytes decode "arabic" == "café" # value can not be decoded with <arabic> encoding
|
||||
| ^^^^^^^^^^^^^^^ value can not be decoded with <arabic> encoding
|
||||
|
|
||||
@ -15,6 +19,8 @@ error: Filter Error
|
||||
error: Assert failure
|
||||
--> tests_failed/filter_decode.hurl:8:0
|
||||
|
|
||||
| GET http://localhost:8000/filter-decode
|
||||
| ...
|
||||
8 | bytes decode "iso-8859-1" == "café" # value can be decoded but to an invalid string café
|
||||
| actual: string <café>
|
||||
| expected: string <café>
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Filter Error
|
||||
--> tests_failed/filter_in_capture.hurl:4:21
|
||||
|
|
||||
| GET http://localhost:8000/error-filter-in-capture
|
||||
| ...
|
||||
4 | id: jsonpath "$.id" toInt
|
||||
| ^^^^^ invalid filter input: string <123x>
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid decoding
|
||||
--> tests_failed/hello_gb2312_failed.hurl:10:1
|
||||
|
|
||||
| GET http://localhost:8000/hello_gb2312_failed
|
||||
| ...
|
||||
10 | xpath "string(//body)" == "你好世界"
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the body can not be decoded with charset 'utf-8'
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid JSONPath
|
||||
--> tests_failed/invalid_jsonpath.hurl:5:10
|
||||
|
|
||||
| GET http://localhost:8000/error-invalid-jsonpath
|
||||
| ...
|
||||
5 | jsonpath "" == false
|
||||
| ^^ the JSONPath expression '' is not valid
|
||||
|
|
||||
@ -8,6 +10,8 @@ error: Invalid JSONPath
|
||||
error: Invalid JSONPath
|
||||
--> tests_failed/invalid_jsonpath.hurl:6:10
|
||||
|
|
||||
| GET http://localhost:8000/error-invalid-jsonpath
|
||||
| ...
|
||||
6 | jsonpath "$.tags[0]x" == false
|
||||
| ^^^^^^^^^^^^ the JSONPath expression '$.tags[0]x' is not valid
|
||||
|
|
||||
@ -15,6 +19,8 @@ error: Invalid JSONPath
|
||||
error: Invalid JSONPath
|
||||
--> tests_failed/invalid_jsonpath.hurl:7:10
|
||||
|
|
||||
| GET http://localhost:8000/error-invalid-jsonpath
|
||||
| ...
|
||||
7 | jsonpath "$.tags[0,A]" == false
|
||||
| ^^^^^^^^^^^^^ the JSONPath expression '$.tags[0,A]' is not valid
|
||||
|
|
||||
@ -22,6 +28,8 @@ error: Invalid JSONPath
|
||||
error: Invalid JSONPath
|
||||
--> tests_failed/invalid_jsonpath.hurl:8:10
|
||||
|
|
||||
| GET http://localhost:8000/error-invalid-jsonpath
|
||||
| ...
|
||||
8 | jsonpath "$.tags[0:A]" == false
|
||||
| ^^^^^^^^^^^^^ the JSONPath expression '$.tags[0:A]' is not valid
|
||||
|
|
||||
@ -29,6 +37,8 @@ error: Invalid JSONPath
|
||||
error: Invalid JSONPath
|
||||
--> tests_failed/invalid_jsonpath.hurl:9:10
|
||||
|
|
||||
| GET http://localhost:8000/error-invalid-jsonpath
|
||||
| ...
|
||||
9 | jsonpath "$.tags[]" == false
|
||||
| ^^^^^^^^^^ the JSONPath expression '$.tags[]' is not valid
|
||||
|
|
||||
@ -36,6 +46,8 @@ error: Invalid JSONPath
|
||||
error: Invalid JSONPath
|
||||
--> tests_failed/invalid_jsonpath.hurl:10:10
|
||||
|
|
||||
| GET http://localhost:8000/error-invalid-jsonpath
|
||||
| ...
|
||||
10 | jsonpath "$." == false
|
||||
| ^^^^ the JSONPath expression '$.' is not valid
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid XML
|
||||
--> tests_failed/invalid_xml.hurl:4:1
|
||||
|
|
||||
| GET http://localhost:8000/error-invalid-xml
|
||||
| ...
|
||||
4 | xpath "xx" == 1
|
||||
| ^^^^^^^^^^ the HTTP response is not a valid XML
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Undefined variable
|
||||
--> tests_failed/key_template.hurl:4:3
|
||||
|
|
||||
| GET http://localhost:8000/error-key-template
|
||||
| ...
|
||||
4 | {{name}}: value
|
||||
| ^^^^ you must set the variable name
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: File read access
|
||||
--> tests_failed/multipart_form_data.hurl:4:15
|
||||
|
|
||||
| POST http://localhost:8000/unused
|
||||
| ...
|
||||
4 | upload1: file,unknown;
|
||||
| ^^^^^^^ file unknown can not be read
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid variable type
|
||||
--> tests_failed/options_template.hurl:6:13
|
||||
|
|
||||
| GET http://localhost:8000/unused
|
||||
| ...
|
||||
6 | location: {{redirect}}
|
||||
| ^^^^^^^^ expecting boolean, actual value is <10>
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:4:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
4 | jsonpath "$.status" == "true"
|
||||
| actual: bool <true>
|
||||
| expected: string <true>
|
||||
@ -9,6 +11,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:5:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
5 | jsonpath "$.count" == 0
|
||||
| actual: int <1>
|
||||
| expected: int <0>
|
||||
@ -17,6 +21,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:6:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
6 | jsonpath "$.message" == 0
|
||||
| actual: string <0>
|
||||
| expected: int <0>
|
||||
@ -25,6 +31,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:7:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
7 | jsonpath "$.empty" == 0
|
||||
| actual: string <>
|
||||
| expected: int <0>
|
||||
@ -33,6 +41,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:8:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
8 | jsonpath "$.number" == 1.1
|
||||
| actual: float <1.0>
|
||||
| expected: float <1.1>
|
||||
@ -41,6 +51,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:9:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
9 | jsonpath "$.count" startsWith "0"
|
||||
| actual: int <1>
|
||||
| expected: starts with string <0>
|
||||
@ -50,6 +62,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:10:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
10 | jsonpath "$.count" endsWith "0"
|
||||
| actual: int <1>
|
||||
| expected: ends with string <0>
|
||||
@ -59,6 +73,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:11:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
11 | jsonpath "$.count" matches "hi"
|
||||
| actual: int <1>
|
||||
| expected: matches regex <hi>
|
||||
@ -68,6 +84,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:12:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
12 | jsonpath "$.count" isEmpty
|
||||
| actual: int <1>
|
||||
| expected: count equals to 0
|
||||
@ -77,6 +95,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:13:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
13 | jsonpath "$.count" includes "foo"
|
||||
| actual: int <1>
|
||||
| expected: includes string <foo>
|
||||
@ -86,6 +106,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:14:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
14 | jsonpath "$.message" startsWith "hi"
|
||||
| actual: string <0>
|
||||
| expected: starts with string <hi>
|
||||
@ -94,6 +116,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:15:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
15 | jsonpath "$.message" endsWith "hi"
|
||||
| actual: string <0>
|
||||
| expected: ends with string <hi>
|
||||
@ -102,6 +126,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:16:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
16 | jsonpath "$.message" contains "hi"
|
||||
| actual: string <0>
|
||||
| expected: contains string <hi>
|
||||
@ -110,6 +136,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:17:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
17 | jsonpath "$.message" matches "hi"
|
||||
| actual: string <0>
|
||||
| expected: matches regex <hi>
|
||||
@ -118,6 +146,8 @@ error: Assert failure
|
||||
error: Invalid regex
|
||||
--> tests_failed/predicate.hurl:18:22
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
18 | jsonpath "$.message" matches "hi{"
|
||||
| ^^^^^^^^^^^^^ regex expression is not valid
|
||||
|
|
||||
@ -125,6 +155,8 @@ error: Invalid regex
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:19:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
19 | jsonpath "$.message" isEmpty
|
||||
| actual: count equals to 1
|
||||
| expected: count equals to 0
|
||||
@ -133,6 +165,8 @@ error: Assert failure
|
||||
error: Filter Error
|
||||
--> tests_failed/predicate.hurl:20:22
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
20 | jsonpath "$.message" count == 1
|
||||
| ^^^^^ invalid filter input: string
|
||||
|
|
||||
@ -140,6 +174,8 @@ error: Filter Error
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:21:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
21 | jsonpath "$.toto" exists
|
||||
| actual: none
|
||||
| expected: something
|
||||
@ -148,6 +184,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:22:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
22 | jsonpath "$.message" not exists
|
||||
| actual: string <0>
|
||||
| expected: not something
|
||||
@ -156,6 +194,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:23:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
23 | jsonpath "$.list" count == 2
|
||||
| actual: int <3>
|
||||
| expected: int <2>
|
||||
@ -164,6 +204,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:24:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
24 | jsonpath "$.not-exist" == 2
|
||||
| actual: none
|
||||
| expected: integer <2>
|
||||
@ -172,6 +214,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:25:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
25 | jsonpath "$.not-exist" > 3
|
||||
| actual: none
|
||||
| expected: greater than <integer <3>>
|
||||
@ -180,6 +224,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:26:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
26 | jsonpath "$.not-exist" >= 3
|
||||
| actual: none
|
||||
| expected: greater than or equals to <integer <3>>
|
||||
@ -188,6 +234,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:27:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
27 | jsonpath "$.not-exist" < 1
|
||||
| actual: none
|
||||
| expected: less than <integer <1>>
|
||||
@ -196,6 +244,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:28:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
28 | jsonpath "$.not-exist" <= 1
|
||||
| actual: none
|
||||
| expected: less than or equals to <integer <1>>
|
||||
@ -204,6 +254,8 @@ error: Assert failure
|
||||
error: Filter Error
|
||||
--> tests_failed/predicate.hurl:29:24
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
29 | jsonpath "$.not-exist" count == 1
|
||||
| ^^^^^ missing value to apply filter
|
||||
|
|
||||
@ -211,6 +263,8 @@ error: Filter Error
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:30:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
30 | jsonpath "$.not-exist" startsWith "foo"
|
||||
| actual: none
|
||||
| expected: starts with string <foo>
|
||||
@ -219,6 +273,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:31:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
31 | jsonpath "$.not-exist" endsWith "foo"
|
||||
| actual: none
|
||||
| expected: ends with string <foo>
|
||||
@ -227,6 +283,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:32:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
32 | jsonpath "$.not-exist" contains "foo"
|
||||
| actual: none
|
||||
| expected: contains string <foo>
|
||||
@ -235,6 +293,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:33:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
33 | jsonpath "$.not-exist" includes "foo"
|
||||
| actual: none
|
||||
| expected: include string <foo>
|
||||
@ -243,6 +303,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:34:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
34 | jsonpath "$.not-exist" matches /foo/
|
||||
| actual: none
|
||||
| expected: matches regex <foo>
|
||||
@ -251,6 +313,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:35:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
35 | jsonpath "$.not-exist" isInteger
|
||||
| actual: none
|
||||
| expected: integer
|
||||
@ -259,6 +323,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:36:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
36 | jsonpath "$.not-exist" isFloat
|
||||
| actual: none
|
||||
| expected: float
|
||||
@ -267,6 +333,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:37:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
37 | jsonpath "$.not-exist" isBoolean
|
||||
| actual: none
|
||||
| expected: boolean
|
||||
@ -275,6 +343,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:38:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
38 | jsonpath "$.not-exist" isString
|
||||
| actual: none
|
||||
| expected: string
|
||||
@ -283,6 +353,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:39:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
39 | jsonpath "$.not-exist" isCollection
|
||||
| actual: none
|
||||
| expected: collection
|
||||
@ -291,6 +363,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:40:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
40 | jsonpath "$.not-exist" isDate
|
||||
| actual: none
|
||||
| expected: date
|
||||
@ -299,6 +373,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:41:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
41 | jsonpath "$.not-exist" exists
|
||||
| actual: none
|
||||
| expected: something
|
||||
@ -307,6 +383,8 @@ error: Assert failure
|
||||
error: Assert failure
|
||||
--> tests_failed/predicate.hurl:42:0
|
||||
|
|
||||
| GET http://localhost:8000/predicate/error/type
|
||||
| ...
|
||||
42 | jsonpath "$.not-exist" isEmpty
|
||||
| actual: none
|
||||
| expected: empty
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Header not found
|
||||
--> tests_failed/query_header_not_found.hurl:3:1
|
||||
|
|
||||
| GET http://localhost:8000/error-query-header-not-found
|
||||
| ...
|
||||
3 | Custom: XXX
|
||||
| ^^^^^^ this header has not been found in the response
|
||||
|
|
||||
|
@ -1 +1 @@
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":2,"success":true},{"line":2,"success":true},{"line":3,"message":"Header not found\n --> tests_failed/query_header_not_found.hurl:3:1\n |\n 3 | Custom: XXX\n | ^^^^^^ this header has not been found in the response\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/error-query-header-not-found"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"12"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":1,"time":~~~}],"filename":"tests_failed/query_header_not_found.hurl","success":false,"time":~~~}
|
||||
{"cookies":[],"entries":[{"asserts":[{"line":2,"success":true},{"line":2,"success":true},{"line":3,"message":"Header not found\n --> tests_failed/query_header_not_found.hurl:3:1\n |\n | GET http://localhost:8000/error-query-header-not-found\n | ...\n 3 | Custom: XXX\n | ^^^^^^ this header has not been found in the response\n |","success":false}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/error-query-header-not-found"},"response":{"cookies":[],"headers":[{"name":"Server","value":"Werkzeug/~~~ Python/~~~"},{"name":"Date","value":"~~~"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"12"},{"name":"Server","value":"Flask Server"},{"name":"Connection","value":"close"}],"httpVersion":"HTTP/1.1","status":200},"timings":{"app_connect":~~~,"begin_call":"~~~","connect":~~~,"end_call":"~~~","name_lookup":~~~,"pre_transfer":~~~,"start_transfer":~~~,"total":~~~}}],"captures":[],"index":1,"line":1,"time":~~~}],"filename":"tests_failed/query_header_not_found.hurl","success":false,"time":~~~}
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid JSON
|
||||
--> tests_failed/query_invalid_json.hurl:4:1
|
||||
|
|
||||
| GET http://localhost:8000/error-query-invalid-json
|
||||
| ...
|
||||
4 | jsonpath "$.errors" count == 2
|
||||
| ^^^^^^^^^^^^^^^^^^^ the HTTP response is not a valid JSON
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Invalid decoding
|
||||
--> tests_failed/query_invalid_utf8.hurl:4:1
|
||||
|
|
||||
| GET http://localhost:8000/error-query-invalid-utf8
|
||||
| ...
|
||||
4 | jsonpath "$.errors" count == 2
|
||||
| ^^^^^^^^^^^^^^^^^^^ the body can not be decoded with charset 'utf-8'
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Assert failure
|
||||
--> tests_failed/query_match_none.hurl:4:0
|
||||
|
|
||||
| GET http://localhost:8000/query-match-none
|
||||
| ...
|
||||
4 | header "Location" matches /^foo$/
|
||||
| actual: none
|
||||
| expected: matches regex <^foo$>
|
||||
|
@ -30,6 +30,7 @@
|
||||
* Assert status code
|
||||
* --> tests_failed/retry.hurl:2:6
|
||||
* |
|
||||
* | GET http://localhost:8000/not-found
|
||||
* 2 | HTTP 200
|
||||
* | ^^^ actual value is <404>
|
||||
* |
|
||||
@ -65,6 +66,7 @@
|
||||
* Assert status code
|
||||
* --> tests_failed/retry.hurl:2:6
|
||||
* |
|
||||
* | GET http://localhost:8000/not-found
|
||||
* 2 | HTTP 200
|
||||
* | ^^^ actual value is <404>
|
||||
* |
|
||||
@ -100,6 +102,7 @@
|
||||
* Assert status code
|
||||
* --> tests_failed/retry.hurl:2:6
|
||||
* |
|
||||
* | GET http://localhost:8000/not-found
|
||||
* 2 | HTTP 200
|
||||
* | ^^^ actual value is <404>
|
||||
* |
|
||||
@ -135,6 +138,7 @@
|
||||
* Assert status code
|
||||
* --> tests_failed/retry.hurl:2:6
|
||||
* |
|
||||
* | GET http://localhost:8000/not-found
|
||||
* 2 | HTTP 200
|
||||
* | ^^^ actual value is <404>
|
||||
* |
|
||||
@ -170,6 +174,7 @@
|
||||
* Assert status code
|
||||
* --> tests_failed/retry.hurl:2:6
|
||||
* |
|
||||
* | GET http://localhost:8000/not-found
|
||||
* 2 | HTTP 200
|
||||
* | ^^^ actual value is <404>
|
||||
* |
|
||||
@ -207,6 +212,7 @@
|
||||
error: Assert status code
|
||||
--> tests_failed/retry.hurl:2:6
|
||||
|
|
||||
| GET http://localhost:8000/not-found
|
||||
2 | HTTP 200
|
||||
| ^^^ actual value is <404>
|
||||
|
|
||||
|
@ -32,6 +32,8 @@
|
||||
* Assert status code
|
||||
* --> tests_failed/retry_option.hurl:5:6
|
||||
* |
|
||||
* | GET http://localhost:8000/not-found
|
||||
* | ...
|
||||
* 5 | HTTP 200
|
||||
* | ^^^ actual value is <404>
|
||||
* |
|
||||
@ -71,6 +73,8 @@
|
||||
* Assert status code
|
||||
* --> tests_failed/retry_option.hurl:5:6
|
||||
* |
|
||||
* | GET http://localhost:8000/not-found
|
||||
* | ...
|
||||
* 5 | HTTP 200
|
||||
* | ^^^ actual value is <404>
|
||||
* |
|
||||
@ -112,6 +116,8 @@
|
||||
error: Assert status code
|
||||
--> tests_failed/retry_option.hurl:5:6
|
||||
|
|
||||
| GET http://localhost:8000/not-found
|
||||
| ...
|
||||
5 | HTTP 200
|
||||
| ^^^ actual value is <404>
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: Unrenderable variable
|
||||
--> tests_failed/template_variable_not_renderable.hurl:12:9
|
||||
|
|
||||
| GET http://localhost:8000/undefined
|
||||
| ...
|
||||
12 | list: {{list}}
|
||||
| ^^^^ variable <list> with value [1,2,3] can not be rendered
|
||||
|
|
||||
@ -8,6 +10,8 @@ error: Unrenderable variable
|
||||
error: Unrenderable variable
|
||||
--> tests_failed/template_variable_not_renderable.hurl:17:11
|
||||
|
|
||||
| GET http://localhost:8000/undefined
|
||||
| ...
|
||||
17 | object: {{object}}
|
||||
| ^^^^^^ variable <object> with value Object() can not be rendered
|
||||
|
|
||||
@ -15,6 +19,8 @@ error: Unrenderable variable
|
||||
error: Unrenderable variable
|
||||
--> tests_failed/template_variable_not_renderable.hurl:22:12
|
||||
|
|
||||
| GET http://localhost:8000/undefined
|
||||
| ...
|
||||
22 | nodeset: {{nodeset}}
|
||||
| ^^^^^^^ variable <nodeset> with value Nodeset1 can not be rendered
|
||||
|
|
||||
|
@ -4,6 +4,8 @@ tests_ok/test.2.hurl: Running [2/2]
|
||||
error: Assert body value
|
||||
--> tests_ok/test.2.hurl:8:1
|
||||
|
|
||||
| GET http://localhost:8000/hello
|
||||
| ...
|
||||
8 | `Goodbye World!`
|
||||
| ^^^^^^^^^^^^^^^^ actual value is <Hello World!>
|
||||
|
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><testsuites><testsuite tests="2" errors="0" failures="1"><testcase id="tests_ok/test.1.hurl" name="tests_ok/test.1.hurl" time="~~~" /><testcase id="tests_ok/test.2.hurl" name="tests_ok/test.2.hurl" time="~~~"><failure>Assert body value
|
||||
--> tests_ok/test.2.hurl:8:1
|
||||
|
|
||||
| GET http://localhost:8000/hello
|
||||
| ...
|
||||
8 | `Goodbye World!`
|
||||
| ^^^^^^^^^^^^^^^^ actual value is <Hello World!>
|
||||
|</failure></testcase></testsuite><testsuite tests="1" errors="0" failures="0"><testcase id="tests_ok/test.3.hurl" name="tests_ok/test.3.hurl" time="~~~" /></testsuite></testsuites>
|
@ -59,6 +59,8 @@
|
||||
* Assert failure
|
||||
* --> tests_ok/retry.hurl:16:0
|
||||
* |
|
||||
* | GET http://localhost:8000/jobs/{{job_id}}
|
||||
* | ...
|
||||
* 16 | jsonpath "$.state" == "COMPLETED"
|
||||
* | actual: string <RUNNING>
|
||||
* | expected: string <COMPLETED>
|
||||
@ -95,6 +97,8 @@
|
||||
* Assert failure
|
||||
* --> tests_ok/retry.hurl:16:0
|
||||
* |
|
||||
* | GET http://localhost:8000/jobs/{{job_id}}
|
||||
* | ...
|
||||
* 16 | jsonpath "$.state" == "COMPLETED"
|
||||
* | actual: string <RUNNING>
|
||||
* | expected: string <COMPLETED>
|
||||
@ -131,6 +135,8 @@
|
||||
* Assert failure
|
||||
* --> tests_ok/retry.hurl:16:0
|
||||
* |
|
||||
* | GET http://localhost:8000/jobs/{{job_id}}
|
||||
* | ...
|
||||
* 16 | jsonpath "$.state" == "COMPLETED"
|
||||
* | actual: string <RUNNING>
|
||||
* | expected: string <COMPLETED>
|
||||
@ -167,6 +173,8 @@
|
||||
* Assert failure
|
||||
* --> tests_ok/retry.hurl:16:0
|
||||
* |
|
||||
* | GET http://localhost:8000/jobs/{{job_id}}
|
||||
* | ...
|
||||
* 16 | jsonpath "$.state" == "COMPLETED"
|
||||
* | actual: string <RUNNING>
|
||||
* | expected: string <COMPLETED>
|
||||
|
File diff suppressed because one or more lines are too long
@ -61,6 +61,8 @@
|
||||
* Assert failure
|
||||
* --> tests_ok/retry_option.hurl:19:0
|
||||
* |
|
||||
* | GET http://localhost:8000/jobs/{{job_id}}
|
||||
* | ...
|
||||
* 19 | jsonpath "$.state" == "COMPLETED"
|
||||
* | actual: string <RUNNING>
|
||||
* | expected: string <COMPLETED>
|
||||
@ -101,6 +103,8 @@
|
||||
* Assert failure
|
||||
* --> tests_ok/retry_option.hurl:19:0
|
||||
* |
|
||||
* | GET http://localhost:8000/jobs/{{job_id}}
|
||||
* | ...
|
||||
* 19 | jsonpath "$.state" == "COMPLETED"
|
||||
* | actual: string <RUNNING>
|
||||
* | expected: string <COMPLETED>
|
||||
@ -141,6 +145,8 @@
|
||||
* Assert failure
|
||||
* --> tests_ok/retry_option.hurl:19:0
|
||||
* |
|
||||
* | GET http://localhost:8000/jobs/{{job_id}}
|
||||
* | ...
|
||||
* 19 | jsonpath "$.state" == "COMPLETED"
|
||||
* | actual: string <RUNNING>
|
||||
* | expected: string <COMPLETED>
|
||||
@ -181,6 +187,8 @@
|
||||
* Assert failure
|
||||
* --> tests_ok/retry_option.hurl:19:0
|
||||
* |
|
||||
* | GET http://localhost:8000/jobs/{{job_id}}
|
||||
* | ...
|
||||
* 19 | jsonpath "$.state" == "COMPLETED"
|
||||
* | actual: string <RUNNING>
|
||||
* | expected: string <COMPLETED>
|
||||
|
File diff suppressed because one or more lines are too long
@ -4,6 +4,8 @@ tests_ok~test.2.hurl: Running [2/3]
|
||||
error: Assert body value
|
||||
--> tests_ok~test.2.hurl:8:1
|
||||
|
|
||||
| GET http://localhost:8000/hello
|
||||
| ...
|
||||
8 | `Goodbye World!`
|
||||
| ^^^^^^^^^^^^^^^^ actual value is <Hello World!>~
|
||||
|
|
||||
|
@ -16,6 +16,7 @@
|
||||
*
|
||||
*/
|
||||
use chrono::{DateTime, Utc};
|
||||
use hurl_core::ast::SourceInfo;
|
||||
use serde_json::Number;
|
||||
|
||||
use crate::http::{
|
||||
@ -73,7 +74,7 @@ impl EntryResult {
|
||||
let asserts = self
|
||||
.asserts
|
||||
.iter()
|
||||
.map(|a| a.to_json(filename, content))
|
||||
.map(|a| a.to_json(filename, content, self.source_info))
|
||||
.collect();
|
||||
map.insert("asserts".to_string(), asserts);
|
||||
map.insert(
|
||||
@ -329,14 +330,20 @@ impl CaptureResult {
|
||||
}
|
||||
|
||||
impl AssertResult {
|
||||
fn to_json(&self, filename: &str, content: &str) -> serde_json::Value {
|
||||
fn to_json(
|
||||
&self,
|
||||
filename: &str,
|
||||
content: &str,
|
||||
entry_src_info: SourceInfo,
|
||||
) -> serde_json::Value {
|
||||
let mut map = serde_json::Map::new();
|
||||
|
||||
let success = self.error().is_none();
|
||||
map.insert("success".to_string(), serde_json::Value::Bool(success));
|
||||
|
||||
if let Some(err) = self.error() {
|
||||
let message = logger::error_string(filename, content, &err, false);
|
||||
let message =
|
||||
logger::error_string(filename, content, &err, Some(entry_src_info), false);
|
||||
map.insert("message".to_string(), serde_json::Value::String(message));
|
||||
}
|
||||
map.insert(
|
||||
|
@ -259,7 +259,7 @@ fn exit_code(runs: &[HurlRun]) -> i32 {
|
||||
for run in runs.iter() {
|
||||
let errors = run.hurl_result.errors();
|
||||
if errors.is_empty() {
|
||||
} else if errors.iter().filter(|e| !e.assert).count() == 0 {
|
||||
} else if errors.iter().filter(|(error, _)| !error.assert).count() == 0 {
|
||||
count_errors_assert += 1;
|
||||
} else {
|
||||
count_errors_runner += 1;
|
||||
|
@ -60,7 +60,8 @@ impl Testcase {
|
||||
let line = e.source_info.start.line;
|
||||
let column = e.source_info.start.column;
|
||||
let filename = &self.filename;
|
||||
let message = logger::error_string(filename, content, e, false);
|
||||
let message =
|
||||
logger::error_string(filename, content, e, Some(e.source_info), false);
|
||||
// We override the first part of the error string to add an anchor to
|
||||
// the error context.
|
||||
let old = format!("{filename}:{line}:{column}");
|
||||
|
@ -38,7 +38,11 @@ impl Testcase {
|
||||
/// Creates an HTML testcase.
|
||||
pub fn from(hurl_result: &HurlResult, filename: &str) -> Testcase {
|
||||
let id = Uuid::new_v4();
|
||||
let errors = hurl_result.errors().into_iter().cloned().collect();
|
||||
let errors = hurl_result
|
||||
.errors()
|
||||
.into_iter()
|
||||
.map(|(e, _)| e.clone())
|
||||
.collect();
|
||||
Testcase {
|
||||
id: id.to_string(),
|
||||
filename: filename.to_string(),
|
||||
|
@ -208,7 +208,8 @@ mod tests {
|
||||
<testcase id=\"-\" name=\"-\" time=\"0.230\">\
|
||||
<failure>Assert status code\n \
|
||||
--> -:2:10\n \
|
||||
|\n \
|
||||
|\n \
|
||||
| GET http://localhost:8000/not_found\n \
|
||||
2 | HTTP/1.0 200\n \
|
||||
| ^^^ actual value is <404>\n \
|
||||
|\
|
||||
|
@ -37,8 +37,9 @@ impl Testcase {
|
||||
let mut failures = vec![];
|
||||
let mut errors = vec![];
|
||||
|
||||
for error in hurl_result.errors() {
|
||||
let message = logger::error_string(filename, content, error, false);
|
||||
for (error, entry_src_info) in hurl_result.errors() {
|
||||
let message =
|
||||
logger::error_string(filename, content, error, Some(entry_src_info), false);
|
||||
if error.assert {
|
||||
failures.push(message);
|
||||
} else {
|
||||
@ -146,6 +147,7 @@ HTTP/1.0 200
|
||||
r#"<?xml version="1.0" encoding="utf-8"?><testcase id="test.hurl" name="test.hurl" time="0.230"><failure>Assert status code
|
||||
--> test.hurl:2:10
|
||||
|
|
||||
| GET http://localhost:8000/not_found
|
||||
2 | HTTP/1.0 200
|
||||
| ^^^ actual value is <404>
|
||||
|</failure></testcase>"#
|
||||
|
@ -83,7 +83,7 @@ pub fn run(
|
||||
let hurl_file = match hurl_file {
|
||||
Ok(h) => h,
|
||||
Err(e) => {
|
||||
logger.error_rich(content, &e);
|
||||
logger.error_parsing_rich(content, &e);
|
||||
return Err(e.description());
|
||||
}
|
||||
};
|
||||
@ -460,7 +460,7 @@ fn log_errors(entry_result: &EntryResult, content: &str, retry: bool, logger: &L
|
||||
entry_result
|
||||
.errors
|
||||
.iter()
|
||||
.for_each(|e| logger.debug_error(content, e));
|
||||
.for_each(|e| logger.debug_error(content, e, entry_result.source_info));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -475,7 +475,7 @@ fn log_errors(entry_result: &EntryResult, content: &str, retry: bool, logger: &L
|
||||
entry_result
|
||||
.errors
|
||||
.iter()
|
||||
.for_each(|e| logger.error_rich(content, e));
|
||||
.for_each(|error| logger.error_runtime_rich(content, error, entry_result.source_info));
|
||||
}
|
||||
|
||||
/// Creates a new logger for this entry.
|
||||
|
@ -32,19 +32,25 @@ pub struct HurlResult {
|
||||
}
|
||||
|
||||
impl HurlResult {
|
||||
/// Returns all the effective errors of this `HurlResult`.
|
||||
/// Returns all the effective errors of this `HurlResult`, with the source information
|
||||
/// of the entry where the error happens.
|
||||
///
|
||||
/// The errors are only the "effective" ones: those that are due to retry are
|
||||
/// ignored.
|
||||
pub fn errors(&self) -> Vec<&Error> {
|
||||
pub fn errors(&self) -> Vec<(&Error, SourceInfo)> {
|
||||
let mut errors = vec![];
|
||||
let mut next_entries = self.entries.iter().skip(1);
|
||||
for entry in self.entries.iter() {
|
||||
match next_entries.next() {
|
||||
None => errors.extend(&entry.errors),
|
||||
None => {
|
||||
let new_errors = entry.errors.iter().map(|error| (error, entry.source_info));
|
||||
errors.extend(new_errors);
|
||||
}
|
||||
Some(next) => {
|
||||
if next.entry_index != entry.entry_index {
|
||||
errors.extend(&entry.errors)
|
||||
let new_errors =
|
||||
entry.errors.iter().map(|error| (error, entry.source_info));
|
||||
errors.extend(new_errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
use std::cmp::max;
|
||||
|
||||
use colored::*;
|
||||
use hurl_core::ast::SourceInfo;
|
||||
use hurl_core::error::Error;
|
||||
|
||||
use crate::runner::{HurlResult, Value};
|
||||
@ -227,14 +228,14 @@ impl Logger {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debug_error<E: Error>(&self, content: &str, error: &E) {
|
||||
pub fn debug_error<E: Error>(&self, content: &str, error: &E, entry_src_info: SourceInfo) {
|
||||
if self.verbosity.is_none() {
|
||||
return;
|
||||
}
|
||||
if self.color {
|
||||
log_debug_error(&self.filename, content, error)
|
||||
log_debug_error(&self.filename, content, error, entry_src_info)
|
||||
} else {
|
||||
log_debug_error_no_color(&self.filename, content, error)
|
||||
log_debug_error_no_color(&self.filename, content, error, entry_src_info)
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,11 +299,24 @@ impl Logger {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error_rich<E: Error>(&self, content: &str, error: &E) {
|
||||
pub fn error_parsing_rich<E: Error>(&self, content: &str, error: &E) {
|
||||
if self.color {
|
||||
log_error_rich(&self.filename, content, error)
|
||||
log_error_rich(&self.filename, content, error, None)
|
||||
} else {
|
||||
log_error_rich_no_color(&self.filename, content, error)
|
||||
log_error_rich_no_color(&self.filename, content, error, None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error_runtime_rich<E: Error>(
|
||||
&self,
|
||||
content: &str,
|
||||
error: &E,
|
||||
entry_src_info: SourceInfo,
|
||||
) {
|
||||
if self.color {
|
||||
log_error_rich(&self.filename, content, error, Some(entry_src_info))
|
||||
} else {
|
||||
log_error_rich_no_color(&self.filename, content, error, Some(entry_src_info))
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,13 +426,18 @@ fn log_debug_important(message: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
fn log_debug_error<E: Error>(filename: &str, content: &str, error: &E) {
|
||||
let message = error_string(filename, content, error, true);
|
||||
fn log_debug_error<E: Error>(filename: &str, content: &str, error: &E, entry_src_info: SourceInfo) {
|
||||
let message = error_string(filename, content, error, Some(entry_src_info), true);
|
||||
split_lines(&message).iter().for_each(|l| log_debug(l));
|
||||
}
|
||||
|
||||
fn log_debug_error_no_color<E: Error>(filename: &str, content: &str, error: &E) {
|
||||
let message = error_string(filename, content, error, false);
|
||||
fn log_debug_error_no_color<E: Error>(
|
||||
filename: &str,
|
||||
content: &str,
|
||||
error: &E,
|
||||
entry_src_info: SourceInfo,
|
||||
) {
|
||||
let message = error_string(filename, content, error, Some(entry_src_info), false);
|
||||
split_lines(&message)
|
||||
.iter()
|
||||
.for_each(|l| log_debug_no_color(l));
|
||||
@ -472,13 +491,23 @@ fn log_error_no_color(message: &str) {
|
||||
eprintln!("error: {message}");
|
||||
}
|
||||
|
||||
fn log_error_rich<E: Error>(filename: &str, content: &str, error: &E) {
|
||||
let message = error_string(filename, content, error, true);
|
||||
fn log_error_rich<E: Error>(
|
||||
filename: &str,
|
||||
content: &str,
|
||||
error: &E,
|
||||
entry_src_info: Option<SourceInfo>,
|
||||
) {
|
||||
let message = error_string(filename, content, error, entry_src_info, true);
|
||||
eprintln!("{}: {}\n", "error".red().bold(), &message)
|
||||
}
|
||||
|
||||
fn log_error_rich_no_color<E: Error>(filename: &str, content: &str, error: &E) {
|
||||
let message = error_string(filename, content, error, false);
|
||||
fn log_error_rich_no_color<E: Error>(
|
||||
filename: &str,
|
||||
content: &str,
|
||||
error: &E,
|
||||
entry_src_info: Option<SourceInfo>,
|
||||
) {
|
||||
let message = error_string(filename, content, error, entry_src_info, false);
|
||||
eprintln!("error: {}\n", &message)
|
||||
}
|
||||
|
||||
@ -551,6 +580,8 @@ fn log_test_completed_no_color(result: &HurlResult, filename: &str) {
|
||||
|
||||
/// Returns the string representation of an `error`, given `lines` of content and a `filename`.
|
||||
///
|
||||
/// The source information where the error occurred can be retrieved in `error`; optionally,
|
||||
/// `entry_src_info` is the optional source information for the entry where the error happened.
|
||||
/// If `colored` is true, the string use ANSI escape codes to add color and improve the readability
|
||||
/// of the representation.
|
||||
///
|
||||
@ -568,20 +599,23 @@ pub(crate) fn error_string<E: Error>(
|
||||
filename: &str,
|
||||
content: &str,
|
||||
error: &E,
|
||||
entry_src_info: Option<SourceInfo>,
|
||||
colored: bool,
|
||||
) -> String {
|
||||
let mut text = String::new();
|
||||
let lines = split_lines(content);
|
||||
let entry_line = entry_src_info.map(|e| e.start.line);
|
||||
let error_line = error.source_info().start.line;
|
||||
let error_column = error.source_info().start.column;
|
||||
// The number of digits of the lines count.
|
||||
let line_number_size = max(lines.len().to_string().len(), 2);
|
||||
let loc_max_width = max(lines.len().to_string().len(), 2);
|
||||
let separator = "|";
|
||||
let separator = if colored {
|
||||
"|".blue().bold().to_string()
|
||||
separator.blue().bold().to_string()
|
||||
} else {
|
||||
"|".to_string()
|
||||
separator.to_string()
|
||||
};
|
||||
let spaces = " ".repeat(line_number_size);
|
||||
let spaces = " ".repeat(loc_max_width);
|
||||
let prefix = format!("{spaces} {separator}");
|
||||
|
||||
// 1. First line is the description, ex. `Assert status code`.
|
||||
@ -594,38 +628,53 @@ pub(crate) fn error_string<E: Error>(
|
||||
text.push('\n');
|
||||
|
||||
// 2. Second line is the filename info, ex. ` --> test.hurl:2:10`
|
||||
let arrow = "-->";
|
||||
let arrow = if colored {
|
||||
"-->".blue().bold().to_string()
|
||||
arrow.blue().bold().to_string()
|
||||
} else {
|
||||
"-->".to_string()
|
||||
arrow.to_string()
|
||||
};
|
||||
let file_line = format!("{spaces}{arrow} {filename}:{error_line}:{error_column}");
|
||||
text.push_str(&file_line);
|
||||
let line = format!("{spaces}{arrow} {filename}:{error_line}:{error_column}");
|
||||
text.push_str(&line);
|
||||
text.push('\n');
|
||||
|
||||
// 3. Appends line separator.
|
||||
text.push_str(&prefix);
|
||||
text.push('\n');
|
||||
|
||||
// 4. Then, we build error line (whitespace is uniformized)
|
||||
// ex. ` 2 | HTTP/1.0 200`
|
||||
let line_raw = lines.get(error_line - 1).unwrap();
|
||||
let line = line_raw.replace('\t', " ");
|
||||
let width = line_number_size;
|
||||
let mut line_number = format!("{error_line:>width$}");
|
||||
if colored {
|
||||
line_number = line_number.blue().bold().to_string();
|
||||
// 4. Appends the optional entry line.
|
||||
if let Some(entry_line) = entry_line {
|
||||
if entry_line != error_line {
|
||||
let line = lines.get(entry_line - 1).unwrap();
|
||||
let line = if colored {
|
||||
line.bright_black().to_string()
|
||||
} else {
|
||||
line.to_string()
|
||||
};
|
||||
text.push_str(&prefix);
|
||||
text.push(' ');
|
||||
text.push_str(&line);
|
||||
text.push('\n');
|
||||
}
|
||||
if error_line - entry_line > 1 {
|
||||
text.push_str(&prefix);
|
||||
let dots = " ...\n";
|
||||
let dots = if colored {
|
||||
dots.bright_black().to_string()
|
||||
} else {
|
||||
dots.to_string()
|
||||
};
|
||||
text.push_str(&dots);
|
||||
}
|
||||
}
|
||||
text.push_str(&line_number);
|
||||
text.push(' ');
|
||||
text.push_str(&separator);
|
||||
if !line.is_empty() {
|
||||
text.push(' ');
|
||||
text.push_str(&line);
|
||||
};
|
||||
|
||||
// 5. Then, we build error line (whitespace is uniformized)
|
||||
// ex. ` 2 | HTTP/1.0 200`
|
||||
let line = line_with_loc(&lines, error_line, &separator, colored);
|
||||
text.push_str(&line);
|
||||
text.push('\n');
|
||||
|
||||
// 5. Then, we append the error detailed message:
|
||||
// 6. Then, we append the error detailed message:
|
||||
// ```
|
||||
// | actual: byte array <ff>
|
||||
// | expected: byte array <00>
|
||||
@ -645,6 +694,7 @@ pub(crate) fn error_string<E: Error>(
|
||||
// tabs with 4 spaces.
|
||||
// TODO: add a unit test with tabs in source info.
|
||||
let mut tab_shift = 0;
|
||||
let line_raw = lines.get(error_line - 1).unwrap();
|
||||
for (i, c) in line_raw.chars().enumerate() {
|
||||
if i >= error_column - 1 {
|
||||
break;
|
||||
@ -681,6 +731,27 @@ pub(crate) fn error_string<E: Error>(
|
||||
text
|
||||
}
|
||||
|
||||
/// Returns the `line` count prefix.
|
||||
/// Example: ` 45 `
|
||||
fn line_with_loc(lines: &[&str], loc: usize, separator: &str, colored: bool) -> String {
|
||||
let mut text = String::new();
|
||||
let loc_max_width = max(lines.len().to_string().len(), 2);
|
||||
let line = lines.get(loc - 1).unwrap();
|
||||
let line = line.replace('\t', " ");
|
||||
let mut line_number = format!("{loc:>loc_max_width$}");
|
||||
if colored {
|
||||
line_number = line_number.blue().bold().to_string();
|
||||
}
|
||||
text.push_str(&line_number);
|
||||
text.push(' ');
|
||||
text.push_str(separator);
|
||||
if !line.is_empty() {
|
||||
text.push(' ');
|
||||
text.push_str(&line);
|
||||
}
|
||||
text
|
||||
}
|
||||
|
||||
/// Prefixes each line of the string `s` with a `prefix` and returns the new string.
|
||||
/// If `colored` is true, each line is colored with ANSI escape codes.
|
||||
fn add_line_prefix(s: &str, prefix: &str, colored: bool) -> String {
|
||||
@ -717,6 +788,26 @@ pub mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_timeout() {
|
||||
let content = "GET http://unknown";
|
||||
let filename = "test.hurl";
|
||||
let inner =
|
||||
runner::RunnerError::HttpConnection("(6) Could not resolve host: unknown".to_string());
|
||||
let error_source_info = SourceInfo::new(Pos::new(1, 5), Pos::new(1, 19));
|
||||
let entry_source_info = SourceInfo::new(Pos::new(1, 1), Pos::new(1, 19));
|
||||
let error = runner::Error::new(error_source_info, inner, true);
|
||||
assert_eq!(
|
||||
error_string(filename, content, &error, Some(entry_source_info), false),
|
||||
r#"HTTP connection
|
||||
--> test.hurl:1:5
|
||||
|
|
||||
1 | GET http://unknown
|
||||
| ^^^^^^^^^^^^^^ (6) Could not resolve host: unknown
|
||||
|"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assert_error_status() {
|
||||
let content = r#"GET http://unknown
|
||||
@ -726,16 +817,15 @@ HTTP/1.0 200
|
||||
let inner = runner::RunnerError::AssertStatus {
|
||||
actual: "404".to_string(),
|
||||
};
|
||||
let error = runner::Error::new(
|
||||
SourceInfo::new(Pos::new(2, 10), Pos::new(2, 13)),
|
||||
inner,
|
||||
true,
|
||||
);
|
||||
let error_source_info = SourceInfo::new(Pos::new(2, 10), Pos::new(2, 13));
|
||||
let entry_source_info = SourceInfo::new(Pos::new(1, 1), Pos::new(1, 18));
|
||||
let error = runner::Error::new(error_source_info, inner, true);
|
||||
assert_eq!(
|
||||
error_string(filename, content, &error, false),
|
||||
error_string(filename, content, &error, Some(entry_source_info), false),
|
||||
r#"Assert status code
|
||||
--> test.hurl:2:10
|
||||
|
|
||||
| GET http://unknown
|
||||
2 | HTTP/1.0 200
|
||||
| ^^^ actual value is <404>
|
||||
|"#
|
||||
@ -750,16 +840,20 @@ HTTP/1.0 200
|
||||
xpath "strong(//head/title)" == "Hello"
|
||||
"#;
|
||||
let filename = "test.hurl";
|
||||
let error_source_info = SourceInfo::new(Pos::new(4, 7), Pos::new(4, 29));
|
||||
let entry_source_info = SourceInfo::new(Pos::new(1, 1), Pos::new(1, 22));
|
||||
let error = runner::Error::new(
|
||||
SourceInfo::new(Pos::new(4, 7), Pos::new(4, 29)),
|
||||
error_source_info,
|
||||
runner::RunnerError::QueryInvalidXpathEval,
|
||||
true,
|
||||
);
|
||||
assert_eq!(
|
||||
error_string(filename, content, &error, false),
|
||||
error_string(filename, content, &error, Some(entry_source_info), false),
|
||||
r#"Invalid XPath expression
|
||||
--> test.hurl:4:7
|
||||
|
|
||||
| GET http://example.com
|
||||
| ...
|
||||
4 | xpath "strong(//head/title)" == "Hello"
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the XPath expression is not valid
|
||||
|"#
|
||||
@ -774,8 +868,10 @@ HTTP/1.0 200
|
||||
jsonpath "$.count" >= 5
|
||||
"#;
|
||||
let filename = "test.hurl";
|
||||
let error_source_info = SourceInfo::new(Pos::new(4, 0), Pos::new(4, 0));
|
||||
let entry_source_info = SourceInfo::new(Pos::new(1, 1), Pos::new(1, 14));
|
||||
let error = runner::Error {
|
||||
source_info: SourceInfo::new(Pos::new(4, 0), Pos::new(4, 0)),
|
||||
source_info: error_source_info,
|
||||
inner: runner::RunnerError::AssertFailure {
|
||||
actual: "int <2>".to_string(),
|
||||
expected: "greater than int <5>".to_string(),
|
||||
@ -784,10 +880,12 @@ jsonpath "$.count" >= 5
|
||||
assert: true,
|
||||
};
|
||||
assert_eq!(
|
||||
error_string(filename, content, &error, false),
|
||||
error_string(filename, content, &error, Some(entry_source_info), false),
|
||||
r#"Assert failure
|
||||
--> test.hurl:4:0
|
||||
|
|
||||
| GET http://api
|
||||
| ...
|
||||
4 | jsonpath "$.count" >= 5
|
||||
| actual: int <2>
|
||||
| expected: greater than int <5>
|
||||
@ -807,17 +905,40 @@ HTTP/1.0 200
|
||||
actual: "<p>Hello</p>\n\n".to_string(),
|
||||
expected: "<p>Hello</p>\n".to_string(),
|
||||
};
|
||||
let error =
|
||||
runner::Error::new(SourceInfo::new(Pos::new(3, 4), Pos::new(4, 1)), inner, true);
|
||||
let error_source_info = SourceInfo::new(Pos::new(3, 4), Pos::new(4, 1));
|
||||
let entry_source_info = SourceInfo::new(Pos::new(1, 1), Pos::new(1, 20));
|
||||
let error = runner::Error::new(error_source_info, inner, true);
|
||||
assert_eq!(
|
||||
error_string(filename, content, &error, false),
|
||||
error_string(filename, content, &error, Some(entry_source_info), false),
|
||||
r#"Assert body value
|
||||
--> test.hurl:3:4
|
||||
|
|
||||
| GET http://localhost
|
||||
| ...
|
||||
3 | ```<p>Hello</p>
|
||||
| ^ actual value is <<p>Hello</p>
|
||||
|
||||
>
|
||||
|"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parsing_error() {
|
||||
let content = "GET abc";
|
||||
let filename = "test.hurl";
|
||||
let error = hurl_core::parser::Error {
|
||||
pos: Pos::new(1, 5),
|
||||
recoverable: false,
|
||||
inner: hurl_core::parser::ParseError::UrlInvalidStart,
|
||||
};
|
||||
assert_eq!(
|
||||
error_string(filename, content, &error, None, false),
|
||||
r#"Parsing URL
|
||||
--> test.hurl:1:5
|
||||
|
|
||||
1 | GET abc
|
||||
| ^ expecting http://, https:// or {{
|
||||
|"#
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user