xtc/tests/unit/test_project_diagnostics.c

112 lines
5.1 KiB
C

#define _POSIX_C_SOURCE 200809L
#include "xtc/xtc_project.h"
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
/* Linker interposition injects errors only into this test executable. */
static int fault;
int __real_fflush(FILE *file);
int __real_fclose(FILE *file);
int __real_fsync(int descriptor);
int __real_rename(const char *old, const char *next);
int __wrap_fflush(FILE *file)
{
if (fault == 1) { errno = EIO; return EOF; }
return __real_fflush(file);
}
int __wrap_fclose(FILE *file)
{
int result = __real_fclose(file);
if (fault == 4) { errno = EIO; return EOF; }
return result;
}
int __wrap_fsync(int descriptor)
{
struct stat info;
assert(fstat(descriptor,&info) == 0);
if ((fault == 2 && S_ISREG(info.st_mode)) || (fault == 5 && S_ISDIR(info.st_mode))) { errno = EIO; return -1; }
return __real_fsync(descriptor);
}
int __wrap_rename(const char *old, const char *next)
{
if (fault == 3) { errno = EIO; return -1; }
return __real_rename(old,next);
}
static void write_text(const char *path, const char *text)
{
FILE *file = fopen(path,"wb"); assert(file);
assert(fwrite(text,1,strlen(text),file) == strlen(text)); assert(fclose(file) == 0);
}
static size_t bytes(const char *path, char out[4096])
{
FILE *file = fopen(path,"rb"); size_t n;
assert(file); n = fread(out,1,4096,file); assert(!ferror(file) && feof(file)); assert(fclose(file) == 0); return n;
}
static void no_temporaries(const char *path)
{
DIR *directory = opendir(path); struct dirent *entry; assert(directory);
while ((entry = readdir(directory))) assert(!strstr(entry->d_name,".tmp."));
assert(closedir(directory) == 0);
}
int main(void)
{
char root[] = "/tmp/xtc-project-report-XXXXXX", song[256], bad[256];
char before[4096], after[4096]; size_t size, n;
xtc_project *old = NULL, *next = NULL, *loaded = NULL;
xtc_project_diagnostic diagnostic;
xtc_track_info track;
uint64_t id;
int mode;
assert(mkdtemp(root));
snprintf(song,sizeof(song),"%s/song.xtc",root); snprintf(bad,sizeof(bad),"%s/bad.xtc",root);
assert(xtc_project_create(&old) == XTC_OK && xtc_project_create(&next) == XTC_OK && xtc_project_create(&loaded) == XTC_OK);
assert(xtc_project_add_track(old,"Old",&id) == XTC_OK && xtc_project_add_track(next,"New",&id) == XTC_OK);
assert(xtc_project_save(old,song) == XTC_OK); size = bytes(song,before);
assert(xtc_project_load_diagnostic(loaded,song,&diagnostic) == XTC_OK && diagnostic.result == XTC_OK &&
diagnostic.format_version == 12 && !diagnostic.line);
for (mode = 1; mode <= 5; ++mode) {
fault = mode;
assert(xtc_project_save(next,song) == XTC_ERR_IO);
fault = 0;
no_temporaries(root);
n = bytes(song,after);
if (mode < 5) assert(n == size && !memcmp(before,after,size));
assert(xtc_project_load(loaded,song) == XTC_OK);
assert(xtc_project_get_track(loaded,0,&track) == XTC_OK && !strcmp(track.name,mode < 5 ? "Old" : "New"));
}
write_text(bad,"XTC_PROJECT 999\n");
assert(xtc_project_load_diagnostic(loaded,bad,&diagnostic) == XTC_ERR_UNSUPPORTED && diagnostic.line == 1 &&
diagnostic.format_version == 999 && !strcmp(diagnostic.record,"XTC_PROJECT") && strstr(diagnostic.message,"1..12"));
write_text(bad,"XTC_PROJECT 10\nAPP 0 1 0\nTEMPO nope\n");
assert(xtc_project_load_diagnostic(loaded,bad,&diagnostic) == XTC_ERR_FORMAT && diagnostic.line == 3 &&
!strcmp(diagnostic.record,"TEMPO"));
write_text(bad,"XTC_PROJECT 10\n");
assert(xtc_project_load_diagnostic(loaded,bad,&diagnostic) == XTC_ERR_FORMAT && diagnostic.line == 2 &&
!strcmp(diagnostic.record,"APP"));
write_text(bad,"XTC_PROJECT 10\nAPP 0 1 0\nTEMPO 120000\nIDS 0 0\nGRAPH 1 1 1 0\nNODE 0 7 00000000\n");
assert(xtc_project_load_diagnostic(loaded,bad,&diagnostic) == XTC_ERR_UNSUPPORTED && diagnostic.line == 6 &&
!strcmp(diagnostic.record,"NODE") && strstr(diagnostic.message,"node type"));
{
FILE *file = fopen(bad,"wb"); assert(file);
assert(ftruncate(fileno(file),4194305) == 0 && fclose(file) == 0);
assert(xtc_project_load_diagnostic(loaded,bad,&diagnostic) == XTC_ERR_FORMAT && !diagnostic.line &&
!strcmp(diagnostic.record,"SIZE") && strstr(diagnostic.message,"4 MiB"));
}
{
FILE *file = fopen(bad,"wb"); size_t i; assert(file);
for (i = 0; i < 1536; ++i) assert(fputc('A',file) != EOF);
assert(fputc('\n',file) != EOF && fclose(file) == 0);
assert(xtc_project_load_diagnostic(loaded,bad,&diagnostic) == XTC_ERR_FORMAT && diagnostic.line == 1);
}
assert(xtc_project_get_track(loaded,0,&track) == XTC_OK && !strcmp(track.name,"New"));
assert(xtc_project_load_diagnostic(loaded,"/absent/xtc-report.xtc",&diagnostic) == XTC_ERR_IO && !diagnostic.line);
xtc_project_destroy(old); xtc_project_destroy(next); xtc_project_destroy(loaded);
unlink(song); unlink(bad); assert(rmdir(root) == 0);
puts("Project load diagnostics, retained state, bounded input and pre/post-rename save faults passed.");
return 0;
}