Files
puzzles/fuzzpuzz.c
Ben Harris ffe2fa169f Extend fuzzpuzz to test more code
Now if the input save file loads correctly, fuzzpuzz asks the back-end
to draw the puzzle.  All the drawing operations are no-ops, but this
tests the drawing code in the back-end.
2023-02-13 21:23:58 +00:00

118 lines
2.7 KiB
C

/*
* fuzzpuzz.c: Fuzzing frontend to all puzzles.
*/
/*
* The idea here is that this front-end supports all back-ends and can
* feed them save files. This tests the deserialiser, the code for
* loading game descriptions, and the processing of move strings,
* without all the tedium of actually rendering anything.
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __AFL_FUZZ_TESTCASE_LEN
# include <unistd.h> /* read() is used by __AFL_FUZZ_TESTCASE_LEN. */
#endif
#include "puzzles.h"
#ifdef __AFL_FUZZ_INIT
__AFL_FUZZ_INIT();
#endif
static bool savefile_read(void *wctx, void *buf, int len)
{
FILE *fp = (FILE *)wctx;
int ret;
ret = fread(buf, 1, len, fp);
return (ret == len);
}
static void savefile_write(void *wctx, const void *buf, int len)
{
FILE *fp = (FILE *)wctx;
fwrite(buf, 1, len, fp);
}
static drawing_api drapi = { NULL };
int main(int argc, char **argv)
{
const char *err;
char *gamename;
int i, ret = -1;
const game *ourgame = NULL;
midend *me;
FILE *in = NULL;
int w, h;
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
exit(1);
}
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif
#ifdef __AFL_FUZZ_TESTCASE_LEN
/*
* AFL persistent mode, where we fuzz from a RAM buffer provided
* by AFL in a loop. This version can still be run standalone if
* necessary, for instance to diagnose a crash.
*/
while (__AFL_LOOP(10000)) {
if (in != NULL) fclose(in);
in = fmemopen(__AFL_FUZZ_TESTCASE_BUF, __AFL_FUZZ_TESTCASE_LEN, "r");
if (in == NULL) {
fprintf(stderr, "fmemopen failed");
ret = 1;
continue;
}
#else
in = stdin;
while (ret == -1) {
#endif
err = identify_game(&gamename, savefile_read, in);
if (err != NULL) {
fprintf(stderr, "%s\n", err);
ret = 1;
continue;
}
for (i = 0; i < gamecount; i++)
if (strcmp(gamename, gamelist[i]->name) == 0)
ourgame = gamelist[i];
sfree(gamename);
if (ourgame == NULL) {
fprintf(stderr, "Game not recognised\n");
ret = 1;
continue;
}
me = midend_new(NULL, ourgame, &drapi, NULL);
rewind(in);
err = midend_deserialise(me, savefile_read, in);
if (err != NULL) {
fprintf(stderr, "%s\n", err);
ret = 1;
midend_free(me);
continue;
}
w = h = INT_MAX;
midend_size(me, &w, &h, false, 1);
midend_redraw(me);
midend_serialise(me, savefile_write, stdout);
midend_free(me);
ret = 0;
}
return ret;
}