mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-23 00:44:55 +03:00
Include carets in fixme message
This commit is contained in:
parent
151a139701
commit
ff7ff9543d
@ -2,6 +2,6 @@
|
||||
[1;34m-->[0m tests_error_parser/parallel_parsing_error_c.hurl:4:5
|
||||
[1;34m |[0m
|
||||
[1;34m 4 |[0m GET //localhost:8000/hello
|
||||
[1;34m |[0m[1;31m ^ [0m[1;31mexpecting http://, https:// or {{[0m
|
||||
[1;34m |[0m[1;31m ^ expecting http://, https:// or {{[0m
|
||||
[1;34m |[0m
|
||||
|
||||
|
@ -4,34 +4,34 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/error/multiline[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 4 |[0m {
|
||||
[1;34m |[0m[1;31m ^ [0m[1;31mactual value is <{[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "first_name": "John",[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "last_name": "Smith",[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "is_alive": true,[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "age": 28,[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "address": {[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "street_address": "21 2nd Street",[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "city": "New York",[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "state": "NY",[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "postal_code": "10021-3100"[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m },[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "phone_numbers": [[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m {[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "type": "home",[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "number": "212 555-1234"[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m },[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m {[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "type": "office",[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "number": "646 555-4567"[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m }[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m ],[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "children": [[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "Catherine",[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "Thomas",[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "Trevor"[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m ],[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m "spouse": null[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m}[0m
|
||||
[1;34m |[0m[1;31m [0m[1;31m>[0m
|
||||
[1;34m |[0m[1;31m ^ actual value is <{[0m
|
||||
[1;34m |[0m[1;31m "first_name": "John",[0m
|
||||
[1;34m |[0m[1;31m "last_name": "Smith",[0m
|
||||
[1;34m |[0m[1;31m "is_alive": true,[0m
|
||||
[1;34m |[0m[1;31m "age": 28,[0m
|
||||
[1;34m |[0m[1;31m "address": {[0m
|
||||
[1;34m |[0m[1;31m "street_address": "21 2nd Street",[0m
|
||||
[1;34m |[0m[1;31m "city": "New York",[0m
|
||||
[1;34m |[0m[1;31m "state": "NY",[0m
|
||||
[1;34m |[0m[1;31m "postal_code": "10021-3100"[0m
|
||||
[1;34m |[0m[1;31m },[0m
|
||||
[1;34m |[0m[1;31m "phone_numbers": [[0m
|
||||
[1;34m |[0m[1;31m {[0m
|
||||
[1;34m |[0m[1;31m "type": "home",[0m
|
||||
[1;34m |[0m[1;31m "number": "212 555-1234"[0m
|
||||
[1;34m |[0m[1;31m },[0m
|
||||
[1;34m |[0m[1;31m {[0m
|
||||
[1;34m |[0m[1;31m "type": "office",[0m
|
||||
[1;34m |[0m[1;31m "number": "646 555-4567"[0m
|
||||
[1;34m |[0m[1;31m }[0m
|
||||
[1;34m |[0m[1;31m ],[0m
|
||||
[1;34m |[0m[1;31m "children": [[0m
|
||||
[1;34m |[0m[1;31m "Catherine",[0m
|
||||
[1;34m |[0m[1;31m "Thomas",[0m
|
||||
[1;34m |[0m[1;31m "Trevor"[0m
|
||||
[1;34m |[0m[1;31m ],[0m
|
||||
[1;34m |[0m[1;31m "spouse": null[0m
|
||||
[1;34m |[0m[1;31m }[0m
|
||||
[1;34m |[0m[1;31m >[0m
|
||||
[1;34m |[0m
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 6 |[0m `Hello World`
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^ [0m[1;31mactual value is <Hello World!>[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^ actual value is <Hello World!>[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mAssert failure[0m
|
||||
@ -13,8 +13,8 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 12 |[0m body == "Hello World"
|
||||
[1;34m |[0m[1;31m[0m[1;31m actual: string <Hello World!>[0m
|
||||
[1;34m |[0m[1;31m[0m[1;31m expected: string <Hello World>[0m
|
||||
[1;34m |[0m[1;31m actual: string <Hello World!>[0m
|
||||
[1;34m |[0m[1;31m expected: string <Hello World>[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mAssert header value[0m
|
||||
@ -23,7 +23,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 17 |[0m Content-Length: 200
|
||||
[1;34m |[0m[1;31m ^^^ [0m[1;31mactual value is <12>[0m
|
||||
[1;34m |[0m[1;31m ^^^ actual value is <12>[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mAssert status code[0m
|
||||
@ -31,7 +31,7 @@
|
||||
[1;34m |[0m
|
||||
[1;34m |[0m [90mGET http://localhost:8000/undefined[0m
|
||||
[1;34m 21 |[0m HTTP 200
|
||||
[1;34m |[0m[1;31m ^^^ [0m[1;31mactual value is <404>[0m
|
||||
[1;34m |[0m[1;31m ^^^ actual value is <404>[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mAssert HTTP version[0m
|
||||
@ -39,7 +39,7 @@
|
||||
[1;34m |[0m
|
||||
[1;34m |[0m [90mGET http://localhost:8000/undefined[0m
|
||||
[1;34m 25 |[0m HTTP/3 *
|
||||
[1;34m |[0m[1;31m ^^^^^^ [0m[1;31mactual value is <HTTP/1.1>[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^ actual value is <HTTP/1.1>[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mDecompression error[0m
|
||||
@ -48,7 +48,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors/could_not_uncompress[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 31 |[0m body startsWith "Hello"
|
||||
[1;34m |[0m[1;31m ^^^^ [0m[1;31mcould not uncompress response with brotli[0m
|
||||
[1;34m |[0m[1;31m ^^^^ could not uncompress response with brotli[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mFile read access[0m
|
||||
@ -56,7 +56,7 @@
|
||||
[1;34m |[0m
|
||||
[1;34m |[0m [90mGET http://localhost:8000/undefined[0m
|
||||
[1;34m 35 |[0m file,undefined.txt;
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^ [0m[1;31mfile undefined.txt can not be read[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^ file undefined.txt can not be read[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;33mwarning[0m: [1mtests_failed~~~output can not be written (~~~)[0m
|
||||
@ -66,7 +66,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 46 |[0m md5 decode "utf-8" == "café"
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^ [0m[1;31mvalue can not be decoded with <utf-8> encoding[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^ value can not be decoded with <utf-8> encoding[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mFilter error[0m
|
||||
@ -75,7 +75,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 52 |[0m bytes decode "toto" == "café"
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^ [0m[1;31m<toto> encoding is not supported[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^ <toto> encoding is not supported[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mFilter error[0m
|
||||
@ -84,7 +84,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 58 |[0m body toInt == 1
|
||||
[1;34m |[0m[1;31m ^^^^^ [0m[1;31minvalid filter input: string <Hello World!>[0m
|
||||
[1;34m |[0m[1;31m ^^^^^ invalid filter input: string <Hello World!>[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mFilter error[0m
|
||||
@ -93,14 +93,14 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 64 |[0m header "count" toInt == 1
|
||||
[1;34m |[0m[1;31m ^^^^^ [0m[1;31mmissing value to apply filter[0m
|
||||
[1;34m |[0m[1;31m ^^^^^ missing value to apply filter[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mHTTP connection[0m
|
||||
[1;34m-->[0m tests_failed/runner_errors.hurl:67:5
|
||||
[1;34m |[0m
|
||||
[1;34m 67 |[0m GET http://unknown
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^ [0m[1;31m(6) Could not resolve host: unknown[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^ (6) Could not resolve host: unknown[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid charset[0m
|
||||
@ -109,7 +109,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors/invalid-charset[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 73 |[0m body == "Hello"
|
||||
[1;34m |[0m[1;31m ^^^^ [0m[1;31mthe charset 'unknown' is not valid[0m
|
||||
[1;34m |[0m[1;31m ^^^^ the charset 'unknown' is not valid[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid decoding[0m
|
||||
@ -118,7 +118,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors/invalid-decoding[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 79 |[0m body == "Hello"
|
||||
[1;34m |[0m[1;31m ^^^^ [0m[1;31mthe body can not be decoded with charset 'utf-8'[0m
|
||||
[1;34m |[0m[1;31m ^^^^ the body can not be decoded with charset 'utf-8'[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid JSON[0m
|
||||
@ -127,7 +127,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 85 |[0m { "a": {{x}} }
|
||||
[1;34m |[0m[1;31m ^ [0m[1;31mactual value is <a>[0m
|
||||
[1;34m |[0m[1;31m ^ actual value is <a>[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid regex[0m
|
||||
@ -136,14 +136,14 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m 91 |[0m body regex "{}" == "a"
|
||||
[1;34m |[0m[1;31m ^^^^ [0m[1;31mregex expression is not valid[0m
|
||||
[1;34m |[0m[1;31m ^^^^ regex expression is not valid[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid URL[0m
|
||||
[1;34m-->[0m tests_failed/runner_errors.hurl:94:5
|
||||
[1;34m |[0m
|
||||
[1;34m 94 |[0m GET {{url}}
|
||||
[1;34m |[0m[1;31m ^^^^^^^ [0m[1;31minvalid URL <localhost:8000/runner_errors> (Missing protocol http or https)[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^ invalid URL <localhost:8000/runner_errors> (Missing protocol http or https)[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mNo query result[0m
|
||||
@ -152,7 +152,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m102 |[0m count: header "count"
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^ [0m[1;31mThe query didn't return any result[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^ The query didn't return any result[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mHeader not found[0m
|
||||
@ -161,7 +161,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m107 |[0m count: 10
|
||||
[1;34m |[0m[1;31m ^^^^^ [0m[1;31mthis header has not been found in the response[0m
|
||||
[1;34m |[0m[1;31m ^^^^^ this header has not been found in the response[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid JSON[0m
|
||||
@ -170,7 +170,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m113 |[0m jsonpath "$.count" == 10
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^^^^^ [0m[1;31mthe HTTP response is not a valid JSON[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^^^^^ the HTTP response is not a valid JSON[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid JSONPath[0m
|
||||
@ -179,7 +179,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m119 |[0m jsonpath "xxx" == 10
|
||||
[1;34m |[0m[1;31m ^^^^^ [0m[1;31mthe JSONPath expression 'xxx' is not valid[0m
|
||||
[1;34m |[0m[1;31m ^^^^^ the JSONPath expression 'xxx' is not valid[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid XML[0m
|
||||
@ -188,7 +188,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors/invalid-xml[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m125 |[0m xpath "//a" == 10
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^ [0m[1;31mthe HTTP response is not a valid XML[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^ the HTTP response is not a valid XML[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid XPath expression[0m
|
||||
@ -197,7 +197,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m131 |[0m xpath "//" == 10
|
||||
[1;34m |[0m[1;31m ^^^^ [0m[1;31mthe XPath expression is not valid[0m
|
||||
[1;34m |[0m[1;31m ^^^^ the XPath expression is not valid[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mInvalid variable type[0m
|
||||
@ -206,7 +206,7 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m137 |[0m verbose: {{verbose}}
|
||||
[1;34m |[0m[1;31m ^^^^^^^ [0m[1;31mexpecting boolean, actual value is <1>[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^ expecting boolean, actual value is <1>[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mUndefined variable[0m
|
||||
@ -215,14 +215,14 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m142 |[0m param: {{value}}
|
||||
[1;34m |[0m[1;31m ^^^^^ [0m[1;31myou must set the variable value[0m
|
||||
[1;34m |[0m[1;31m ^^^^^ you must set the variable value[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mHTTP connection[0m
|
||||
[1;34m-->[0m tests_failed/runner_errors.hurl:145:5
|
||||
[1;34m |[0m
|
||||
[1;34m145 |[0m GET http://localhost:8000/runner_errors/redirect/2
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [0m[1;31mtoo many redirect[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ too many redirect[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mUnauthorized file access[0m
|
||||
@ -230,7 +230,7 @@
|
||||
[1;34m |[0m
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m152 |[0m file,/root/file;
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^ [0m[1;31munauthorized access to file /root/file, check --file-root option[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^ unauthorized access to file /root/file, check --file-root option[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mUnrenderable variable[0m
|
||||
@ -238,7 +238,7 @@
|
||||
[1;34m |[0m
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors[0m
|
||||
[1;34m160 |[0m `{{list}}`
|
||||
[1;34m |[0m[1;31m ^^^^ [0m[1;31mvariable <list> with value [1,2,3] can not be rendered[0m
|
||||
[1;34m |[0m[1;31m ^^^^ variable <list> with value [1,2,3] can not be rendered[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mDecompression error[0m
|
||||
@ -247,13 +247,13 @@
|
||||
[1;34m |[0m [90mGET http://localhost:8000/runner_errors/unsupported-content-encoding[0m
|
||||
[1;34m |[0m[90m ...[0m
|
||||
[1;34m166 |[0m bytes count == 10
|
||||
[1;34m |[0m[1;31m ^^^^^ [0m[1;31mcompression unknown is not supported[0m
|
||||
[1;34m |[0m[1;31m ^^^^^ compression unknown is not supported[0m
|
||||
[1;34m |[0m
|
||||
|
||||
[1;31merror[0m: [1mUnsupported HTTP version[0m
|
||||
[1;34m-->[0m tests_failed/runner_errors.hurl:169:5
|
||||
[1;34m |[0m
|
||||
[1;34m169 |[0m GET http://localhost:8000/runner_errors
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [0m[1;31mHTTP/3 is not supported, check --version[0m
|
||||
[1;34m |[0m[1;31m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ HTTP/3 is not supported, check --version[0m
|
||||
[1;34m |[0m
|
||||
|
||||
|
@ -30,7 +30,7 @@ impl Error {
|
||||
|
||||
impl From<runner::Error> for Error {
|
||||
fn from(error: runner::Error) -> Self {
|
||||
Error::new(&error.fixme())
|
||||
Error::new(&error.fixme(&[]))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,10 +159,11 @@ impl hurl_core::error::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn fixme(&self) -> String {
|
||||
fn fixme(&self, content: &[&str]) -> String {
|
||||
match &self.inner {
|
||||
RunnerError::AssertBodyValueError { actual, .. } => {
|
||||
format!("actual value is <{actual}>")
|
||||
let message = &format!("actual value is <{actual}>");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::AssertFailure {
|
||||
actual,
|
||||
@ -178,75 +179,130 @@ impl hurl_core::error::Error for Error {
|
||||
format!(" actual: {actual}\n expected: {expected}{additional}")
|
||||
}
|
||||
RunnerError::AssertHeaderValueError { actual } => {
|
||||
format!("actual value is <{actual}>")
|
||||
let message = &format!("actual value is <{actual}>");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::AssertStatus { actual, .. } => {
|
||||
let message = &format!("actual value is <{actual}>");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::AssertVersion { actual, .. } => {
|
||||
let message = &format!("actual value is <{actual}>");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::AssertStatus { actual, .. } => format!("actual value is <{actual}>"),
|
||||
RunnerError::AssertVersion { actual, .. } => format!("actual value is <{actual}>"),
|
||||
RunnerError::CouldNotUncompressResponse(algorithm) => {
|
||||
format!("could not uncompress response with {algorithm}")
|
||||
let message = &format!("could not uncompress response with {algorithm}");
|
||||
|
||||
// only add carets if source_info is set
|
||||
// TODO: add additional attribute in the error to be more explicit?
|
||||
if self.source_info.start.line == 0 {
|
||||
message.to_string()
|
||||
} else {
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
}
|
||||
RunnerError::FileReadAccess { path } => {
|
||||
format!("file {} can not be read", path.to_string_lossy())
|
||||
let message = &format!("file {} can not be read", path.to_string_lossy());
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::FileWriteAccess { path, error } => {
|
||||
format!("{} can not be written ({error})", path.to_string_lossy())
|
||||
}
|
||||
RunnerError::FilterDecode(encoding) => {
|
||||
format!("value can not be decoded with <{encoding}> encoding")
|
||||
let message = &format!("value can not be decoded with <{encoding}> encoding");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::FilterInvalidEncoding(encoding) => {
|
||||
format!("<{encoding}> encoding is not supported")
|
||||
let message = &format!("<{encoding}> encoding is not supported");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::FilterInvalidInput(message) => {
|
||||
format!("invalid filter input: {message}")
|
||||
let message = &format!("invalid filter input: {message}");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::FilterMissingInput => {
|
||||
let message = "missing value to apply filter";
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::HttpConnection(message) => {
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::FilterMissingInput => "missing value to apply filter".to_string(),
|
||||
RunnerError::HttpConnection(message) => message.to_string(),
|
||||
RunnerError::InvalidCharset { charset } => {
|
||||
format!("the charset '{charset}' is not valid")
|
||||
let message = &format!("the charset '{charset}' is not valid");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::InvalidDecoding { charset } => {
|
||||
format!("the body can not be decoded with charset '{charset}'")
|
||||
let message = &format!("the body can not be decoded with charset '{charset}'");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::InvalidJson { value } => {
|
||||
format!("actual value is <{value}>")
|
||||
let message = &format!("actual value is <{value}>");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::InvalidRegex => {
|
||||
let message = "regex expression is not valid";
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::InvalidUrl(url, reason) => {
|
||||
let message = &format!("invalid URL <{url}> ({reason})");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::NoQueryResult => {
|
||||
let message = "The query didn't return any result";
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::InvalidRegex => "regex expression is not valid".to_string(),
|
||||
RunnerError::InvalidUrl(url, reason) => format!("invalid URL <{url}> ({reason})"),
|
||||
|
||||
RunnerError::NoQueryResult => "The query didn't return any result".to_string(),
|
||||
RunnerError::QueryHeaderNotFound => {
|
||||
"this header has not been found in the response".to_string()
|
||||
let message = "this header has not been found in the response";
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::QueryInvalidJson => {
|
||||
let message = "the HTTP response is not a valid JSON";
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::QueryInvalidJson => "the HTTP response is not a valid JSON".to_string(),
|
||||
RunnerError::QueryInvalidJsonpathExpression { value } => {
|
||||
format!("the JSONPath expression '{value}' is not valid")
|
||||
let message = &format!("the JSONPath expression '{value}' is not valid");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::QueryInvalidXml => {
|
||||
let message = "the HTTP response is not a valid XML";
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::QueryInvalidXpathEval => {
|
||||
let message = "the XPath expression is not valid";
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::QueryInvalidXml => "the HTTP response is not a valid XML".to_string(),
|
||||
RunnerError::QueryInvalidXpathEval => "the XPath expression is not valid".to_string(),
|
||||
RunnerError::TemplateVariableInvalidType {
|
||||
value, expecting, ..
|
||||
} => {
|
||||
format!("expecting {expecting}, actual value is <{value}>")
|
||||
let message = &format!("expecting {expecting}, actual value is <{value}>");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::TemplateVariableNotDefined { name } => {
|
||||
format!("you must set the variable {name}")
|
||||
let message = &format!("you must set the variable {name}");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::TooManyRedirect => {
|
||||
let message = "too many redirect";
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::TooManyRedirect => "too many redirect".to_string(),
|
||||
RunnerError::UnauthorizedFileAccess { path } => {
|
||||
format!(
|
||||
let message = &format!(
|
||||
"unauthorized access to file {}, check --file-root option",
|
||||
path.to_string_lossy()
|
||||
)
|
||||
);
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::UnrenderableVariable { name, value } => {
|
||||
format!("variable <{name}> with value {value} can not be rendered")
|
||||
let message = &format!("variable <{name}> with value {value} can not be rendered");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::UnsupportedContentEncoding(algorithm) => {
|
||||
format!("compression {algorithm} is not supported")
|
||||
let message = &format!("compression {algorithm} is not supported");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
RunnerError::UnsupportedHttpVersion(version) => {
|
||||
format!("{version} is not supported, check --version")
|
||||
let message = &format!("{version} is not supported, check --version");
|
||||
hurl_core::error::add_carets(message, self.source_info, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -254,10 +310,6 @@ impl hurl_core::error::Error for Error {
|
||||
fn show_source_line(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn show_caret(&self) -> bool {
|
||||
!matches!(&self.inner, RunnerError::AssertFailure { .. })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HttpError> for RunnerError {
|
||||
|
@ -285,7 +285,7 @@ pub fn run_entries(
|
||||
stdout,
|
||||
source_info,
|
||||
) {
|
||||
logger.warning(&error.fixme());
|
||||
logger.warning(&error.fixme(&[]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -567,57 +567,14 @@ fn get_message<E: Error>(error: &E, lines: &[&str], colored: bool) -> String {
|
||||
text.push_str(&line);
|
||||
text.push('\n');
|
||||
}
|
||||
|
||||
let mut prefix = if error.show_caret() {
|
||||
//let mut prefix = String::new();
|
||||
// the fixme message is offset with space and carets according to the error column
|
||||
let error_line = error.source_info().start.line;
|
||||
let error_column = error.source_info().start.column;
|
||||
|
||||
// Error source info start and end can be on different lines, we insure a minimum width.
|
||||
let width = if error.source_info().end.column > error_column {
|
||||
error.source_info().end.column - error_column
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
// We take tabs into account because we have normalize the display of the error line by replacing
|
||||
// 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;
|
||||
};
|
||||
if c == '\t' {
|
||||
tab_shift += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut value = " ".repeat(error_column + tab_shift * 3);
|
||||
value.push_str("^".repeat(width).as_str());
|
||||
value.push(' ');
|
||||
value
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let fixme = error.fixme();
|
||||
let fixme = error.fixme(lines);
|
||||
let lines = split_lines(&fixme);
|
||||
for (i, line) in lines.iter().enumerate() {
|
||||
if i > 0 {
|
||||
if !prefix.is_empty() {
|
||||
prefix = " ".repeat(prefix.len());
|
||||
}
|
||||
text.push('\n');
|
||||
}
|
||||
if !line.is_empty() {
|
||||
text.push_str(color_if_needed(&prefix, colored).as_str());
|
||||
}
|
||||
text.push_str(color_if_needed(line, colored).as_str());
|
||||
}
|
||||
|
||||
text
|
||||
}
|
||||
|
||||
@ -688,7 +645,7 @@ HTTP/1.0 200
|
||||
colored::control::set_override(true);
|
||||
assert_eq!(
|
||||
get_message(&error, &split_lines(content), true),
|
||||
" HTTP/1.0 200\n\u{1b}[1;31m ^^^ \u{1b}[0m\u{1b}[1;31mactual value is <404>\u{1b}[0m"
|
||||
" HTTP/1.0 200\n\u{1b}[1;31m ^^^ actual value is <404>\u{1b}[0m"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@ -853,7 +810,7 @@ HTTP 200
|
||||
"Assert body value".to_string()
|
||||
}
|
||||
|
||||
fn fixme(&self) -> String {
|
||||
fn fixme(&self, _lines: &[&str]) -> String {
|
||||
r#" {
|
||||
"name": "John",
|
||||
- "age": 27
|
||||
@ -866,10 +823,6 @@ HTTP 200
|
||||
fn show_source_line(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn show_caret(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
let error = E;
|
||||
|
||||
|
@ -20,7 +20,104 @@ use crate::ast::SourceInfo;
|
||||
pub trait Error {
|
||||
fn source_info(&self) -> SourceInfo;
|
||||
fn description(&self) -> String;
|
||||
fn fixme(&self) -> String;
|
||||
fn fixme(&self, content: &[&str]) -> String;
|
||||
fn show_source_line(&self) -> bool;
|
||||
fn show_caret(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Show column position with carets
|
||||
pub fn add_carets(message: &str, source_info: SourceInfo, content: &[&str]) -> String {
|
||||
let error_line = source_info.start.line;
|
||||
let error_column = source_info.start.column;
|
||||
// Error source info start and end can be on different lines, we insure a minimum width.
|
||||
let width = if source_info.end.column > error_column {
|
||||
source_info.end.column - error_column
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let line_raw = content.get(error_line - 1).unwrap();
|
||||
let prefix = get_carets(line_raw, error_column, width);
|
||||
|
||||
let mut s = String::new();
|
||||
for (i, line) in split_lines(message).iter().enumerate() {
|
||||
if i == 0 {
|
||||
s.push_str(format!("{prefix}{line}").as_str());
|
||||
} else {
|
||||
s.push('\n');
|
||||
if !line.is_empty() {
|
||||
s.push_str(" ".repeat(prefix.len()).as_str());
|
||||
}
|
||||
s.push_str(line);
|
||||
};
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Splits this `text` to a list of LF/CRLF separated lines.
|
||||
fn split_lines(text: &str) -> Vec<&str> {
|
||||
regex::Regex::new(r"\n|\r\n").unwrap().split(text).collect()
|
||||
}
|
||||
|
||||
/// Generate carets for the given source_line/source_info
|
||||
fn get_carets(line_raw: &str, error_column: usize, width: usize) -> String {
|
||||
// We take tabs into account because we have normalize the display of the error line by replacing
|
||||
// tabs with 4 spaces.
|
||||
let mut tab_shift = 0;
|
||||
for (i, c) in line_raw.chars().enumerate() {
|
||||
if i >= (error_column - 1) {
|
||||
break;
|
||||
};
|
||||
if c == '\t' {
|
||||
tab_shift += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut prefix = " ".repeat(error_column + tab_shift * 3);
|
||||
prefix.push_str("^".repeat(width).as_str());
|
||||
prefix.push(' ');
|
||||
prefix
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::Pos;
|
||||
|
||||
#[test]
|
||||
fn test_add_carets() {
|
||||
// `Hello World`
|
||||
// ^^^^^^^^^^^^^ actual value is <Hello World!>
|
||||
assert_eq!(
|
||||
add_carets(
|
||||
"actual value is <Hello World!>",
|
||||
SourceInfo::new(Pos::new(1, 1), Pos::new(1, 14)),
|
||||
&["`Hello World`"]
|
||||
),
|
||||
" ^^^^^^^^^^^^^ actual value is <Hello World!>".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_carets() {
|
||||
// `Hello World`
|
||||
// ^^^^^^^^^^^^^ actual value is <Hello World!>
|
||||
assert_eq!(
|
||||
get_carets("`Hello World`", 1, 13),
|
||||
" ^^^^^^^^^^^^^ ".to_string()
|
||||
);
|
||||
|
||||
// Content-Length: 200
|
||||
// ^^^ actual value is <12>
|
||||
assert_eq!(
|
||||
get_carets("Content-Length: 200", 17, 3),
|
||||
" ^^^ ".to_string()
|
||||
);
|
||||
|
||||
// With a tab instead of a space
|
||||
// Content-Length: 200
|
||||
// ^^^ actual value is <12>
|
||||
assert_eq!(
|
||||
get_carets("Content-Length:\t200", 17, 3),
|
||||
" ^^^ ".to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -131,8 +131,8 @@ impl crate::error::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn fixme(&self) -> String {
|
||||
match &self.inner {
|
||||
fn fixme(&self, content: &[&str]) -> String {
|
||||
let message = match &self.inner {
|
||||
ParseError::DuplicateSection => "the section is already defined".to_string(),
|
||||
ParseError::EscapeChar => "the escaping sequence is not valid".to_string(),
|
||||
ParseError::Expecting { value } => format!("expecting '{value}'"),
|
||||
@ -233,16 +233,14 @@ impl crate::error::Error for Error {
|
||||
}
|
||||
ParseError::XPathExpr => "expecting a XPath expression".to_string(),
|
||||
ParseError::Xml => "invalid XML".to_string(),
|
||||
}
|
||||
};
|
||||
|
||||
crate::error::add_carets(&message, self.source_info(), content)
|
||||
}
|
||||
|
||||
fn show_source_line(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn show_caret(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn did_you_mean(valid_values: &[&str], actual: &str, default: &str) -> String {
|
||||
|
@ -17,12 +17,11 @@
|
||||
*/
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::linter;
|
||||
use colored::*;
|
||||
use hurl_core::error::Error;
|
||||
use hurl_core::parser;
|
||||
|
||||
use crate::linter;
|
||||
|
||||
pub fn make_logger_verbose(verbose: bool) -> impl Fn(&str) {
|
||||
move |message| log_verbose(verbose, message)
|
||||
}
|
||||
@ -130,8 +129,9 @@ fn log_error(
|
||||
|
||||
// TODO: to clean/Refacto
|
||||
// specific case for assert errors
|
||||
let lines = lines.iter().map(|s| s.as_str()).collect::<Vec<&str>>();
|
||||
if error.source_info().start.column == 0 {
|
||||
let fix_me = &error.fixme();
|
||||
let fix_me = &error.fixme(&lines);
|
||||
let fixme_lines: Vec<&str> = regex::Regex::new(r"\n|\r\n")
|
||||
.unwrap()
|
||||
.split(fix_me)
|
||||
@ -162,7 +162,7 @@ fn log_error(
|
||||
" ".repeat(line_number_size).as_str(),
|
||||
" ".repeat(error.source_info().start.column - 1 + tab_shift * 3),
|
||||
"^".repeat(if width > 1 { width } else { 1 }),
|
||||
fixme = error.fixme().as_str(),
|
||||
fixme = error.fixme(&lines).as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ impl Error for linter::Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn fixme(&self) -> String {
|
||||
fn fixme(&self, _lines: &[&str]) -> String {
|
||||
match self.inner {
|
||||
LinterError::UnnecessarySpace => "Remove space".to_string(),
|
||||
LinterError::UnnecessaryJsonEncoding => "Use Simple String".to_string(),
|
||||
@ -48,8 +48,4 @@ impl Error for linter::Error {
|
||||
fn show_source_line(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn show_caret(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user