forked from KolibriOS/kolibrios
245 lines
5.2 KiB
C
245 lines
5.2 KiB
C
|
#include <ctype.h>
|
||
|
#include <inttypes.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <libcss/libcss.h>
|
||
|
|
||
|
#include "utils/utils.h"
|
||
|
|
||
|
#include "dump.h"
|
||
|
#include "testutils.h"
|
||
|
|
||
|
/** \todo at some point, we need to extend this to handle nested blocks */
|
||
|
typedef struct line_ctx {
|
||
|
size_t buflen;
|
||
|
size_t bufused;
|
||
|
uint8_t *buf;
|
||
|
|
||
|
size_t explen;
|
||
|
size_t expused;
|
||
|
char *exp;
|
||
|
|
||
|
bool indata;
|
||
|
bool inerrors;
|
||
|
bool inexp;
|
||
|
|
||
|
bool inrule;
|
||
|
} line_ctx;
|
||
|
|
||
|
static bool handle_line(const char *data, size_t datalen, void *pw);
|
||
|
static void css__parse_expected(line_ctx *ctx, const char *data, size_t len);
|
||
|
static void run_test(const uint8_t *data, size_t len,
|
||
|
const char *exp, size_t explen);
|
||
|
|
||
|
static void *myrealloc(void *data, size_t len, void *pw)
|
||
|
{
|
||
|
UNUSED(pw);
|
||
|
|
||
|
return realloc(data, len);
|
||
|
}
|
||
|
|
||
|
static css_error resolve_url(void *pw,
|
||
|
const char *base, lwc_string *rel, lwc_string **abs)
|
||
|
{
|
||
|
UNUSED(pw);
|
||
|
UNUSED(base);
|
||
|
|
||
|
/* About as useless as possible */
|
||
|
*abs = lwc_string_ref(rel);
|
||
|
|
||
|
return CSS_OK;
|
||
|
}
|
||
|
|
||
|
static bool fail_because_lwc_leaked = false;
|
||
|
|
||
|
static void
|
||
|
printing_lwc_iterator(lwc_string *str, void *pw)
|
||
|
{
|
||
|
UNUSED(pw);
|
||
|
|
||
|
printf(" DICT: %*s\n", (int)(lwc_string_length(str)), lwc_string_data(str));
|
||
|
fail_because_lwc_leaked = true;
|
||
|
}
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
line_ctx ctx;
|
||
|
|
||
|
if (argc != 2) {
|
||
|
printf("Usage: %s <filename>\n", argv[0]);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
ctx.buflen = css__parse_filesize(argv[1]);
|
||
|
if (ctx.buflen == 0)
|
||
|
return 1;
|
||
|
|
||
|
ctx.buf = malloc(ctx.buflen);
|
||
|
if (ctx.buf == NULL) {
|
||
|
printf("Failed allocating %u bytes\n",
|
||
|
(unsigned int) ctx.buflen);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
ctx.buf[0] = '\0';
|
||
|
ctx.bufused = 0;
|
||
|
ctx.explen = 0;
|
||
|
ctx.expused = 0;
|
||
|
ctx.exp = NULL;
|
||
|
ctx.indata = false;
|
||
|
ctx.inerrors = false;
|
||
|
ctx.inexp = false;
|
||
|
|
||
|
assert(css__parse_testfile(argv[1], handle_line, &ctx) == true);
|
||
|
|
||
|
/* and run final test */
|
||
|
if (ctx.bufused > 0)
|
||
|
run_test(ctx.buf, ctx.bufused, ctx.exp, ctx.expused);
|
||
|
|
||
|
free(ctx.buf);
|
||
|
free(ctx.exp);
|
||
|
|
||
|
lwc_iterate_strings(printing_lwc_iterator, NULL);
|
||
|
|
||
|
assert(fail_because_lwc_leaked == false);
|
||
|
|
||
|
printf("PASS\n");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
bool handle_line(const char *data, size_t datalen, void *pw)
|
||
|
{
|
||
|
line_ctx *ctx = (line_ctx *) pw;
|
||
|
|
||
|
if (data[0] == '#') {
|
||
|
if (ctx->inexp) {
|
||
|
/* This marks end of testcase, so run it */
|
||
|
|
||
|
run_test(ctx->buf, ctx->bufused,
|
||
|
ctx->exp, ctx->expused);
|
||
|
|
||
|
ctx->buf[0] = '\0';
|
||
|
ctx->bufused = 0;
|
||
|
|
||
|
ctx->expused = 0;
|
||
|
}
|
||
|
|
||
|
if (ctx->indata && strncasecmp(data+1, "errors", 6) == 0) {
|
||
|
ctx->indata = false;
|
||
|
ctx->inerrors = true;
|
||
|
ctx->inexp = false;
|
||
|
} else if (ctx->inerrors &&
|
||
|
strncasecmp(data+1, "expected", 8) == 0) {
|
||
|
ctx->indata = false;
|
||
|
ctx->inerrors = false;
|
||
|
ctx->inexp = true;
|
||
|
ctx->inrule = false;
|
||
|
} else if (ctx->inexp && strncasecmp(data+1, "data", 4) == 0) {
|
||
|
ctx->indata = true;
|
||
|
ctx->inerrors = false;
|
||
|
ctx->inexp = false;
|
||
|
} else if (ctx->indata) {
|
||
|
memcpy(ctx->buf + ctx->bufused, data, datalen);
|
||
|
ctx->bufused += datalen;
|
||
|
} else {
|
||
|
ctx->indata = (strncasecmp(data+1, "data", 4) == 0);
|
||
|
ctx->inerrors = (strncasecmp(data+1, "errors", 6) == 0);
|
||
|
ctx->inexp = (strncasecmp(data+1, "expected", 8) == 0);
|
||
|
}
|
||
|
} else {
|
||
|
if (ctx->indata) {
|
||
|
memcpy(ctx->buf + ctx->bufused, data, datalen);
|
||
|
ctx->bufused += datalen;
|
||
|
}
|
||
|
if (ctx->inexp) {
|
||
|
css__parse_expected(ctx, data, datalen);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void css__parse_expected(line_ctx *ctx, const char *data, size_t len)
|
||
|
{
|
||
|
while (ctx->expused + len >= ctx->explen) {
|
||
|
size_t required = ctx->explen == 0 ? 64 : ctx->explen * 2;
|
||
|
char *temp = realloc(ctx->exp, required);
|
||
|
if (temp == NULL) {
|
||
|
assert(0 && "No memory for expected output");
|
||
|
}
|
||
|
|
||
|
ctx->exp = temp;
|
||
|
ctx->explen = required;
|
||
|
}
|
||
|
|
||
|
memcpy(ctx->exp + ctx->expused, data, len);
|
||
|
|
||
|
ctx->expused += len;
|
||
|
}
|
||
|
|
||
|
void run_test(const uint8_t *data, size_t len, const char *exp, size_t explen)
|
||
|
{
|
||
|
css_stylesheet_params params;
|
||
|
css_stylesheet *sheet;
|
||
|
css_error error;
|
||
|
char *buf;
|
||
|
size_t buflen;
|
||
|
static int testnum;
|
||
|
|
||
|
buf = malloc(2 * explen);
|
||
|
if (buf == NULL) {
|
||
|
assert(0 && "No memory for result data");
|
||
|
}
|
||
|
buflen = 2 * explen;
|
||
|
|
||
|
params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
|
||
|
params.level = CSS_LEVEL_21;
|
||
|
params.charset = "UTF-8";
|
||
|
params.url = "foo";
|
||
|
params.title = NULL;
|
||
|
params.allow_quirks = false;
|
||
|
params.inline_style = false;
|
||
|
params.resolve = resolve_url;
|
||
|
params.resolve_pw = NULL;
|
||
|
params.import = NULL;
|
||
|
params.import_pw = NULL;
|
||
|
params.color = NULL;
|
||
|
params.color_pw = NULL;
|
||
|
params.font = NULL;
|
||
|
params.font_pw = NULL;
|
||
|
|
||
|
assert(css_stylesheet_create(¶ms, myrealloc, NULL,
|
||
|
&sheet) == CSS_OK);
|
||
|
|
||
|
error = css_stylesheet_append_data(sheet, data, len);
|
||
|
if (error != CSS_OK && error != CSS_NEEDDATA) {
|
||
|
printf("Failed appending data: %d\n", error);
|
||
|
assert(0);
|
||
|
}
|
||
|
|
||
|
assert(css_stylesheet_data_done(sheet) == CSS_OK);
|
||
|
|
||
|
testnum++;
|
||
|
|
||
|
dump_sheet(sheet, buf, &buflen);
|
||
|
|
||
|
if (2 * explen - buflen != explen || memcmp(buf, exp, explen) != 0) {
|
||
|
printf("Expected (%u):\n%.*s\n",
|
||
|
(int) explen, (int) explen, exp);
|
||
|
printf("Result (%u):\n%.*s\n", (int) (2 * explen - buflen),
|
||
|
(int) (2 * explen - buflen), buf);
|
||
|
assert(0 && "Result doesn't match expected");
|
||
|
}
|
||
|
|
||
|
css_stylesheet_destroy(sheet);
|
||
|
|
||
|
free(buf);
|
||
|
|
||
|
printf("Test %d: PASS\n", testnum);
|
||
|
}
|
||
|
|