Browse Source

Add more exercises

master
Riyyi 1 week ago
parent
commit
ec77cf9a1d
  1. 7
      README.org
  2. 30
      src/9-1-snek-objects/main.c
  3. 13
      src/9-1-snek-objects/snekobject.h
  4. 40
      src/9-2-integer/main.c
  5. 11
      src/9-2-integer/snekobject.c
  6. 14
      src/9-2-integer/snekobject.h
  7. 45
      src/9-3-float/main.c
  8. 24
      src/9-3-float/snekobject.c
  9. 17
      src/9-3-float/snekobject.h
  10. 41
      src/9-4-string/main.c
  11. 46
      src/9-4-string/snekobject.c
  12. 20
      src/9-4-string/snekobject.h
  13. 81
      src/9-5-vector3/main.c
  14. 69
      src/9-5-vector3/snekobject.c
  15. 31
      src/9-5-vector3/snekobject.h
  16. 6
      src/munit.h

7
README.org

@ -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:

30
src/9-1-snek-objects/main.c

@ -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
src/9-1-snek-objects/snekobject.h

@ -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
src/9-2-integer/main.c

@ -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
src/9-2-integer/snekobject.c

@ -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
src/9-2-integer/snekobject.h

@ -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
src/9-3-float/main.c

@ -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
src/9-3-float/snekobject.c

@ -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
src/9-3-float/snekobject.h

@ -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
src/9-4-string/main.c

@ -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
src/9-4-string/snekobject.c

@ -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
src/9-4-string/snekobject.h

@ -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
src/9-5-vector3/main.c

@ -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
src/9-5-vector3/snekobject.c

@ -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
src/9-5-vector3/snekobject.h

@ -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
src/munit.h

@ -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)

Loading…
Cancel
Save