Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. #include <inttypes.h>
  2. #include <stdbool.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6.  
  7. #include <parserutils/input/inputstream.h>
  8.  
  9. #include <libcss/libcss.h>
  10.  
  11. #include "charset/detect.h"
  12. #include "lex/lex.h"
  13. #include "utils/utils.h"
  14.  
  15. #include "testutils.h"
  16.  
  17. typedef struct exp_entry {
  18.         css_token_type type;
  19. #define EXP_ENTRY_TEXT_LEN (128)
  20.         char text[EXP_ENTRY_TEXT_LEN];
  21.         size_t textLen;
  22.         bool hasText;
  23. } exp_entry;
  24.  
  25. typedef struct line_ctx {
  26.         size_t buflen;
  27.         size_t bufused;
  28.         uint8_t *buf;
  29.  
  30.         size_t explen;
  31.         size_t expused;
  32.         exp_entry *exp;
  33.  
  34.         bool indata;
  35.         bool inexp;
  36. } line_ctx;
  37.  
  38. static bool handle_line(const char *data, size_t datalen, void *pw);
  39. static void css__parse_expected(line_ctx *ctx, const char *data, size_t len);
  40. static const char *string_from_type(css_token_type type);
  41. static css_token_type string_to_type(const char *data, size_t len);
  42. static void run_test(const uint8_t *data, size_t len,
  43.                 exp_entry *exp, size_t explen);
  44.  
  45. static void *myrealloc(void *data, size_t len, void *pw)
  46. {
  47.         UNUSED(pw);
  48.  
  49.         return realloc(data, len);
  50. }
  51.  
  52. int main(int argc, char **argv)
  53. {
  54.         line_ctx ctx;
  55.  
  56.         if (argc != 2) {
  57.                 printf("Usage: %s <filename>\n", argv[0]);
  58.                 return 1;
  59.         }
  60.  
  61.         ctx.buflen = css__parse_filesize(argv[1]);
  62.         if (ctx.buflen == 0)
  63.                 return 1;
  64.  
  65.         ctx.buf = malloc(ctx.buflen);
  66.         if (ctx.buf == NULL) {
  67.                 printf("Failed allocating %u bytes\n",
  68.                                 (unsigned int) ctx.buflen);
  69.                 return 1;
  70.         }
  71.  
  72.         ctx.buf[0] = '\0';
  73.         ctx.bufused = 0;
  74.         ctx.explen = 0;
  75.         ctx.expused = 0;
  76.         ctx.exp = NULL;
  77.         ctx.indata = false;
  78.         ctx.inexp = false;
  79.  
  80.         assert(css__parse_testfile(argv[1], handle_line, &ctx) == true);
  81.  
  82.         /* and run final test */
  83.         if (ctx.bufused > 0)
  84.                 run_test(ctx.buf, ctx.bufused, ctx.exp, ctx.expused);
  85.  
  86.         free(ctx.buf);
  87.         free(ctx.exp);
  88.  
  89.         printf("PASS\n");
  90.  
  91.         return 0;
  92. }
  93.  
  94. bool handle_line(const char *data, size_t datalen, void *pw)
  95. {
  96.         line_ctx *ctx = (line_ctx *) pw;
  97.  
  98.         if (data[0] == '#') {
  99.                 if (ctx->inexp) {
  100.                         /* This marks end of testcase, so run it */
  101.  
  102.                         run_test(ctx->buf, ctx->bufused,
  103.                                         ctx->exp, ctx->expused);
  104.  
  105.                         ctx->buf[0] = '\0';
  106.                         ctx->bufused = 0;
  107.  
  108.                         ctx->expused = 0;
  109.                 }
  110.  
  111.                 if (ctx->indata && strncasecmp(data+1, "expected", 8) == 0) {
  112.                         ctx->indata = false;
  113.                         ctx->inexp = true;
  114.                 } else if (!ctx->indata) {
  115.                         ctx->indata = (strncasecmp(data+1, "data", 4) == 0);
  116.                         ctx->inexp  = (strncasecmp(data+1, "expected", 8) == 0);
  117.                 } else {
  118.                         memcpy(ctx->buf + ctx->bufused, data, datalen);
  119.                         ctx->bufused += datalen;
  120.                 }
  121.         } else {
  122.                 if (ctx->indata) {
  123.                         memcpy(ctx->buf + ctx->bufused, data, datalen);
  124.                         ctx->bufused += datalen;
  125.                 }
  126.                 if (ctx->inexp) {
  127.                         if (data[datalen - 1] == '\n')
  128.                                 datalen -= 1;
  129.  
  130.                         css__parse_expected(ctx, data, datalen);
  131.                 }
  132.         }
  133.  
  134.         return true;
  135. }
  136.  
  137. void css__parse_expected(line_ctx *ctx, const char *data, size_t len)
  138. {
  139.         css_token_type type;
  140.         const char *colon = css__parse_strnchr(data, len, ':');
  141.  
  142.         if (colon == NULL)
  143.                 colon = data + len;
  144.  
  145.         type = string_to_type(data, colon - data);
  146.  
  147.         /* Append to list of expected tokens */
  148.         if (ctx->expused == ctx->explen) {
  149.                 size_t num = ctx->explen == 0 ? 4 : ctx->explen;
  150.  
  151.                 exp_entry *temp = realloc(ctx->exp,
  152.                                 num * 2 * sizeof(exp_entry));
  153.                 if (temp == NULL) {
  154.                         assert(0 && "No memory for expected tokens");
  155.                 }
  156.  
  157.                 ctx->exp = temp;
  158.                 ctx->explen = num * 2;
  159.         }
  160.  
  161.         ctx->exp[ctx->expused].type = type;
  162.         ctx->exp[ctx->expused].textLen = 0;
  163.         ctx->exp[ctx->expused].hasText = (colon != data + len);
  164.  
  165.         if (colon != data + len) {
  166.                 const char *p = colon + 1;
  167.                 bool escape = false;
  168.  
  169.                 for (len = len - (colon + 1 - data); len > 0; len--, p++) {
  170.                         char c;
  171.  
  172.                         if (escape == false && *p == '\\') {
  173.                                 escape = true;
  174.                                 continue;
  175.                         }
  176.  
  177.                         if (escape) {
  178.                                 switch (*p) {
  179.                                 case 'n':
  180.                                         c = 0xa;
  181.                                         break;
  182.                                 case 't':
  183.                                         c = 0x9;
  184.                                         break;
  185.                                 default:
  186.                                         c = *p;
  187.                                         break;
  188.                                 }
  189.                                 escape = false;
  190.                         } else {
  191.                                 c = *p;
  192.                         }
  193.  
  194.                         ctx->exp[ctx->expused].text[
  195.                                         ctx->exp[ctx->expused].textLen] = c;
  196.                         ctx->exp[ctx->expused].textLen++;
  197.  
  198.                         assert(ctx->exp[ctx->expused].textLen <
  199.                                         EXP_ENTRY_TEXT_LEN);
  200.                 }
  201.         }
  202.         ctx->expused++;
  203. }
  204.  
  205. const char *string_from_type(css_token_type type)
  206. {
  207.         const char *names[] =
  208.         {
  209.                 "IDENT", "ATKEYWORD", "HASH", "FUNCTION", "STRING", "INVALID",
  210.                 "URI", "UNICODE-RANGE", "CHAR", "NUMBER", "PERCENTAGE",
  211.                 "DIMENSION", "last_intern", "CDO", "CDC", "S", "COMMENT",
  212.                 "INCLUDES", "DASHMATCH", "PREFIXMATCH", "SUFFIXMATCH",
  213.                 "SUBSTRINGMATCH", "EOF"
  214.         };
  215.  
  216.         return names[type];
  217. }
  218.  
  219. css_token_type string_to_type(const char *data, size_t len)
  220. {
  221.         if (len == 5 && strncasecmp(data, "IDENT", len) == 0)
  222.                 return CSS_TOKEN_IDENT;
  223.         else if (len == 9 && strncasecmp(data, "ATKEYWORD", len) == 0)
  224.                 return CSS_TOKEN_ATKEYWORD;
  225.         else if (len == 6 && strncasecmp(data, "STRING", len) == 0)
  226.                 return CSS_TOKEN_STRING;
  227.         else if (len == 7 && strncasecmp(data, "INVALID", len) == 0)
  228.                 return CSS_TOKEN_INVALID_STRING;
  229.         else if (len == 4 && strncasecmp(data, "HASH", len) == 0)
  230.                 return CSS_TOKEN_HASH;
  231.         else if (len == 6 && strncasecmp(data, "NUMBER", len) == 0)
  232.                 return CSS_TOKEN_NUMBER;
  233.         else if (len == 10 && strncasecmp(data, "PERCENTAGE", len) == 0)
  234.                 return CSS_TOKEN_PERCENTAGE;
  235.         else if (len == 9 && strncasecmp(data, "DIMENSION", len) == 0)
  236.                 return CSS_TOKEN_DIMENSION;
  237.         else if (len == 3 && strncasecmp(data, "URI", len) == 0)
  238.                 return CSS_TOKEN_URI;
  239.         else if (len == 13 && strncasecmp(data, "UNICODE-RANGE", len) == 0)
  240.                 return CSS_TOKEN_UNICODE_RANGE;
  241.         else if (len == 3 && strncasecmp(data, "CDO", len) == 0)
  242.                 return CSS_TOKEN_CDO;
  243.         else if (len == 3 && strncasecmp(data, "CDC", len) == 0)
  244.                 return CSS_TOKEN_CDC;
  245.         else if (len == 1 && strncasecmp(data, "S", len) == 0)
  246.                 return CSS_TOKEN_S;
  247.         else if (len == 7 && strncasecmp(data, "COMMENT", len) == 0)
  248.                 return CSS_TOKEN_COMMENT;
  249.         else if (len == 8 && strncasecmp(data, "FUNCTION", len) == 0)
  250.                 return CSS_TOKEN_FUNCTION;
  251.         else if (len == 8 && strncasecmp(data, "INCLUDES", len) == 0)
  252.                 return CSS_TOKEN_INCLUDES;
  253.         else if (len == 9 && strncasecmp(data, "DASHMATCH", len) == 0)
  254.                 return CSS_TOKEN_DASHMATCH;
  255.         else if (len == 11 && strncasecmp(data, "PREFIXMATCH", len) == 0)
  256.                 return CSS_TOKEN_PREFIXMATCH;
  257.         else if (len == 11 && strncasecmp(data, "SUFFIXMATCH", len) == 0)
  258.                 return CSS_TOKEN_SUFFIXMATCH;
  259.         else if (len == 14 && strncasecmp(data, "SUBSTRINGMATCH", len) == 0)
  260.                 return CSS_TOKEN_SUBSTRINGMATCH;
  261.         else if (len == 4 && strncasecmp(data, "CHAR", len) == 0)
  262.                 return CSS_TOKEN_CHAR;
  263.         else
  264.                 return CSS_TOKEN_EOF;
  265. }
  266.  
  267. void run_test(const uint8_t *data, size_t len, exp_entry *exp, size_t explen)
  268. {
  269.         parserutils_inputstream *input;
  270.         css_lexer *lexer;
  271.         css_error error;
  272.         css_token *tok;
  273.         size_t e;
  274.         static int testnum;
  275.  
  276.         assert(parserutils_inputstream_create("UTF-8", CSS_CHARSET_DICTATED,
  277.                         css__charset_extract, myrealloc, NULL, &input) ==
  278.                         PARSERUTILS_OK);
  279.  
  280.         assert(css__lexer_create(input, myrealloc, NULL, &lexer) == CSS_OK);
  281.  
  282.         assert(parserutils_inputstream_append(input, data, len) ==
  283.                         PARSERUTILS_OK);
  284.  
  285.         assert(parserutils_inputstream_append(input, NULL, 0) ==
  286.                         PARSERUTILS_OK);
  287.  
  288.         e = 0;
  289.         testnum++;
  290.  
  291.         while ((error = css__lexer_get_token(lexer, &tok)) == CSS_OK) {
  292.                 if (tok->type != exp[e].type) {
  293.                         printf("%d: Got token %s, Expected %s [%d, %d]\n",
  294.                                 testnum, string_from_type(tok->type),
  295.                                 string_from_type(exp[e].type),
  296.                                 tok->line, tok->col);
  297.                         assert(0 && "Types differ");
  298.                 }
  299.  
  300.                 if (exp[e].hasText) {
  301.                         if (tok->data.len != exp[e].textLen) {
  302.                                 printf("%d: Got length %d, Expected %d\n",
  303.                                         testnum, (int) tok->data.len,
  304.                                         (int) exp[e].textLen);
  305.                                 assert(0 && "Text lengths differ");
  306.                         }
  307.  
  308.                         if (strncmp((char *) tok->data.data, exp[e].text,
  309.                                         tok->data.len) != 0) {
  310.                                 printf("%d: Got data '%.*s', Expected '%.*s'\n",
  311.                                         testnum,
  312.                                         (int) tok->data.len, tok->data.data,
  313.                                         (int) exp[e].textLen, exp[e].text);
  314.                                 assert(0 && "Text differs");
  315.                         }
  316.                 }
  317.  
  318.                 e++;
  319.  
  320.                 if (tok->type == CSS_TOKEN_EOF)
  321.                         break;
  322.         }
  323.  
  324.         assert(e == explen);
  325.  
  326.         css__lexer_destroy(lexer);
  327.  
  328.         parserutils_inputstream_destroy(input);
  329.  
  330.         printf("Test %d: PASS\n", testnum);
  331. }
  332.