Browse Source

Improve CMake structure

master
Riyyi 2 weeks ago
parent
commit
215c1849f1
  1. 7
      CMakeLists.txt
  2. 0
      src/4-1-enums/color.h
  3. 28
      src/4-1-enums/main.c
  4. 27
      src/4-1/main.c
  5. 0
      src/4-2-non-default-values/color.h
  6. 28
      src/4-2-non-default-values/main.c
  7. 27
      src/4-2/main.c
  8. 27
      src/4-3-switch-case/http.c
  9. 0
      src/4-3-switch-case/http.h
  10. 28
      src/4-3-switch-case/main.c
  11. 7
      src/4-3/http.c
  12. 27
      src/4-3/main.c
  13. 23
      src/4-4-sizeof-enum/main.c
  14. 34
      src/5-1-union/exercise.c
  15. 20
      src/5-1-union/exercise.h
  16. 51
      src/5-1-union/main.c
  17. 24
      src/5-2-memory-layout/main.c
  18. 42
      src/5-3-5-4-union-size/main.c
  19. 10
      src/5-5-helper-fields/exercise.h
  20. 53
      src/5-5-helper-fields/main.c
  21. 4
      src/6-1-the-stack/exercise.h
  22. 48
      src/6-1-the-stack/main.c
  23. 9
      src/6-2-why-a-stack/main.c
  24. 16
      src/6-3-stack-overflow/main.c
  25. 25
      src/6-4-pointers-to-the-stack/main.c
  26. 10
      src/6-5-the-heap/exercise.c
  27. 1
      src/6-5-the-heap/exercise.h
  28. 44
      src/6-5-the-heap/main.c
  29. 57
      src/munit.h

7
CMakeLists.txt

