blob: a951dedd75e6a9d42907a985f573485be687da06 [file] [log] [blame] [raw]
#include "fio.h"
#define INCLUDE_MUSTACHE_IMPLEMENTATION 1
#include "mustache_parser.h"
static size_t callback_count = 0;
static struct {
enum cb_type_e {
CB_ERROR,
CB_ON_TEXT,
CB_ON_ARG,
CB_ON_ARG_UNESCAPE,
CB_ON_TEST,
CB_ON_START,
} cb_type;
void *udata1;
} callback_expected[] = {
{CB_ON_TEXT, (void *)0}, {CB_ON_TEST, (void *)0},
{CB_ON_START, (void *)0}, {CB_ON_ARG, (void *)1},
{CB_ON_START, (void *)0}, {CB_ON_ARG, (void *)1},
{CB_ON_ARG_UNESCAPE, (void *)0}, {CB_ON_ARG_UNESCAPE, (void *)0},
{CB_ON_TEST, (void *)0}, {CB_ON_START, (void *)0},
{CB_ON_ARG_UNESCAPE, (void *)1}, {CB_ON_ARG_UNESCAPE, (void *)1},
{CB_ON_TEST, (void *)1}, {CB_ERROR, NULL},
};
static const size_t callback_max =
sizeof(callback_expected) / sizeof(callback_expected[0]);
static void mustache_test_callback(mustache_section_s *section,
enum cb_type_e expected) {
if (callback_expected[callback_count].cb_type == CB_ERROR) {
fprintf(stderr, "FAILED: mustache callback count overflow\n");
exit(-1);
}
if (callback_expected[callback_count].cb_type != expected) {
fprintf(stderr,
"FAILED: mustache callback type mismatch (count: %zu, expected %u, "
"got %u)\n",
callback_count, callback_expected[callback_count].cb_type,
expected);
exit(-1);
}
if (callback_expected[callback_count].udata1 != section->udata1) {
fprintf(stderr,
"FAILED: mustache callback udata1 mismatch (count: %zu, expected "
"%p, got %p)\n",
callback_count, callback_expected[callback_count].udata1,
section->udata1);
exit(-1);
}
++callback_count;
}
static int mustache_on_arg(mustache_section_s *section, const char *name,
uint32_t name_len, unsigned char escape) {
mustache_test_callback(section, escape ? CB_ON_ARG : CB_ON_ARG_UNESCAPE);
(void)name;
(void)name_len;
return 0;
}
static int mustache_on_text(mustache_section_s *section, const char *data,
uint32_t data_len) {
mustache_test_callback(section, CB_ON_TEXT);
(void)data;
(void)data_len;
return 0;
}
static int32_t mustache_on_section_test(mustache_section_s *section,
const char *name, uint32_t name_len) {
mustache_test_callback(section, CB_ON_TEST);
(void)name;
(void)name_len;
static int ret = 1;
return (ret-- == 1 ? 2 : (ret + 1));
}
static int mustache_on_section_start(mustache_section_s *section,
char const *name, uint32_t name_len,
uint32_t index) {
mustache_test_callback(section, CB_ON_START);
section->udata1 = (void *)((uintptr_t)section->udata1 + 1);
(void)index;
(void)name;
(void)name_len;
return 0;
}
static void mustache_on_formatting_error(void *udata1, void *udata2) {
(void)udata1;
(void)udata2;
}
static inline void save2file(char const *filename, char const *data,
size_t length) {
int fd = open(filename, O_CREAT | O_RDWR, 0);
if (fd == -1) {
perror("Couldn't open / create file for template testing");
exit(-1);
}
fchmod(fd, 0777);
if (pwrite(fd, data, length, 0) != (ssize_t)length) {
perror("Mustache template write error");
exit(-1);
}
close(fd);
}
static inline void mustache_print_instructions(mustache_s *m) {
mustache__instruction_s *ary = (mustache__instruction_s *)(m + 1);
for (uint32_t i = 0; i < m->u.read_only.intruction_count; ++i) {
char *name = NULL;
switch (ary[i].instruction) {
case MUSTACHE_WRITE_TEXT:
name = "MUSTACHE_WRITE_TEXT";
break;
case MUSTACHE_WRITE_ARG:
name = "MUSTACHE_WRITE_ARG";
break;
case MUSTACHE_WRITE_ARG_UNESCAPED:
name = "MUSTACHE_WRITE_ARG_UNESCAPED";
break;
case MUSTACHE_SECTION_START:
name = "MUSTACHE_SECTION_START";
break;
case MUSTACHE_SECTION_START_INV:
name = "MUSTACHE_SECTION_START_INV";
break;
case MUSTACHE_SECTION_END:
name = "MUSTACHE_SECTION_END";
break;
case MUSTACHE_SECTION_GOTO:
name = "MUSTACHE_SECTION_GOTO";
break;
default:
name = "UNKNOWN!!!";
break;
}
fprintf(stderr, "[%u] %s, start: %u, len %u\n", i, name, ary[i].data.start,
ary[i].data.len);
}
}
void mustache_test(void) {
fprintf(stderr, "=== Testing Mustache parser (mustache_parser.h)\n");
char const *template =
"Hi there{{#user}}{{name}}{{/user}}{{> mustache_test_partial }}";
char const *partial = "{{& raw1}}{{{raw2}}}{{^negative}}"
"{{> mustache_test_partial }}{{=<< >>=}}<</negative>>";
char const *partial2 = "{{& raw1}}{{{raw2}}}{{^negative}}"
"{{=<< >>=}}<</negative>>";
char const *template_name = "mustache_test_template.mustache";
char const *partial_name = "mustache_test_partial.mustache";
save2file(template_name, template, strlen(template));
save2file(partial_name, partial, strlen(partial));
mustache_error_en err = MUSTACHE_OK;
mustache_s *m = mustache_load(.filename = template_name, .err = &err);
if (!m) {
unlink(template_name);
unlink(partial_name);
FIO_ASSERT(m, "Mustache template loading from file failed with error %u\n",
err);
}
mustache_free(m);
m = mustache_load(.data = partial2, .data_len = strlen(partial2),
.err = &err);
if (!m) {
unlink(template_name);
unlink(partial_name);
FIO_ASSERT(
m, "Mustache template loading partial as data failed with error %u\n",
err);
}
mustache_free(m);
m = mustache_load(.filename = template_name, .data = template,
.data_len = strlen(template), .err = &err);
unlink(template_name);
unlink(partial_name);
uint32_t expected[] = {
MUSTACHE_SECTION_START, MUSTACHE_WRITE_TEXT,
MUSTACHE_SECTION_START, MUSTACHE_WRITE_ARG,
MUSTACHE_SECTION_END, MUSTACHE_SECTION_START,
MUSTACHE_WRITE_ARG_UNESCAPED, MUSTACHE_WRITE_ARG_UNESCAPED,
MUSTACHE_SECTION_START_INV, MUSTACHE_SECTION_GOTO,
MUSTACHE_SECTION_END, MUSTACHE_SECTION_END,
MUSTACHE_SECTION_END,
};
FIO_ASSERT(m, "Mustache template loading failed with error %u\n", err);
fprintf(stderr, "* template loaded, testing template instruction array.\n");
mustache_print_instructions(m);
mustache__instruction_s *ary = (mustache__instruction_s *)(m + 1);
FIO_ASSERT(m->u.read_only.intruction_count == 13,
"Mustache template instruction count error %u\n",
m->u.read_only.intruction_count);
for (uint16_t i = 0; i < 13; ++i) {
FIO_ASSERT(ary[i].instruction == expected[i],
"Mustache instraction[%u] error, type %u != %u\n", i,
ary[0].instruction, expected[i]);
}
mustache_build(m, .udata1 = NULL);
FIO_ASSERT(callback_count + 1 == callback_max,
"Callback count error %zu != %zu", callback_count + 1,
callback_max);
FIO_ASSERT(callback_expected[callback_count].cb_type == CB_ERROR,
"Callback type error on finish");
/* cleanup */
mustache_free(m);
fprintf(stderr, "* passed.\n");
}