112 lines
5.2 KiB
C
112 lines
5.2 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 == XTC_PROJECT_FORMAT_VERSION && !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..15"));
|
|
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;
|
|
}
|