@ -17,9 +17,6 @@ file(GLOB_RECURSE LIBRARY_SOURCES "vendor/munit/*.c")
add_library(munit ${LIBRARY_SOURCES}) add_library(munit ${LIBRARY_SOURCES})
target_include_directories(munit PUBLIC
"vendor/munit")
# ------------------------------------------ # ------------------------------------------
# Executable # Executable
@ -42,8 +39,8 @@ foreach(LESSON ${LESSONS})
add_executable(${EXE_NAME} ${LESSON_SOURCES}) add_executable(${EXE_NAME} ${LESSON_SOURCES})
target_include_directories(${EXE_NAME} PRIVATE target_include_directories(${EXE_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/${LESSON} ${CMAKE_CURRENT_SOURCE_DIR}/src
"vendor/munit") ${CMAKE_CURRENT_SOURCE_DIR}/${LESSON})
target_link_libraries(${EXE_NAME} munit) target_link_libraries(${EXE_NAME} munit)
# Collect all the directory names for the run target # Collect all the directory names for the run target

0
src/4-1/color.h → src/4-1-enums/color.h

28
src/4-1-enums/main.c

@ -0,0 +1,28 @@
#include "munit.h"
#include "color.h"
munit_case(RUN, test_color_enum1, {
assert_int(RED, ==, 0, "RED is defined as 0");
assert_int(GREEN, ==, 1, "GREEN is defined as 1");
assert_int(BLUE, ==, 2, "BLUE is defined as 2");
});
munit_case(SUBMIT, test_color_enum2, {
assert_int(RED, !=, 4, "RED is not defined as 4");
assert_int(GREEN, !=, 2, "GREEN is not defined as 2");
assert_int(BLUE, !=, 0, "BLUE is not defined as 0");
});
int main()
{
MunitTest tests[] = {
munit_test("/are_defined", test_color_enum1),
munit_test("/are_defined_correctly", test_color_enum2),
munit_null_test,
};
MunitSuite suite = munit_suite("colors", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

27
src/4-1/main.c

@ -1,27 +0,0 @@
#include "munit.h"
#include "color.h"
munit_case(RUN, test_color_enum1, {
assert_int(RED, ==, 0, "RED is defined as 0");
assert_int(GREEN, ==, 1, "GREEN is defined as 1");
assert_int(BLUE, ==, 2, "BLUE is defined as 2");
});
munit_case(SUBMIT, test_color_enum2, {
assert_int(RED, !=, 4, "RED is not defined as 4");
assert_int(GREEN, !=, 2, "GREEN is not defined as 2");
assert_int(BLUE, !=, 0, "BLUE is not defined as 0");
});
int main() {
MunitTest tests[] = {
munit_test("/are_defined", test_color_enum1),
munit_test("/are_defined_correctly", test_color_enum2),
munit_null_test,
};
MunitSuite suite = munit_suite("colors", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

0
src/4-2/color.h → src/4-2-non-default-values/color.h

28
src/4-2-non-default-values/main.c

@ -0,0 +1,28 @@
#include "munit.h"
#include "color.h"
munit_case(RUN, test_colors_defined, {
assert_int(RED, ==, 55, "RED is defined as 55 (nvim green!)");
assert_int(GREEN, ==, 176, "GREEN is defined as 176 (nvim green!)");
assert_int(BLUE, ==, 38, "BLUE is defined as 38 (nvim green!)");
});
munit_case(SUBMIT, test_colors_defined_correctly, {
assert_int(RED, !=, 0, "RED is not defined as 0 (vsc*de blue!)");
assert_int(GREEN, !=, 120, "GREEN is not defined as 120 (vsc*de blue!)");
assert_int(BLUE, !=, 215, "BLUE is not defined as 215 (vsc*de blue!)");
});
int main()
{
MunitTest tests[] = {
munit_test("/defined", test_colors_defined),
munit_test("/defined_vscode", test_colors_defined_correctly),
munit_null_test,
};
MunitSuite suite = munit_suite("colors", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

27
src/4-2/main.c

@ -1,27 +0,0 @@
#include "munit.h"
#include "color.h"
munit_case(RUN, test_colors_defined, {
assert_int(RED, ==, 55, "RED is defined as 55 (nvim green!)");
assert_int(GREEN, ==, 176, "GREEN is defined as 176 (nvim green!)");
assert_int(BLUE, ==, 38, "BLUE is defined as 38 (nvim green!)");
});
munit_case(SUBMIT, test_colors_defined_correctly, {
assert_int(RED, !=, 0, "RED is not defined as 0 (vsc*de blue!)");
assert_int(GREEN, !=, 120, "GREEN is not defined as 120 (vsc*de blue!)");
assert_int(BLUE, !=, 215, "BLUE is not defined as 215 (vsc*de blue!)");
});
int main() {
MunitTest tests[] = {
munit_test("/defined", test_colors_defined),
munit_test("/defined_vscode", test_colors_defined_correctly),
munit_null_test,
};
MunitSuite suite = munit_suite("colors", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

27
src/4-3-switch-case/http.c

@ -0,0 +1,27 @@
#include "http.h"
char* http_to_str(http_error_code_t code)
{
switch (code) {
case HTTP_BAD_REQUEST:
return "400 Bad Request";
break;
case HTTP_UNAUTHORIZED:
return "401 Unauthorized";
break;
case HTTP_NOT_FOUND:
return "404 Not Found";
break;
case HTTP_TEAPOT:
return "418 I AM A TEAPOT!";
break;
case HTTP_INTERNAL_SERVER_ERROR:
return "500 Internal Server Error";
break;
default:
return "Unknown HTTP status code";
break;
};
return 0;
}

0
src/4-3/http.h → src/4-3-switch-case/http.h

28
src/4-3-switch-case/main.c

@ -0,0 +1,28 @@
#include "munit.h"
#include "http.h"
munit_case(RUN, test_switch_enum, {
assert_string_equal(http_to_str(HTTP_BAD_REQUEST), "400 Bad Request", "");
assert_string_equal(http_to_str(HTTP_UNAUTHORIZED), "401 Unauthorized", "");
assert_string_equal(http_to_str(HTTP_NOT_FOUND), "404 Not Found", "");
assert_string_equal(http_to_str(HTTP_TEAPOT), "418 I AM A TEAPOT!", "");
assert_string_equal(http_to_str(HTTP_INTERNAL_SERVER_ERROR), "500 Internal Server Error", "");
});
munit_case(SUBMIT, test_switch_enum_default, {
assert_string_equal(http_to_str((http_error_code_t)999), "Unknown HTTP status code", "");
});
int main()
{
MunitTest tests[] = {
munit_test("/switch_enum", test_switch_enum),
munit_test("/switch_enum_default", test_switch_enum_default),
munit_null_test,
};
MunitSuite suite = munit_suite("http", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

7
src/4-3/http.c

@ -1,7 +0,0 @@
#include "http.h"
char* http_to_str(http_error_code_t code)
{
// ?
return 0;
}

27
src/4-3/main.c

@ -1,27 +0,0 @@
#include "munit.h"
#include "http.h"
munit_case(RUN, test_switch_enum, {
assert_string_equal(http_to_str(HTTP_BAD_REQUEST), "400 Bad Request", "");
assert_string_equal(http_to_str(HTTP_UNAUTHORIZED), "401 Unauthorized", "");
assert_string_equal(http_to_str(HTTP_NOT_FOUND), "404 Not Found", "");
assert_string_equal(http_to_str(HTTP_TEAPOT), "418 I AM A TEAPOT!", "");
assert_string_equal(http_to_str(HTTP_INTERNAL_SERVER_ERROR), "500 Internal Server Error", "");
});
munit_case(SUBMIT, test_switch_enum_default, {
assert_string_equal(http_to_str((http_error_code_t)999), "Unknown HTTP status code", "");
});
int main() {
MunitTest tests[] = {
munit_test("/switch_enum", test_switch_enum),
munit_test("/switch_enum_default", test_switch_enum_default),
munit_null_test,
};
MunitSuite suite = munit_suite("http", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

23
src/4-4-sizeof-enum/main.c

@ -0,0 +1,23 @@
#include <stdio.h>
typedef enum {
BIG = 123412341234,
BIGGER,
BIGGEST,
} BigNumbers;
typedef enum {
HTTP_BAD_REQUEST = 400,
HTTP_UNAUTHORIZED = 401,
HTTP_NOT_FOUND = 404,
HTTP_I_AM_A_TEAPOT = 418,
HTTP_INTERNAL_SERVER_ERROR = 500
} HttpErrorCode;
int main()
{
printf("The size of BigNumbers is %zu bytes\n", sizeof(BigNumbers));
printf("The size of HttpErrorCode is %zu bytes\n", sizeof(HttpErrorCode));
return 0;
}

34
src/5-1-union/exercise.c

@ -0,0 +1,34 @@
#include <stdio.h>
#include "exercise.h"
void format_object(snek_object_t obj, char* buffer)
{
switch (obj.kind) {
case INTEGER:
sprintf(buffer, "int:%d", obj.data.v_int);
break;
case STRING:
sprintf(buffer, "string:%s", obj.data.v_string);
break;
};
}
// don't touch below this line'
snek_object_t new_integer(int i)
{
return (snek_object_t) {
.kind = INTEGER,
.data = { .v_int = i }
};
}
snek_object_t new_string(char* str)
{
// NOTE: We will learn how to copy this data later.
return (snek_object_t) {
.kind = STRING,
.data = { .v_string = str }
};
}

20
src/5-1-union/exercise.h

@ -0,0 +1,20 @@
typedef enum SnekObjectKind {
INTEGER,
STRING,
} snek_object_kind_t;
// don't touch below this line'
typedef union SnekObjectData {
int v_int;
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_integer(int);
snek_object_t new_string(char* str);
void format_object(snek_object_t obj, char* buffer);

51
src/5-1-union/main.c

@ -0,0 +1,51 @@
#include <stdio.h>
#include "exercise.h"
#include "munit.h"
munit_case(RUN, test_formats_int1, {
char buffer[100];
snek_object_t i = new_integer(5);
format_object(i, buffer);
assert_string_equal("int:5", buffer, "formats INTEGER");
});
munit_case(RUN, test_formats_string1, {
char buffer[100];
snek_object_t s = new_string("Hello!");
format_object(s, buffer);
assert_string_equal("string:Hello!", buffer, "formats STRING");
});
munit_case(SUBMIT, test_formats_int2, {
char buffer[100];
snek_object_t i = new_integer(2014);
format_object(i, buffer);
assert_string_equal("int:2014", buffer, "formats INTEGER");
});
munit_case(SUBMIT, test_formats_string2, {
char buffer[100];
snek_object_t s = new_string("nvim btw");
format_object(s, buffer);
assert_string_equal("string:nvim btw", buffer, "formats STRING");
});
int main()
{
MunitTest tests[] = {
munit_test("/integer", test_formats_int1),
munit_test("/string", test_formats_string1),
munit_test("/integer_nvim", test_formats_int2),
munit_test("/string_nvim", test_formats_string2),
munit_null_test,
};
MunitSuite suite = munit_suite("format", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

24
src/5-2-memory-layout/main.c

@ -0,0 +1,24 @@
#include <limits.h>
#include <stdio.h>
#include "munit.h"
typedef union {
int value;
unsigned int err;
} val_or_err_t;
int main()
{
val_or_err_t lanes_score = {
.value = -420
};
printf("value (set): %d\n", lanes_score.value);
printf("err (unset): %u\n", lanes_score.err);
val_or_err_t teejs_score = {
.err = UINT_MAX
};
printf("value (unset): %d\n", teejs_score.value);
printf("err (set): %u\n", teejs_score.err);
}

42
src/5-3-5-4-union-size/main.c

@ -0,0 +1,42 @@
union SensorData {
long int temperature;
long int humidity;
long int pressure;
};
union PacketPayload {
char text[256];
unsigned char binary[256];
struct ImageData {
int width;
int height;
unsigned char data[1024];
} image;
};
union Item {
struct {
int damage;
int range;
int size;
} weapon;
struct {
int healingAmount;
int duration;
} potion;
struct {
int doorID;
} key;
};
int main()
{
// Q: How many bytes will an instance of SensorData require?
// A: 8 bytes
// Q: Which is the correct order, from least to greatest, of the memory
// requirements of the given unions?
// A: SensorData, Item, Packetpayload
}

10
src/5-5-helper-fields/exercise.h

@ -0,0 +1,10 @@
#include <stdint.h>
typedef union PacketHeader {
struct {
uint16_t src_port;
uint16_t dest_port;
uint32_t seq_num;
} tcp_header;
uint8_t raw[8];
} packet_header_t;

53
src/5-5-helper-fields/main.c

@ -0,0 +1,53 @@
#include <string.h>
#include "exercise.h"
#include "munit.h"
munit_case(RUN, test_packet_header_size, {
munit_assert_size(sizeof(packet_header_t), ==, 8, "PacketHeader union should be 8 bytes");
});
munit_case(RUN, test_tcp_header_fields, {
packet_header_t header;
header.tcp_header.src_port = 0x1234;
header.tcp_header.dest_port = 0x5678;
header.tcp_header.seq_num = 0x9ABCDEF0;
munit_assert_uint16(header.tcp_header.src_port, ==, 0x1234, "src_port should be 0x1234");
munit_assert_uint16(header.tcp_header.dest_port, ==, 0x5678, "dest_port should be 0x5678");
munit_assert_uint32(header.tcp_header.seq_num, ==, 0x9ABCDEF0, "seq_num should be 0x9ABCDEF0");
});
munit_case(SUBMIT, test_field_raw_size, {
munit_assert_size(sizeof(((packet_header_t*)0)->raw), ==, 8, "PacketHeader union should be 8 bytes");
});
munit_case(SUBMIT, test_field_to_raw_consistency, {
packet_header_t header = { 0 };
header.tcp_header.src_port = 0x1234;
header.tcp_header.dest_port = 0x5678;
header.tcp_header.seq_num = 0x9ABCDEF0;
munit_assert_uint8(header.raw[0], ==, 0x34, "[0] should be 0x34");
munit_assert_uint8(header.raw[1], ==, 0x12, "[1] should be 0x12");
munit_assert_uint8(header.raw[2], ==, 0x78, "[2] should be 0x78");
munit_assert_uint8(header.raw[3], ==, 0x56, "[3] should be 0x56");
munit_assert_uint8(header.raw[4], ==, 0xF0, "[4] should be 0xF0");
munit_assert_uint8(header.raw[5], ==, 0xDE, "[5] should be 0xDE");
munit_assert_uint8(header.raw[6], ==, 0xBC, "[6] should be 0xBC");
munit_assert_uint8(header.raw[7], ==, 0x9A, "[7] should be 0x9A");
});
int main()
{
MunitTest tests[] = {
munit_test("/test_packet_header_size", test_packet_header_size),
munit_test("/test_tcp_header_fields", test_tcp_header_fields),
munit_test("/test_field_raw_size", test_field_raw_size),
munit_test("/test_field_to_raw_consistency", test_field_to_raw_consistency),
munit_null_test,
};
MunitSuite suite = munit_suite("PacketHeader", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

4
src/6-1-the-stack/exercise.h

@ -0,0 +1,4 @@
void printMessageOne();
void printMessageTwo();
void printMessageThree();
void printStackPointerDiff();

48
src/6-1-the-stack/main.c

@ -0,0 +1,48 @@
#include "exercise.h"
#include <stdio.h>
int main()
{
printMessageOne();
printMessageTwo();
printMessageThree();
return 0;
}
void printMessageOne()
{
const char* message = "Dark mode?\n";
printStackPointerDiff();
printf("%s\n", message);
}
void printMessageTwo()
{
const char* message = "More like...\n";
printStackPointerDiff();
printf("%s\n", message);
}
void printMessageThree()
{
const char* message = "dark roast.\n";
printStackPointerDiff();
printf("%s\n", message);
}
// don't touch below this line
void printStackPointerDiff()
{
static void* last_sp = NULL;
void* current_sp;
current_sp = __builtin_frame_address(0);
long diff = (char*)last_sp - (char*)current_sp;
if (last_sp == NULL) {
last_sp = current_sp;
diff = 0;
}
printf("---------------------------------\n");
printf("Stack pointer offset: %ld bytes\n", diff);
printf("---------------------------------\n");
}

9
src/6-2-why-a-stack/main.c

@ -0,0 +1,9 @@
// Q: Generally speaking, it's more performant to store a variable's data on...?
// - Video casette
// - Ticker tape
// - The stack
// - The heap
// A: The Stack

16
src/6-3-stack-overflow/main.c

@ -0,0 +1,16 @@
#include <stdio.h>
int main()
{
const int pool_size = 1024 * 10;
char snek_pool[pool_size];
snek_pool[0] = 's';
snek_pool[1] = 'n';
snek_pool[2] = 'e';
snek_pool[3] = 'k';
snek_pool[4] = '\0';
printf("Size of pool: %d\n", pool_size);
printf("Initial string: %s\n", snek_pool);
return 0;
}

25
src/6-4-pointers-to-the-stack/main.c

@ -0,0 +1,25 @@
#include <stdio.h>
typedef struct {
int x;
int y;
} coord_t;
coord_t new_coord(int x, int y)
{
coord_t c;
c.x = x;
c.y = y;
return c;
}
int main()
{
coord_t c1 = new_coord(10, 20);
coord_t c2 = new_coord(30, 40);
coord_t c3 = new_coord(50, 60);
printf("c1: %d, %d\n", c1.x, c1.y);
printf("c2: %d, %d\n", c2.x, c2.y);
printf("c3: %d, %d\n", c3.x, c3.y);
}

10
src/6-5-the-heap/exercise.c

@ -0,0 +1,10 @@
#include "exercise.h"
#include <stdio.h>
#include <stdlib.h>
char* get_full_greeting(char* greeting, char* name, int size)
{
char full_greeting[100];
snprintf(full_greeting, 100, "%s %s", greeting, name);
return full_greeting;
}

1
src/6-5-the-heap/exercise.h

@ -0,0 +1 @@
char* get_full_greeting(char* greeting, char* name, int size);

44
src/6-5-the-heap/main.c

@ -0,0 +1,44 @@
#include "exercise.h"
#include "munit.h"
#include <stdbool.h>
#include <string.h>
// Helper function to check if a pointer is on the stack
bool is_on_stack(void* ptr)
{
void* stack_top = __builtin_frame_address(0);
uintptr_t stack_top_addr = (uintptr_t)stack_top;
uintptr_t ptr_addr = (uintptr_t)ptr;
// Check within a threshold in both directions (e.g., 1MB)
uintptr_t threshold = 1024;
return ptr_addr >= (stack_top_addr - threshold) && ptr_addr <= (stack_top_addr + threshold);
}
munit_case(RUN, test_basic_greeting, {
char* result = get_full_greeting("Hello", "Alice", 20);
munit_assert_string_equal(result, "Hello Alice", "Basic greeting should be correct");
munit_assert_false(is_on_stack(result));
free(result);
});
munit_case(SUBMIT, test_short_buffer, {
char* result = get_full_greeting("Hey", "Bob", 4);
munit_assert_string_equal(result, "Hey", "Should truncate to fit buffer");
munit_assert_false(is_on_stack(result));
free(result);
});
int main()
{
MunitTest tests[] = {
munit_test("/test_basic_greeting", test_basic_greeting),
munit_test("/test_short_buffer", test_short_buffer),
munit_null_test,
};
MunitSuite suite = munit_suite("get_full_greeting", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

57
src/munit.h

@ -0,0 +1,57 @@
#include "../vendor/munit/munit.h"
// TJ seems to have added a bunch of macros to the default munit.h,
// implement those here
// -----------------------------------------
// Test suite macros
#define munit_case(NAME, FUNCNAME, BODY) \
static MunitResult FUNCNAME(const MunitParameter params[], void* data) \
{ \
(void)params; \
(void)data; \
BODY return MUNIT_OK; \
}
#define munit_test(NAME, FN) \
{ NAME, FN, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
#define munit_null_test \
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
#define munit_suite(NAME, TESTS) \
(MunitSuite) { NAME, TESTS, NULL, 1, MUNIT_SUITE_OPTION_NONE }
// -----------------------------------------
// Overwrite assertion macros, extended with "msg" parameter
#undef assert_int
#define assert_int(A, OP, B, MSG) \
munit_assert_int(A, OP, B);
#undef assert_uint
#define assert_uint(A, OP, B, MSG) \
munit_assert_uint(A, OP, B);
#undef assert_double
#define assert_double(A, OP, B, MSG) \
munit_assert_double(A, OP, B);
#undef assert_string_equal
#define assert_string_equal(A, B, MSG) \
munit_assert_string_equal(A, B);
#undef munit_assert_size
#define munit_assert_size(A, OP, B, MSG) \
munit_assert_type(size_t, MUNIT_SIZE_MODIFIER "u", A, OP, B)
#undef munit_assert_uint8
#define munit_assert_uint8(A, OP, B, MSG) \
munit_assert_type(munit_uint8_t, PRIu8, A, OP, B)
#undef munit_assert_uint16
#define munit_assert_uint16(A, OP, B, MSG) \
munit_assert_type(munit_uint16_t, PRIu16, A, OP, B)
#undef munit_assert_uint32
#define munit_assert_uint32(A, OP, B, MSG) \
munit_assert_type(munit_uint32_t, PRIu32, A, OP, B)
Loading…
Cancel
Save