Add more exercises
This commit is contained in:
+3
-4
@@ -8,6 +8,9 @@ Completed course from
|
||||
|
||||
The exercises from the course have been worked out in this repo.
|
||||
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,
|
||||
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
|
||||
conflict on macOS
|
||||
|
||||
The first the 3 chapters of the course can be done interactively on the website.
|
||||
|
||||
[[./bootdev-c.png]]
|
||||
|
||||
** Build instructions
|
||||
|
||||
Compiling and running all the tests can be done with the following commands:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -105,8 +105,14 @@
|
||||
#define munit_assert_ptr_not_equal(A, B, MSG) \
|
||||
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
|
||||
#define assert_ptr_not_null(PTR, MSG) munit_assert_not_null(PTR, MSG)
|
||||
|
||||
#undef assert_ptr_equal
|
||||
#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)
|
||||
|
||||
Reference in New Issue
Block a user