diff options
author | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2015-10-24 04:12:43 -0200 |
---|---|---|
committer | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2015-10-24 04:12:43 -0200 |
commit | 3a5ea19f35e4228cd782d69f21f52656c1e9a1b8 (patch) | |
tree | d587ea7522d51d0d15c63c891a2b4f58e88060a0 | |
parent | b3eb6d3f1cae3449c8f988fe0985c58d1e22a7f8 (diff) | |
download | blogc-3a5ea19f35e4228cd782d69f21f52656c1e9a1b8.tar.gz blogc-3a5ea19f35e4228cd782d69f21f52656c1e9a1b8.tar.bz2 blogc-3a5ea19f35e4228cd782d69f21f52656c1e9a1b8.zip |
error: improved error reporting for parsers
it will now report the line and the approximate position of the error.
-rw-r--r-- | src/error.c | 50 | ||||
-rw-r--r-- | tests/check_error.c | 40 | ||||
-rw-r--r-- | tests/check_source_parser.c | 18 | ||||
-rw-r--r-- | tests/check_template_parser.c | 47 |
4 files changed, 117 insertions, 38 deletions
diff --git a/src/error.c b/src/error.c index ad4e3f4..d3d045d 100644 --- a/src/error.c +++ b/src/error.c @@ -50,26 +50,54 @@ blogc_error_parser(blogc_error_type_t type, const char *src, size_t src_len, char *msg = b_strdup_vprintf(format, ap); va_end(ap); - b_string_t *str = b_string_new(); - while (current < src_len) { - char c = src[current]; - - if (c == '\r' || c == '\n') + size_t lineno = 1; + size_t linestart = 0; + size_t lineend = 0; + size_t pos = 1; + + for (size_t i = 0; i < src_len; i++) { + char c = src[i]; + if (i < current) { + if ((i + 1) < src_len) { + if ((c == '\n' && src[i + 1] == '\r') || + (c == '\r' && src[i + 1] == '\n')) + { + lineno++; + pos = 1; + c = src[++i]; + if ((i + 1) < src_len) + linestart = i + 1; + continue; + } + } + if (c == '\n' || c == '\r') { + lineno++; + pos = 1; + if ((i + 1) < src_len) + linestart = i + 1; + continue; + } + pos++; + } + else if (c == '\n' || c == '\r') { + lineend = i; break; + } + } - b_string_append_c(str, c); + if (lineend <= linestart && src_len >= linestart) + lineend = src_len; - current++; - } - char *line = b_string_free(str, false); + char *line = b_strndup(src + linestart, lineend - linestart); blogc_error_t *rv = NULL; - if (strlen(line) == 0) // "near to" message isn't useful if line is empty + if (line[0] == '\0') // "near" message isn't useful if line is empty rv = blogc_error_new(type, msg); else rv = blogc_error_new_printf(type, - "%s\nError occurred near to '%s'", msg, line); + "%s\nError occurred near line %d, position %d: %s", msg, lineno, + pos, line); free(msg); free(line); diff --git a/tests/check_error.c b/tests/check_error.c index 68f287a..17e1c40 100644 --- a/tests/check_error.c +++ b/tests/check_error.c @@ -48,7 +48,28 @@ test_error_parser(void **state) blogc_error_t *error = blogc_error_parser(1, a, strlen(a), 11, "asd %d", 10); assert_non_null(error); assert_int_equal(error->type, 1); - assert_string_equal(error->msg, "asd 10\nError occurred near to 'hunda'"); + assert_string_equal(error->msg, + "asd 10\nError occurred near line 3, position 2: chunda"); + blogc_error_free(error); + a = "bola\nguda\nchunda"; + error = blogc_error_parser(1, a, strlen(a), 11, "asd %d", 10); + assert_non_null(error); + assert_int_equal(error->type, 1); + assert_string_equal(error->msg, + "asd 10\nError occurred near line 3, position 2: chunda"); + blogc_error_free(error); + a = "bola\nguda\nchunda"; + error = blogc_error_parser(1, a, strlen(a), 0, "asd %d", 10); + assert_non_null(error); + assert_int_equal(error->type, 1); + assert_string_equal(error->msg, + "asd 10\nError occurred near line 1, position 1: bola"); + blogc_error_free(error); + a = ""; + error = blogc_error_parser(1, a, strlen(a), 0, "asd %d", 10); + assert_non_null(error); + assert_int_equal(error->type, 1); + assert_string_equal(error->msg, "asd 10"); blogc_error_free(error); } @@ -60,7 +81,22 @@ test_error_parser_crlf(void **state) blogc_error_t *error = blogc_error_parser(1, a, strlen(a), 13, "asd %d", 10); assert_non_null(error); assert_int_equal(error->type, 1); - assert_string_equal(error->msg, "asd 10\nError occurred near to 'hunda'"); + assert_string_equal(error->msg, + "asd 10\nError occurred near line 3, position 2: chunda"); + blogc_error_free(error); + a = "bola\r\nguda\r\nchunda"; + error = blogc_error_parser(1, a, strlen(a), 13, "asd %d", 10); + assert_non_null(error); + assert_int_equal(error->type, 1); + assert_string_equal(error->msg, + "asd 10\nError occurred near line 3, position 2: chunda"); + blogc_error_free(error); + a = "bola\r\nguda\r\nchunda"; + error = blogc_error_parser(1, a, strlen(a), 0, "asd %d", 10); + assert_non_null(error); + assert_int_equal(error->type, 1); + assert_string_equal(error->msg, + "asd 10\nError occurred near line 1, position 1: bola"); blogc_error_free(error); } diff --git a/tests/check_source_parser.c b/tests/check_source_parser.c index 810786b..4d8518e 100644 --- a/tests/check_source_parser.c +++ b/tests/check_source_parser.c @@ -183,7 +183,7 @@ test_source_parse_config_invalid_key(void **state) assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER); assert_string_equal(err->msg, "Can't find a configuration key or the content separator.\n" - "Error occurred near to 'bola: guda'"); + "Error occurred near line 1, position 1: bola: guda"); blogc_error_free(err); b_trie_free(source); } @@ -199,7 +199,7 @@ test_source_parse_config_no_key(void **state) assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER); assert_string_equal(err->msg, "Invalid configuration key.\n" - "Error occurred near to 'a'"); + "Error occurred near line 1, position 4: BOLa"); blogc_error_free(err); b_trie_free(source); } @@ -214,7 +214,8 @@ test_source_parse_config_no_key2(void **state) assert_non_null(err); assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER); assert_string_equal(err->msg, - "Your last configuration key is missing ':' and the value"); + "Your last configuration key is missing ':' and the value\n" + "Error occurred near line 1, position 5: BOLA"); blogc_error_free(err); b_trie_free(source); } @@ -230,7 +231,8 @@ test_source_parse_config_no_value(void **state) assert_non_null(err); assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER); assert_string_equal(err->msg, - "Configuration value not provided for 'BOLA'."); + "Configuration value not provided for 'BOLA'.\n" + "Error occurred near line 1, position 6: BOLA:"); blogc_error_free(err); b_trie_free(source); } @@ -246,7 +248,8 @@ test_source_parse_config_no_value2(void **state) assert_non_null(err); assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER); assert_string_equal(err->msg, - "Configuration value not provided for 'BOLA'."); + "Configuration value not provided for 'BOLA'.\n" + "Error occurred near line 1, position 6: BOLA:"); blogc_error_free(err); b_trie_free(source); } @@ -449,7 +452,8 @@ test_source_parse_config_value_no_line_ending(void **state) assert_non_null(err); assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER); assert_string_equal(err->msg, - "No line ending after the configuration value for 'BOLA'."); + "No line ending after the configuration value for 'BOLA'.\n" + "Error occurred near line 1, position 10: BOLA: asd"); blogc_error_free(err); b_trie_free(source); } @@ -466,7 +470,7 @@ test_source_parse_invalid_separator(void **state) assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER); assert_string_equal(err->msg, "Invalid content separator. Must be more than one '-' characters.\n" - "Error occurred near to '#'"); + "Error occurred near line 2, position 4: ---#"); blogc_error_free(err); b_trie_free(source); } diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c index df5dc4c..94f669b 100644 --- a/tests/check_template_parser.c +++ b/tests/check_template_parser.c @@ -359,7 +359,7 @@ test_template_parse_invalid_block_start(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid statement syntax. Must begin with lowercase letter.\n" - "Error occurred near to 'ASD %}'"); + "Error occurred near line 1, position 4: {% ASD %}"); blogc_error_free(err); } @@ -377,7 +377,7 @@ test_template_parse_invalid_block_nested(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Blocks can't be nested.\n" - "Error occurred near to ' listing %}'"); + "Error occurred near line 2, position 9: {% block listing %}"); blogc_error_free(err); } @@ -393,7 +393,7 @@ test_template_parse_invalid_block_not_open(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "'endblock' statement without an open 'block' statement.\n" - "Error occurred near to ' %}'"); + "Error occurred near line 1, position 12: {% endblock %}"); blogc_error_free(err); } @@ -409,7 +409,8 @@ test_template_parse_invalid_endif_not_open(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "'endif' statement without an open 'ifdef' or 'ifndef' statement.\n" - "Error occurred near to ' %}{% endblock %}'"); + "Error occurred near line 1, position 28: " + "{% block listing %}{% endif %}{% endblock %}"); blogc_error_free(err); } @@ -425,7 +426,8 @@ test_template_parse_invalid_block_name(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid statement type: Allowed types are: 'block', 'endblock', 'ifdef', " - "'ifndef' and 'endif'.\nError occurred near to ' %}'"); + "'ifndef' and 'endif'.\n" + "Error occurred near line 1, position 10: {% chunda %}"); blogc_error_free(err); } @@ -441,7 +443,7 @@ test_template_parse_invalid_block_type_start(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid block syntax. Must begin with lowercase letter.\n" - "Error occurred near to 'ENTRY %}'"); + "Error occurred near line 1, position 10: {% block ENTRY %}"); blogc_error_free(err); } @@ -457,7 +459,7 @@ test_template_parse_invalid_block_type(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid block type. Allowed types are: 'entry', 'listing' and 'listing_once'.\n" - "Error occurred near to ' %}'"); + "Error occurred near line 1, position 16: {% block chunda %}"); blogc_error_free(err); } @@ -473,7 +475,8 @@ test_template_parse_invalid_ifdef_start(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid variable name. Must begin with uppercase letter.\n" - "Error occurred near to 'guda %}'"); + "Error occurred near line 1, position 27: " + "{% block entry %}{% ifdef guda %}"); blogc_error_free(err); } @@ -489,7 +492,8 @@ test_template_parse_invalid_ifdef_variable(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid variable name. Must be uppercase letter, number or '_'.\n" - "Error occurred near to 'oLA %}'"); + "Error occurred near line 1, position 28: " + "{% block entry %}{% ifdef BoLA %}"); blogc_error_free(err); } @@ -505,7 +509,8 @@ test_template_parse_invalid_if_operator(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid 'if' operator. Must be '<', '>', '<=', '>=', '==' or '!='.\n" - "Error occurred near to '= \"asd\" %}'"); + "Error occurred near line 1, position 29: " + "{% block entry %}{% if BOLA = \"asd\" %}"); blogc_error_free(err); } @@ -521,7 +526,8 @@ test_template_parse_invalid_if_operand(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid 'if' operand. Must be double-quoted static string.\n" - "Error occurred near to 'asd %}'"); + "Error occurred near line 1, position 32: " + "{% block entry %}{% if BOLA == asd %}"); blogc_error_free(err); } @@ -537,7 +543,8 @@ test_template_parse_invalid_if_operand2(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Found an open double-quoted string.\n" - "Error occurred near to '\"asd %}'"); + "Error occurred near line 1, position 32: " + "{% block entry %}{% if BOLA == \"asd %}"); blogc_error_free(err); } @@ -553,7 +560,7 @@ test_template_parse_invalid_block_end(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid statement syntax. Must end with '%}'.\n" - "Error occurred near to '}}'"); + "Error occurred near line 1, position 16: {% block entry }}"); blogc_error_free(err); } @@ -569,7 +576,8 @@ test_template_parse_invalid_variable_name(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid variable name. Must begin with uppercase letter.\n" - "Error occurred near to 'bola }}{% endblock %}'"); + "Error occurred near line 1, position 21: " + "{% block entry %}{{ bola }}{% endblock %}"); blogc_error_free(err); } @@ -585,7 +593,8 @@ test_template_parse_invalid_variable_name2(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid variable name. Must be uppercase letter, number or '_'.\n" - "Error occurred near to 'ola }}{% endblock %}'"); + "Error occurred near line 1, position 22: " + "{% block entry %}{{ Bola }}{% endblock %}"); blogc_error_free(err); } @@ -601,7 +610,8 @@ test_template_parse_invalid_variable_end(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid statement syntax. Must end with '}}'.\n" - "Error occurred near to '%}{% endblock %}'"); + "Error occurred near line 1, position 26: " + "{% block entry %}{{ BOLA %}{% endblock %}"); blogc_error_free(err); } @@ -617,7 +627,7 @@ test_template_parse_invalid_close(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid statement syntax. Must end with '}'.\n" - "Error occurred near to '%'"); + "Error occurred near line 1, position 17: {% block entry %%"); blogc_error_free(err); } @@ -633,7 +643,8 @@ test_template_parse_invalid_close2(void **state) assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER); assert_string_equal(err->msg, "Invalid statement syntax. Must end with '}'.\n" - "Error occurred near to '%{% endblock %}'"); + "Error occurred near line 1, position 27: " + "{% block entry %}{{ BOLA }%{% endblock %}"); blogc_error_free(err); } |