test/harness/warningsparser.c
author ali <ali@juiblex.co.uk>
Wed Oct 16 22:51:29 2013 +0100 (2013-10-16)
changeset 104 70cc629ec1e0
parent 17 2c88fd553e5d
permissions -rw-r--r--
Fix bug #28: Don't report ., as double punctuation after "etc" or "&c"
     1 #include <stdlib.h>
     2 #include <string.h>
     3 #include <glib.h>
     4 #include "testcase.h"
     5 #include "warningsparser.h"
     6 
     7 /*
     8  * A GMarkupParser for the contents of a WARNINGS tag.
     9  */
    10 
    11 typedef struct {
    12     Testcase *testcase;
    13     TestcaseWarning *warning;
    14     TestcaseLocation *location;
    15     enum {
    16 	WARNINGS_INIT,
    17 	WARNINGS_IN_EXPECTED,
    18 	WARNINGS_IN_SUMMARY,
    19 	WARNINGS_IN_WARNING,
    20 	WARNINGS_IN_AT,
    21 	WARNINGS_IN_TEXT,
    22 	WARNINGS_DONE,
    23     } state,parent_state;
    24 } WarningsBaton;
    25 
    26 static void warnings_parser_start_element(GMarkupParseContext *context,
    27   const char *element_name,const char **attribute_names,
    28   const char **attribute_values,void *user_data,GError **error)
    29 {
    30     int i;
    31     guint64 tmp;
    32     char *endp;
    33     WarningsBaton *baton=user_data;
    34     baton->parent_state=baton->state;
    35     switch(baton->state)
    36     {
    37 	case WARNINGS_INIT:
    38 	    if (strcmp(element_name,"expected"))
    39 		g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_UNKNOWN_ELEMENT,
    40 		  "Unknown root element: '%s'",element_name);
    41 	    else if (attribute_names[0])
    42 		g_set_error(error,G_MARKUP_ERROR,
    43 		  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
    44 		  "Unknown attribute on element 'expected': '%s'",
    45 		  attribute_names[0]);
    46 	    else
    47 		baton->state=WARNINGS_IN_EXPECTED;
    48 	    break;
    49 	case WARNINGS_IN_EXPECTED:
    50 	    if (!strcmp(element_name,"summary"))
    51 	    {
    52 		if (baton->testcase->summary.texts)
    53 		{
    54 		    g_set_error(error,G_MARKUP_ERROR,
    55 		      G_MARKUP_ERROR_INVALID_CONTENT,"Multiple summary "
    56 		      "elements are not valid");
    57 		}
    58 		else
    59 		    baton->state=WARNINGS_IN_SUMMARY;
    60 	    }
    61 	    else
    62 	    {
    63 		baton->warning=g_new0(TestcaseWarning,1);
    64 		if (!strcmp(element_name,"error"))
    65 		    baton->warning->is_real=TRUE;
    66 		else if (!strcmp(element_name,"false-positive"))
    67 		    baton->warning->xfail=TRUE;
    68 		else if (!strcmp(element_name,"false-negative"))
    69 		    baton->warning->is_real=baton->warning->xfail=TRUE;
    70 		else
    71 		{
    72 		    g_set_error(error,G_MARKUP_ERROR,
    73 		      G_MARKUP_ERROR_UNKNOWN_ELEMENT,
    74 		      "Unknown element in 'expected': '%s'",element_name);
    75 		    g_free(baton->warning);
    76 		    baton->warning=NULL;
    77 		    return;
    78 		}
    79 		baton->state=WARNINGS_IN_WARNING;
    80 	    }
    81 	    if (attribute_names[0])
    82 	    {
    83 		g_set_error(error,G_MARKUP_ERROR,
    84 		  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
    85 		  "Unknown attribute on element '%s': '%s'",element_name,
    86 		  attribute_names[0]);
    87 		if (baton->state==WARNINGS_IN_WARNING)
    88 		{
    89 		    g_free(baton->warning);
    90 		    baton->warning=NULL;
    91 		}
    92 		baton->state=WARNINGS_IN_EXPECTED;
    93 		return;
    94 	    }
    95 	    break;
    96 	case WARNINGS_IN_SUMMARY:
    97 	    if (!strcmp(element_name,"text"))
    98 	    {
    99 		if (attribute_names[0])
   100 		{
   101 		    g_set_error(error,G_MARKUP_ERROR,
   102 		      G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
   103 		      "Unknown attribute on element 'text': '%s'",
   104 		      attribute_names[0]);
   105 		    return;
   106 		}
   107 		baton->state=WARNINGS_IN_TEXT;
   108 	    }
   109 	    break;
   110 	case WARNINGS_IN_WARNING:
   111 	    if (!strcmp(element_name,"at"))
   112 	    {
   113 		baton->location=g_new0(TestcaseLocation,1);
   114 		for(i=0;attribute_names[i];i++)
   115 		{
   116 		    if (!strcmp(attribute_names[i],"line"))
   117 		    {
   118 			tmp=g_ascii_strtoull(attribute_values[i],&endp,0);
   119 			if (tmp<1 || tmp>G_MAXUINT || tmp==G_MAXUINT64)
   120 			{
   121 			    g_set_error(error,G_MARKUP_ERROR,
   122 			      G_MARKUP_ERROR_INVALID_CONTENT,"Invalid value "
   123 			      "for attribute 'line' on element '%s': '%s'",
   124 			      element_name,attribute_values[i]);
   125 			    return;
   126 			}
   127 			baton->location->line=(guint)tmp;
   128 		    }
   129 		    else if (!strcmp(attribute_names[i],"column"))
   130 		    {
   131 			tmp=g_ascii_strtoull(attribute_values[i],&endp,0);
   132 			if (tmp<1 || tmp>G_MAXUINT || tmp==G_MAXUINT64)
   133 			{
   134 			    g_set_error(error,G_MARKUP_ERROR,
   135 			      G_MARKUP_ERROR_INVALID_CONTENT,"Invalid value "
   136 			      "for attribute 'column' on element '%s': '%s'",
   137 			      element_name,attribute_values[i]);
   138 			    return;
   139 			}
   140 			baton->location->column=(guint)tmp;
   141 		    }
   142 		    else
   143 		    {
   144 			g_set_error(error,G_MARKUP_ERROR,
   145 			  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
   146 			  "Unknown attribute on element '%s': '%s'",
   147 			  element_name,attribute_names[i]);
   148 			return;
   149 		    }
   150 		}
   151 		if (!baton->location->line)
   152 		{
   153 		    g_set_error(error,G_MARKUP_ERROR,
   154 		      G_MARKUP_ERROR_MISSING_ATTRIBUTE,
   155 		      "Missing attribute on element '%s': 'line'",element_name);
   156 		    return;
   157 		}
   158 		baton->state=WARNINGS_IN_AT;
   159 	    }
   160 	    else if (!strcmp(element_name,"text"))
   161 	    {
   162 		if (attribute_names[0])
   163 		{
   164 		    g_set_error(error,G_MARKUP_ERROR,
   165 		      G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
   166 		      "Unknown attribute on element 'text': '%s'",
   167 		      attribute_names[0]);
   168 		    return;
   169 		}
   170 		baton->state=WARNINGS_IN_TEXT;
   171 	    }
   172 	    break;
   173 	case WARNINGS_IN_AT:
   174 	    g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_UNKNOWN_ELEMENT,
   175 	      "Unknown element in 'at': '%s'",element_name);
   176 	    return;
   177 	case WARNINGS_IN_TEXT:
   178 	    g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_UNKNOWN_ELEMENT,
   179 	      "Unknown element in 'text': '%s'",element_name);
   180 	    return;
   181 	default:
   182 	    g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_UNKNOWN_ELEMENT,
   183 	      "Unexpected element: '%s'",element_name);
   184 	    return;
   185     }
   186 }
   187 
   188 static void warnings_parser_end_element(GMarkupParseContext *context,
   189   const char *element_name,void *user_data,GError **error)
   190 {
   191     WarningsBaton *baton=user_data;
   192     switch(baton->state)
   193     {
   194 	case WARNINGS_IN_EXPECTED:
   195 	    baton->testcase->warnings=
   196 	      g_slist_reverse(baton->testcase->warnings);
   197 	    baton->state=WARNINGS_DONE;
   198 	    break;
   199 	case WARNINGS_IN_SUMMARY:
   200 	    if (!baton->testcase->summary.texts)
   201 		g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT,
   202 		  "Summary element must contain at least one text element");
   203 	    else
   204 		baton->testcase->summary.texts=
   205 		  g_slist_reverse(baton->testcase->summary.texts);
   206 	    baton->state=WARNINGS_IN_EXPECTED;
   207 	    break;
   208 	case WARNINGS_IN_WARNING:
   209 	    baton->warning->locations=
   210 	      g_slist_reverse(baton->warning->locations);
   211 	    baton->testcase->warnings=g_slist_prepend(baton->testcase->warnings,
   212 	      baton->warning);
   213 	    baton->warning=NULL;
   214 	    baton->state=WARNINGS_IN_EXPECTED;
   215 	    break;
   216 	case WARNINGS_IN_AT:
   217 	    baton->warning->locations=g_slist_prepend(baton->warning->locations,
   218 	      baton->location);
   219 	    baton->location=NULL;
   220 	    baton->state=WARNINGS_IN_WARNING;
   221 	    break;
   222 	case WARNINGS_IN_TEXT:
   223 	    baton->state=baton->parent_state;
   224 	    break;
   225 	default:
   226 	    g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_UNKNOWN_ELEMENT,
   227 	      "Unexpected element ending: '%s'",element_name);
   228 	    return;
   229     }
   230 }
   231 
   232 static void warnings_parser_text(GMarkupParseContext *context,
   233   const char *text,gsize text_len,void *user_data,GError **error)
   234 {
   235     char *s,*t;
   236     WarningsBaton *baton=user_data;
   237     switch(baton->state)
   238     {
   239 	case WARNINGS_IN_EXPECTED:
   240 	    if (strspn(text," \t\n")!=text_len)
   241 		g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT,
   242 		  "The 'expected' tag does not take any content");
   243 	    break;
   244 	case WARNINGS_IN_SUMMARY:
   245 	    if (strspn(text," \t\n")!=text_len)
   246 		g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT,
   247 		  "The summary tags do not take any content");
   248 	    break;
   249 	case WARNINGS_IN_WARNING:
   250 	    if (strspn(text," \t\n")!=text_len)
   251 		g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT,
   252 		  "The warning tags do not take any content");
   253 	    break;
   254 	case WARNINGS_IN_AT:
   255 	    if (strspn(text," \t\n")!=text_len)
   256 		g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT,
   257 		  "The 'at' tag does not take any content");
   258 	    break;
   259 	case WARNINGS_IN_TEXT:
   260 	    s=g_strdup(text+strspn(text," \t\n"));
   261 	    g_strchomp(s);
   262 	    if (baton->parent_state==WARNINGS_IN_SUMMARY)
   263 		baton->testcase->summary.texts=
   264 		  g_slist_prepend(baton->testcase->summary.texts,s);
   265 	    else if (baton->warning->text)
   266 	    {
   267 		t=g_strconcat(baton->warning->text,s,NULL);
   268 		g_free(baton->warning->text);
   269 		g_free(s);
   270 		baton->warning->text=t;
   271 	    }
   272 	    else
   273 		baton->warning->text=s;
   274 	    break;
   275 	default:
   276 	    g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT,
   277 	      "Unexpected content: '%s'",text);
   278 	    return;
   279     }
   280 }
   281 
   282 GMarkupParseContext *warnings_parse_context_new(Testcase *testcase)
   283 {
   284     static GMarkupParser parser={0};
   285     WarningsBaton *baton;
   286     parser.start_element=warnings_parser_start_element;
   287     parser.end_element=warnings_parser_end_element;
   288     parser.text=warnings_parser_text;
   289     baton=g_new0(WarningsBaton,1);
   290     baton->testcase=testcase;
   291     baton->parent_state=WARNINGS_INIT;
   292     baton->state=WARNINGS_INIT;
   293     return g_markup_parse_context_new(&parser,
   294       G_MARKUP_TREAT_CDATA_AS_TEXT|G_MARKUP_PREFIX_ERROR_POSITION,
   295       baton,g_free);
   296 }