Add more exercises

This commit is contained in:
Riyyi
2025-09-01 14:43:45 +02:00
parent 8d203036f7
commit ec77cf9a1d
16 changed files with 491 additions and 4 deletions
+3 -4
View File
@@ -8,6 +8,9 @@ Completed course from
The exercises from the course have been worked out in this repo. The exercises from the course have been worked out in this repo.
This is my way of having the "certificate" for free. This is my way of having the "certificate" for free.
The first the 3 chapters of the course can be done interactively on the website.
[[./bootdev-c.png]]
If you're reading this with the intention of completing the exercises yourself, If you're reading this with the intention of completing the exercises yourself,
just remove the directories from the =src= directory and recreate the directory just remove the directories from the =src= directory and recreate the directory
@@ -21,10 +24,6 @@ Note:
- In chapter 8, I renamed ~stack_t~ to ~my_stack_t~ due to a =std= naming - In chapter 8, I renamed ~stack_t~ to ~my_stack_t~ due to a =std= naming
conflict on macOS conflict on macOS
The first the 3 chapters of the course can be done interactively on the website.
[[./bootdev-c.png]]
** Build instructions ** Build instructions
Compiling and running all the tests can be done with the following commands: Compiling and running all the tests can be done with the following commands:
+30
View File
@@ -0,0 +1,30 @@
#include <stdlib.h>
#include "munit.h"
#include "snekobject.h"
munit_case(RUN, test_integer_constant, {
assert_int(INTEGER, ==, 0, "INTEGER is defined as 0");
});
munit_case(RUN, test_integer_obj, {
snek_object_t *obj = malloc(sizeof(snek_object_t));
obj->kind = INTEGER;
obj->data.v_int = 0;
assert_int(obj->kind, ==, INTEGER, "must be INTEGER type");
assert_int(obj->data.v_int, ==, 0, "must equal zero");
free(obj);
});
int main() {
MunitTest tests[] = {
munit_test("/integer_constant", test_integer_constant),
munit_test("/integer_obj", test_integer_obj),
munit_null_test,
};
MunitSuite suite = munit_suite("object-integer-def", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+13
View File
@@ -0,0 +1,13 @@
typedef enum SnekObjectKind {
INTEGER,
} snek_object_kind_t;
typedef union SnekObjectData {
int v_int;
} snek_object_data_t;
typedef struct SnekObject {
snek_object_kind_t kind;
snek_object_data_t data;
} snek_object_t;
+40
View File
@@ -0,0 +1,40 @@
#include "munit.h"
#include "snekobject.h"
munit_case(RUN, test_positive, {
snek_object_t *int_object = new_snek_integer(42);
assert_int(int_object->data.v_int, ==, 42, "must allow positive numbers");
free(int_object);
});
munit_case(RUN, test_zero, {
snek_object_t *int_object = new_snek_integer(0);
assert_int(int_object->kind, ==, INTEGER, "must be INTEGER type");
assert_int(int_object->data.v_int, ==, 0, "must equal zero");
free(int_object);
});
munit_case(SUBMIT, test_negative, {
snek_object_t *int_object = new_snek_integer(-5);
assert_int(int_object->kind, ==, INTEGER, "must be INTEGER type");
assert_int(int_object->data.v_int, ==, -5, "must allow negative numbers");
free(int_object);
});
int main() {
MunitTest tests[] = {
munit_test("/positive", test_positive),
munit_test("/zero", test_zero),
munit_test("/negative", test_negative),
munit_null_test,
};
MunitSuite suite = munit_suite("object-integer", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+11
View File
@@ -0,0 +1,11 @@
#include <stdlib.h>
#include "snekobject.h"
snek_object_t *new_snek_integer(int value) {
snek_object_t *number = (snek_object_t *)malloc(sizeof(snek_object_t));
if (number == NULL) return NULL;
number->kind = INTEGER;
number->data.v_int = value;
return number;
}
+14
View File
@@ -0,0 +1,14 @@
typedef enum SnekObjectKind {
INTEGER,
} snek_object_kind_t;
typedef union SnekObjectData {
int v_int;
} snek_object_data_t;
typedef struct SnekObject {
snek_object_kind_t kind;
snek_object_data_t data;
} snek_object_t;
snek_object_t *new_snek_integer(int value);
+45
View File
@@ -0,0 +1,45 @@
#include <stdlib.h>
#include "munit.h"
#include "snekobject.h"
munit_case(RUN, test_positive, {
snek_object_t *obj = new_snek_float(42);
assert_float(obj->data.v_float, ==, 42, "Must accept positive values");
free(obj);
// assert(boot_all_freed());
});
munit_case(SUBMIT, test_zero, {
snek_object_t *obj = new_snek_float(0.0);
assert_float(obj->kind, ==, FLOAT, "Must set type to FLOAT");
assert_float(obj->data.v_float, ==, 0.0, "Must accept 0.0");
free(obj);
// assert(boot_all_freed());
});
munit_case(SUBMIT, test_negative, {
snek_object_t *obj = new_snek_float(-5.0);
assert_float(obj->kind, ==, FLOAT, "Must set type to FLOAT");
assert_float(obj->data.v_float, ==, -5.0, "Must accept negative numbers");
free(obj);
// assert(boot_all_freed());
});
int main() {
MunitTest tests[] = {
munit_test("/positive", test_positive),
munit_test("/zero", test_zero),
munit_test("/negative", test_negative),
munit_null_test,
};
MunitSuite suite = munit_suite("object-float", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+24
View File
@@ -0,0 +1,24 @@
#include <stdlib.h>
#include "snekobject.h"
snek_object_t *new_snek_float(float value) {
snek_object_t *obj = (snek_object_t *)malloc(sizeof(snek_object_t));
if (obj == NULL) return NULL;
obj->kind = FLOAT;
obj->data.v_float = value;
return obj;
}
// don't touch below this line
snek_object_t *new_snek_integer(int value) {
snek_object_t *obj = malloc(sizeof(snek_object_t));
if (obj == NULL) {
return NULL;
}
obj->kind = INTEGER;
obj->data.v_int = value;
return obj;
}
+17
View File
@@ -0,0 +1,17 @@
typedef enum SnekObjectKind {
INTEGER,
FLOAT,
} snek_object_kind_t;
typedef union SnekObjectData {
int v_int;
float v_float;
} snek_object_data_t;
typedef struct SnekObject {
snek_object_kind_t kind;
snek_object_data_t data;
} snek_object_t;
snek_object_t *new_snek_integer(int value);
snek_object_t *new_snek_float(float value);
+41
View File
@@ -0,0 +1,41 @@
#include <stdlib.h>
#include "munit.h"
#include "snekobject.h"
munit_case(RUN, test_str_copied, {
char *input = "Hello, World!";
snek_object_t *obj = new_snek_string(input);
assert_int(obj->kind, ==, STRING, "Must be a string!");
// Should not have pointers be the same, otherwise we didn't copy the value.
assert_ptr_not_equal(
obj->data.v_string, input, "You need to copy the string."
);
// But should have the same data!
// This way the object can free it's own memory later.
assert_string_equal(
obj->data.v_string, input, "Should copy string correctly"
);
// Should allocate memory for the string with null terminator.
// assert_int_equal(boot_alloc_size(), 22, "Must allocate memory for string");
// Free the string, and then free the object.
free(obj->data.v_string);
free(obj);
// assert(boot_all_freed());
});
int main() {
MunitTest tests[] = {
munit_test("/copies_value", test_str_copied),
munit_null_test,
};
MunitSuite suite = munit_suite("object-string", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+46
View File
@@ -0,0 +1,46 @@
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "snekobject.h"
snek_object_t *new_snek_string(char *value) {
snek_object_t *obj = malloc(sizeof(snek_object_t));
if (obj == NULL) return NULL;
size_t size = strlen(value);
char *str = (char *)malloc(sizeof(char) * size + 1);
if (str == NULL) {
free(obj);
return NULL;
}
strcpy(str, value);
obj->kind = STRING;
obj->data.v_string = str;
return obj;
}
// don't touch below this line
snek_object_t *new_snek_integer(int value) {
snek_object_t *obj = malloc(sizeof(snek_object_t));
if (obj == NULL) {
return NULL;
}
obj->kind = INTEGER;
obj->data.v_int = value;
return obj;
}
snek_object_t *new_snek_float(float value) {
snek_object_t *obj = malloc(sizeof(snek_object_t));
if (obj == NULL) {
return NULL;
}
obj->kind = FLOAT;
obj->data.v_float = value;
return obj;
}
+20
View File
@@ -0,0 +1,20 @@
typedef enum SnekObjectKind {
INTEGER,
FLOAT,
STRING,
} snek_object_kind_t;
typedef union SnekObjectData {
int v_int;
float v_float;
char* v_string;
} snek_object_data_t;
typedef struct SnekObject {
snek_object_kind_t kind;
snek_object_data_t data;
} snek_object_t;
snek_object_t *new_snek_integer(int value);
snek_object_t *new_snek_float(float value);
snek_object_t *new_snek_string(char *value);
+81
View File
@@ -0,0 +1,81 @@
#include <stdlib.h>
#include "munit.h"
#include "snekobject.h"
munit_case(RUN, test_returns_null, {
snek_object_t *vec = new_snek_vector3(NULL, NULL, NULL);
assert_null(vec, "Should return null when input is null");
// assert(boot_all_freed());
});
munit_case(RUN, test_vec_multiple_objects, {
snek_object_t *x = new_snek_integer(1);
snek_object_t *y = new_snek_integer(2);
snek_object_t *z = new_snek_integer(3);
snek_object_t *vec = new_snek_vector3(x, y, z);
assert_ptr_not_null(vec, "should allocate a new object");
// Vectors should not copy objects, they get the reference to the objects.
assert_ptr(x, ==, vec->data.v_vector3.x, "should reference x");
assert_ptr(y, ==, vec->data.v_vector3.y, "should reference y");
assert_ptr(z, ==, vec->data.v_vector3.z, "should reference z");
// Assert we have integer values correct
assert_int(vec->data.v_vector3.x->data.v_int, ==, 1, "should have correct x");
assert_int(vec->data.v_vector3.y->data.v_int, ==, 2, "should have correct y");
assert_int(vec->data.v_vector3.z->data.v_int, ==, 3, "should have correct z");
// Free all of our objects.
free(x);
free(y);
free(z);
free(vec);
// assert(boot_all_freed());
});
munit_case(SUBMIT, test_vec_same_object, {
snek_object_t *i = new_snek_integer(1);
snek_object_t *vec = new_snek_vector3(i, i, i);
assert_ptr_not_null(vec, "should allocate a new object");
// Vectors should not copy objects, they get the reference to the objects.
assert_ptr(i, ==, vec->data.v_vector3.x, "should reference x");
assert_ptr(i, ==, vec->data.v_vector3.y, "should reference y");
assert_ptr(i, ==, vec->data.v_vector3.z, "should reference z");
// Assert we have integer values correct
assert_int(vec->data.v_vector3.x->data.v_int, ==, 1, "should have correct x");
assert_int(vec->data.v_vector3.y->data.v_int, ==, 1, "should have correct y");
assert_int(vec->data.v_vector3.z->data.v_int, ==, 1, "should have correct z");
i->data.v_int = 2;
// Assert we have integer values correct, after update
assert_int(vec->data.v_vector3.x->data.v_int, ==, 2, "should have correct x");
assert_int(vec->data.v_vector3.y->data.v_int, ==, 2, "should have correct y");
assert_int(vec->data.v_vector3.z->data.v_int, ==, 2, "should have correct z");
// Free all of our objects.
free(i);
free(vec);
// assert(boot_all_freed());
});
int main() {
MunitTest tests[] = {
munit_test("/returns_null", test_returns_null),
munit_test("/multiple_objects", test_vec_multiple_objects),
munit_test("/same_object", test_vec_same_object),
munit_null_test,
};
MunitSuite suite = munit_suite("object-vector", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+69
View File
@@ -0,0 +1,69 @@
#include <stdlib.h>
#include <string.h>
#include "snekobject.h"
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z)
{
if (x == NULL || y == NULL || z == NULL) return NULL;
snek_object_t *obj = (snek_object_t *)malloc(sizeof(snek_object_t));
if (obj == NULL) return NULL;
snek_vector_t *vec = (snek_vector_t *)malloc(sizeof(snek_vector_t));
if (vec == NULL) {
free(obj);
return NULL;
}
vec->x = x;
vec->y = y;
vec->z = z;
obj->kind = VECTOR3;
obj->data.v_vector3 = *vec;
return obj;
}
// don't touch below this line
snek_object_t *new_snek_integer(int value) {
snek_object_t *obj = malloc(sizeof(snek_object_t));
if (obj == NULL) {
return NULL;
}
obj->kind = INTEGER;
obj->data.v_int = value;
return obj;
}
snek_object_t *new_snek_float(float value) {
snek_object_t *obj = malloc(sizeof(snek_object_t));
if (obj == NULL) {
return NULL;
}
obj->kind = FLOAT;
obj->data.v_float = value;
return obj;
}
snek_object_t *new_snek_string(char *value) {
snek_object_t *obj = malloc(sizeof(snek_object_t));
if (obj == NULL) {
return NULL;
}
int len = strlen(value);
char *dst = malloc(len + 1);
if (dst == NULL) {
free(obj);
return NULL;
}
strcpy(dst, value);
obj->kind = STRING;
obj->data.v_string = dst;
return obj;
}
+31
View File
@@ -0,0 +1,31 @@
typedef struct SnekObject snek_object_t;
typedef enum SnekObjectKind {
INTEGER,
FLOAT,
STRING,
VECTOR3,
} snek_object_kind_t;
typedef struct SnekVector {
snek_object_t *x;
snek_object_t *y;
snek_object_t *z;
} snek_vector_t;
typedef union SnekObjectData {
int v_int;
float v_float;
char* v_string;
snek_vector_t v_vector3;
} snek_object_data_t;
typedef struct SnekObject {
snek_object_kind_t kind;
snek_object_data_t data;
} snek_object_t;
snek_object_t *new_snek_integer(int value);
snek_object_t *new_snek_float(float value);
snek_object_t *new_snek_string(char *value);
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z);
+6
View File
@@ -105,8 +105,14 @@
#define munit_assert_ptr_not_equal(A, B, MSG) \ #define munit_assert_ptr_not_equal(A, B, MSG) \
munit_assert_ptr(A, !=, B) munit_assert_ptr(A, !=, B)
#undef assert_ptr
#define assert_ptr(A, OP, B, MSG) munit_assert_ptr(A, OP, B)
#undef assert_ptr_not_null #undef assert_ptr_not_null
#define assert_ptr_not_null(PTR, MSG) munit_assert_not_null(PTR, MSG) #define assert_ptr_not_null(PTR, MSG) munit_assert_not_null(PTR, MSG)
#undef assert_ptr_equal #undef assert_ptr_equal
#define assert_ptr_equal(A, B, MSG) munit_assert_ptr_equal(A, B) #define assert_ptr_equal(A, B, MSG) munit_assert_ptr_equal(A, B)
#undef assert_ptr_not_equal
#define assert_ptr_not_equal(A, B, MSG) munit_assert_ptr_not_equal(A, B, MSG)