Compare commits

...

1 commit

Author SHA1 Message Date
03f3f59e2d add tests 2026-05-22 15:31:47 +02:00
3 changed files with 320 additions and 0 deletions

93
doubly_linked_list_test.h Normal file
View file

@ -0,0 +1,93 @@
#ifndef DOUBLY_LINKED_LIST_TEST_H
#define DOUBLY_LINKED_LIST_TEST_H
#include <assert.h>
#include "scheduler.h"
// External declarations of your implemented functions
bool stud_rq_empty(struct run_queue const *rq);
struct task *stud_task_create(int pid, enum states state);
void stud_task_free(struct task *task);
void stud_rq_destroy(struct run_queue *rq);
struct task *stud_rq_find(struct run_queue *rq, int pid);
struct task *stud_rq_head(struct run_queue *rq);
struct task *stud_rq_tail(struct run_queue *rq);
bool stud_rq_enqueue(struct run_queue *rq, struct task *task);
bool stud_rq_prepend(struct run_queue *rq, struct task *task);
size_t stud_rq_length(struct run_queue *rq);
// Helper to print queue exactly like the VPL server
static void print_rq(struct run_queue *rq) {
if (stud_rq_empty(rq)) {
printf("END\n");
return;
}
struct task *curr = rq->head;
do {
const char *state_str = (curr->state == READY) ? "ready" :
(curr->state == RUNNING) ? "running" :
(curr->state == BLOCKED) ? "blocked" : "terminated";
printf("{ id = %d, state = %s, runtime = %d } -- ", curr->pid, state_str, curr->runtime);
curr = curr->next;
} while (curr != rq->head);
printf("END\n");
}
void test_rq_empty() { /* omitted for brevity, passing */ }
void test_rq_head() { /* omitted for brevity, passing */ }
void test_rq_length() { /* omitted for brevity, passing */ }
// Crash line 128 in your log
void test_rq_destroy() {
struct run_queue rq = {NULL, 0, 0};
stud_rq_enqueue(&rq, stud_task_create(1, READY));
stud_rq_enqueue(&rq, stud_task_create(2, READY));
// Line 128
stud_rq_destroy(&rq);
assert(stud_rq_empty(&rq));
}
// Crash line 143 in your log
void test_rq_find() {
struct run_queue rq = {NULL, 0, 0};
// Line 143: This causes your code to segfault because rq is empty
// and stud_rq_find attempts to dereference NULL.
struct task *t = stud_rq_find(&rq, 99);
assert(t == NULL);
}
// Crash line 186 in your log
void test_rq_tail() {
struct run_queue rq = {NULL, 0, 0};
stud_rq_enqueue(&rq, stud_task_create(1, READY));
stud_rq_enqueue(&rq, stud_task_create(2, READY));
struct task *tail = stud_rq_tail(&rq);
// Line 186
assert(tail && tail->pid == 2);
}
void test_rq_enqueue() {
struct run_queue rq = {NULL, 0, 0};
printf("add tasks 1-4\n");
stud_rq_enqueue(&rq, stud_task_create(1, READY));
stud_rq_enqueue(&rq, stud_task_create(2, READY));
stud_rq_enqueue(&rq, stud_task_create(3, READY));
stud_rq_enqueue(&rq, stud_task_create(4, READY));
print_rq(&rq);
stud_rq_destroy(&rq); // This triggers your double free!
}
// Crash line 201 in your log
void test_rq_prepend() {
struct run_queue rq = {NULL, 0, 0};
printf("add tasks 1-4\n");
stud_rq_enqueue(&rq, stud_task_create(2, READY));
// Line 201: Prepending causes your segfault here.
stud_rq_prepend(&rq, stud_task_create(1, READY));
}
#endif // DOUBLY_LINKED_LIST_TEST_H

View file

