sources/tester/main.c (132 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <inttypes.h>
#include "cqlrt.h"
#include "dbhelp.h"
// super cheesy error handling
#define E(x) \
if (SQLITE_OK != (x)) { \
fprintf(stderr, "error encountered at: %s (%s:%d)\n", #x, __FILE__, __LINE__); \
fprintf(stderr, "args: %s, %s\n", sql_name, result_name); \
fprintf(stderr, "sqlite3_errmsg: %s\n", sqlite3_errmsg(db)); \
goto error; \
}
const char *prefix = "The statement ending at line ";
int32_t tests = 0;
int32_t errors = 0;
int32_t attempts = 0;
sqlite3 *db = NULL;
const char *sql_name;
const char *result_name;
static void print_error_message(char *buffer, int32_t line, int32_t expected) {
printf("error: at line %d, expected '%s' %spresent", line, buffer, expected ? "" : "not ");
if (expected) {
printf(" %s%d times\n", expected == -1 ? "at least " : "", expected == -1 ? 1 : expected);
}
printf("\n");
}
void do_match(char *buffer, int32_t line) {
int32_t search_line;
int32_t count;
int32_t expected;
if (buffer[0] == '-' && buffer[1] == ' ') {
buffer++;
expected = 0;
}
else if (buffer[0] == '+' && buffer[1] == ' ') {
buffer++;
expected = -1;
}
else if (buffer[0] == '+' && buffer[1] >= '0' && buffer[1] <= '9' && buffer[2] == ' ') {
expected = buffer[1] - '0';
buffer += 2;
}
else {
return;
}
attempts++;
// replace the trailing linefeed with %
int32_t len = strlen(buffer);
buffer[len-1] = '%';
buffer[0] = '%';
cql_string_ref ref = cql_string_ref_new(buffer);
E(dbhelp_find(db, line, ref, &search_line, &count));
cql_string_release(ref);
if (expected == count || (expected == -1 && count > 0)) {
return;
}
errors++;
print_error_message(buffer, line, expected);
printf("found:\n");
E(dbhelp_dump_line(db, search_line));
int32_t prev;
E(dbhelp_prev_line(db, search_line, &prev));
printf("\nThe corresponding test case is:\n");
E(dbhelp_dump_source(db, prev, search_line));
print_error_message(buffer, line, expected);
printf("test file: %s\n", sql_name);
printf("result file: %s\n", result_name);
printf("\n");
return;
error:
printf("unexpected sqlite error\n");
exit(1);
}
int main(int argc, char **argv) {
if (argc != 3) {
printf("usage cql-verify foo.sql foo.out\n");
printf("cql-verify is a test tool. It processes the input foo.sql\n");
printf("looking for patterns to match in the CQL output foo.out\n");
exit(0);
}
sql_name = argv[1];
result_name = argv[2];
FILE *sql = fopen(sql_name, "r");
if (!sql) {
fprintf(stderr, "unable to open file '%s'\n", sql_name);
}
FILE *result = fopen(result_name, "r");
if (!result) {
fprintf(stderr, "unable to open file '%s'\n", result_name);
}
E(sqlite3_open(":memory:", &db));
E(dbhelp_setup(db));
char buffer[40960]; // good enough for test purposes
int32_t line = 0;
int32_t len = strlen(prefix);
while (fgets(buffer, sizeof(buffer), result)) {
const char *p = strstr(buffer, prefix);
if (p) {
line = atoi(p + len);
}
cql_string_ref ref = cql_string_ref_new(buffer);
if (line == 0) continue;
E(dbhelp_add(db, line, ref));
cql_string_release(ref);
}
fclose(result);
line = 1;
while (fgets(buffer, sizeof(buffer), sql)) {
cql_string_ref ref = cql_string_ref_new(buffer);
E(dbhelp_add_source(db, line, ref));
cql_string_release(ref);
line++;
}
fclose(sql);
dbhelp_source_result_set_ref result_set;
E(dbhelp_source_fetch_results(db, &result_set));
cql_int32 count = dbhelp_source_result_count(result_set);
for (cql_int32 i = 0; i < count; i++) {
cql_string_ref ref;
line = dbhelp_source_get_line(result_set, i);
ref = dbhelp_source_get_data(result_set, i);
char *text = (char*)ref->ptr;
if (strstr(text, "-- TEST:")) {
tests++;
}
if (!strncmp(text, "-- +", 4) || !strncmp(text, "-- -", 4)) {
do_match(text + 3, line);
}
}
cql_result_set_release(result_set);
printf("Verification results: %d tests matched %d patterns of which %d were errors.\n", tests, attempts, errors);
exit(errors);
error:
exit(1);
}