Add the tester
This commit is contained in:
205
tools/init.c
Normal file
205
tools/init.c
Normal file
@ -0,0 +1,205 @@
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/reboot.h>
|
||||
|
||||
#define FILENAME_BUFFER_SIZE 256
|
||||
|
||||
size_t read_command(int descriptor, char *command_buffer)
|
||||
{
|
||||
ssize_t bytes_read = 0;
|
||||
size_t read_so_far = 0;
|
||||
|
||||
while ((bytes_read = read(descriptor, command_buffer + read_so_far, FILENAME_BUFFER_SIZE - read_so_far - 1)) > 0)
|
||||
{
|
||||
read_so_far += bytes_read;
|
||||
if (read_so_far >= FILENAME_BUFFER_SIZE - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
command_buffer[read_so_far] = 0;
|
||||
return read_so_far;
|
||||
}
|
||||
|
||||
enum status
|
||||
{
|
||||
status_success,
|
||||
status_failure,
|
||||
status_warning,
|
||||
status_fatal
|
||||
};
|
||||
|
||||
unsigned int make_path(char *destination, const char *directory, const char *filename, const char *extension)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
for (; i < FILENAME_BUFFER_SIZE; i++)
|
||||
{
|
||||
if (directory[i] == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
destination[i] = directory[i];
|
||||
}
|
||||
for (int j = 0; i < FILENAME_BUFFER_SIZE; i++, j++)
|
||||
{
|
||||
if (filename[j] == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
destination[i] = filename[j];
|
||||
}
|
||||
if (extension == NULL)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
for (int j = 0; i < FILENAME_BUFFER_SIZE; i++, j++)
|
||||
{
|
||||
if (extension[j] == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
destination[i] = extension[j];
|
||||
}
|
||||
done:
|
||||
destination[i] = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
enum status run_test(const char *file_entry_name)
|
||||
{
|
||||
printf("Running %s. ", file_entry_name);
|
||||
|
||||
char filename[FILENAME_BUFFER_SIZE];
|
||||
char command_buffer[FILENAME_BUFFER_SIZE];
|
||||
char file_buffer[256];
|
||||
int pipe_ends[2];
|
||||
|
||||
if (pipe(pipe_ends) == -1)
|
||||
{
|
||||
perror("pipe");
|
||||
return status_fatal;
|
||||
}
|
||||
make_path(filename, "./tests/", file_entry_name, NULL);
|
||||
|
||||
int child_pid = fork();
|
||||
if (child_pid == -1)
|
||||
{
|
||||
return status_fatal;
|
||||
}
|
||||
else if (child_pid == 0)
|
||||
{
|
||||
close(STDIN_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
close(pipe_ends[0]); // Close the read end.
|
||||
|
||||
if (dup2(pipe_ends[1], STDOUT_FILENO) == -1)
|
||||
{
|
||||
perror("dup2");
|
||||
}
|
||||
else
|
||||
{
|
||||
execl(filename, filename);
|
||||
perror("execl");
|
||||
}
|
||||
close(STDOUT_FILENO);
|
||||
close(pipe_ends[1]);
|
||||
_exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(pipe_ends[1]); // Close the write end.
|
||||
read_command(pipe_ends[0], command_buffer);
|
||||
close(pipe_ends[0]);
|
||||
|
||||
int wait_status = 0;
|
||||
wait(&wait_status);
|
||||
|
||||
make_path(filename, "./expectations/", file_entry_name, ".txt");
|
||||
|
||||
FILE *expectation_descriptor = fopen(filename, "r");
|
||||
|
||||
if (expectation_descriptor == NULL)
|
||||
{
|
||||
return status_warning;
|
||||
}
|
||||
size_t read_from_file = fread(file_buffer, 1, sizeof(file_buffer) - 1, expectation_descriptor);
|
||||
fclose(expectation_descriptor);
|
||||
|
||||
file_buffer[read_from_file] = 0;
|
||||
for (unsigned int i = 0; ; ++i)
|
||||
{
|
||||
if (command_buffer[i] == 0 && file_buffer[i] == 0)
|
||||
{
|
||||
fwrite("\n", 1, 1, stdout);
|
||||
return status_success;
|
||||
}
|
||||
else if (command_buffer[i] != file_buffer[i])
|
||||
{
|
||||
printf("Failed. Got:\n%s", command_buffer);
|
||||
return status_failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct summary
|
||||
{
|
||||
size_t total;
|
||||
size_t failure;
|
||||
size_t success;
|
||||
};
|
||||
|
||||
void walk()
|
||||
{
|
||||
DIR *directory_stream = opendir("./tests");
|
||||
struct dirent *file_entry;
|
||||
|
||||
struct summary test_summary = { .total = 0, .failure = 0, .success = 0 };
|
||||
|
||||
while ((file_entry = readdir(directory_stream)) != NULL)
|
||||
{
|
||||
if (file_entry->d_name[0] == '.')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
++test_summary.total;
|
||||
switch (run_test(file_entry->d_name))
|
||||
{
|
||||
case status_failure:
|
||||
++test_summary.failure;
|
||||
break;
|
||||
case status_success:
|
||||
++test_summary.success;
|
||||
break;
|
||||
case status_warning:
|
||||
break;
|
||||
case status_fatal:
|
||||
goto end_walk;
|
||||
}
|
||||
}
|
||||
printf("Successful: %lu, Failed: %lu, Total: %lu.\n",
|
||||
test_summary.success, test_summary.failure, test_summary.total);
|
||||
end_walk:
|
||||
closedir(directory_stream);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int dev_console = open("/dev/console", O_WRONLY);
|
||||
if (dev_console != -1)
|
||||
{
|
||||
dup2(dev_console, STDOUT_FILENO);
|
||||
walk();
|
||||
close(dev_console);
|
||||
}
|
||||
sync();
|
||||
reboot(RB_POWER_OFF);
|
||||
|
||||
return 1;
|
||||
}
|
Reference in New Issue
Block a user