@ -0,0 +1,166 @@
#ifndef SCHEDULER_ROUND_ROBIN_TEST_H
#define SCHEDULER_ROUND_ROBIN_TEST_H
#include <assert.h>
#include "scheduler.h"
void stud_RR_start(struct run_queue *rq, int pid);
void stud_RR_elect(struct run_queue *rq);
void stud_RR_terminate(struct run_queue *rq);
void stud_RR_clock_tick(struct run_queue *rq);
void stud_RR_wait(struct run_queue *rq);
void stud_RR_wake_up(struct run_queue *rq, int pid);
void stud_RR(struct run_queue* rq, enum events event, int pid);
// Mock implementation of the grader's verifier
bool rq_eq(struct run_queue *sol, struct run_queue *stu) {
if (sol->n_tasks != stu->n_tasks) return false;
if (sol->n_tasks == 0) return true;
struct task *c1 = sol->head;
struct task *c2 = stu->head;
int pos = 0;
do {
if (c1->pid != c2->pid || c1->state != c2->state) {
fprintf(stderr, "Task (%d, %s) error at position %d\n",
c2->pid, c2->state == RUNNING ? "running" : "other", pos);
return false;
}
c1 = c1->next;
c2 = c2->next;
pos++;
} while (c1 != sol->head && c2 != stu->head);
return true;
}
// Crash line 73 in your log
void test_RR_start() {
struct run_queue stu = {NULL, 0, 0};
struct run_queue sol = {NULL, 0, 0}; // Mock expected state
// Manually build expected solution queue to compare against
stud_rq_enqueue(&sol, stud_task_create(1, RUNNING));
stud_rq_enqueue(&sol, stud_task_create(2, READY));
stud_rq_enqueue(&sol, stud_task_create(3, READY));
printf("add task 1\n");
stud_RR_start(&stu, 1);
printf("add task 2\n");
stud_RR_start(&stu, 2);
printf("add task 3\n");
stud_RR_start(&stu, 3);
printf("add task 1 again\n");
stud_RR_start(&stu, 1);
print_rq(&stu);
// Line 73
assert(rq_eq(&sol, &stu));
}
// Helper to prepopulate a specific queue state for testing the crash logs
void prepopulate_queue(struct run_queue *rq) {
stud_rq_enqueue(rq, stud_task_create(1, RUNNING));
stud_rq_enqueue(rq, stud_task_create(2, TERMINATED));
stud_rq_enqueue(rq, stud_task_create(3, READY));
stud_rq_enqueue(rq, stud_task_create(4, TERMINATED));
stud_rq_enqueue(rq, stud_task_create(8, READY));
stud_rq_enqueue(rq, stud_task_create(14, BLOCKED));
}
// Crash line 109 in your log
void test_RR_elect_running() {
struct run_queue rq = {NULL, 0, 0};
prepopulate_queue(&rq);
print_rq(&rq);
printf("electing new task...\n");
// Line 109
stud_RR_elect(&rq);
}
// Crash line 127 in your log
void test_RR_elect_blocked() {
struct run_queue rq = {NULL, 0, 0};
prepopulate_queue(&rq);
rq.head->state = BLOCKED; // Change 1 to blocked
print_rq(&rq);
printf("electing new task...\n");
// Line 127
stud_RR_elect(&rq);
}
// Crash line 148 in your log
void test_RR_terminate() {
struct run_queue rq = {NULL, 0, 0};
prepopulate_queue(&rq);
print_rq(&rq);
printf("task terminating...\n");
// Line 148
stud_RR_terminate(&rq);
}
// Crash line 169 in your log
void test_RR_wait() {
struct run_queue rq = {NULL, 0, 0};
prepopulate_queue(&rq);
print_rq(&rq);
printf("task is waiting...\n");
// Line 169
stud_RR_wait(&rq);
}
// Crash line 190 in your log
void test_RR_wake_up() {
struct run_queue rq = {NULL, 0, 0};
prepopulate_queue(&rq);
print_rq(&rq);
printf("task 14 waking up...\n");
// Line 190
stud_RR_wake_up(&rq, 14);
}
// Crash line 216 in your log
void test_RR_clock_tick() {
struct run_queue stu = {NULL, 0, 0};
prepopulate_queue(&stu);
print_rq(&stu);
for(int i=0; i<10; i++) {
printf("running clock tick...\n");
stud_RR_clock_tick(&stu);
}
print_rq(&stu);
struct run_queue sol = {NULL, 0, 0};
// Expected solution queue state omitted for brevity
// Line 216
// assert(rq_eq(&sol, &stu));
}
// Crash line 263 in your log
void test_RR_scripted_1() {
struct run_queue stu = {NULL, 0, 0};
prepopulate_queue(&stu);
print_rq(&stu);
for(int i=0; i<5; i++) {
printf("running clock tick...\n");
stud_RR_clock_tick(&stu);
}
print_rq(&stu);
printf("task is waiting...\n");
// Line 263
stud_RR(&stu, wait, 0);
}
#endif // SCHEDULER_ROUND_ROBIN_TEST_H

61
tests.c Normal file
View file

@ -0,0 +1,61 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <execinfo.h>
#include <unistd.h>
#include "scheduler.h"
#include "doubly_linked_list_test.h"
#include "scheduler_round_robin_test.h"
// Replicates the crash handler from tests.c:211
void segv_handler(int sig) {
void *array[10];
size_t size;
fprintf(stderr, "\n=== Caught signal %d (Segmentation fault) ===\n", sig);
size = backtrace(array, 10);
backtrace_symbols_fd(array, size, STDERR_FILENO);
fprintf(stderr, "exit()/exec() detected (test did not return to harness)\n");
exit(1);
}
// Replicates the test routing from tests.c:146
void run_test_and_checks(int suite, const char *test_name) {
if (suite == 0) {
if (strcmp(test_name, "empty") == 0) test_rq_empty();
else if (strcmp(test_name, "head") == 0) test_rq_head();
else if (strcmp(test_name, "tail") == 0) test_rq_tail();
else if (strcmp(test_name, "enqueue") == 0) test_rq_enqueue();
else if (strcmp(test_name, "prepend") == 0) test_rq_prepend();
else if (strcmp(test_name, "find") == 0) test_rq_find();
else if (strcmp(test_name, "length") == 0) test_rq_length();
else if (strcmp(test_name, "destroy") == 0) test_rq_destroy();
} else if (suite == 3) {
if (strcmp(test_name, "start") == 0) test_RR_start();
else if (strcmp(test_name, "clock_tick") == 0) test_RR_clock_tick();
else if (strcmp(test_name, "elect_blocked") == 0) test_RR_elect_blocked();
else if (strcmp(test_name, "elect_running") == 0) test_RR_elect_running();
else if (strcmp(test_name, "terminate") == 0) test_RR_terminate();
else if (strcmp(test_name, "wait") == 0) test_RR_wait();
else if (strcmp(test_name, "wake_up") == 0) test_RR_wake_up();
else if (strcmp(test_name, "scripted_1") == 0) test_RR_scripted_1();
}
printf("Test passed!\n");
}
// Replicates tests.c:409
int main(int argc, char **argv) {
signal(SIGSEGV, segv_handler);
signal(SIGABRT, segv_handler);
if (argc < 3) {
fprintf(stderr, "Usage: ./vpl_execution <suite_id> <test_name>\n");
return 1;
}
int suite = atoi(argv[1]);
const char *test_name = argv[2];
run_test_and_checks(suite, test_name);
return 0;
}