Improve CMake structure
This commit is contained in:
+2
-5
@@ -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,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);
|
||||||
|
}
|
||||||
@@ -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,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);
|
||||||
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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,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);
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#include "http.h"
|
|
||||||
|
|
||||||
char* http_to_str(http_error_code_t code)
|
|
||||||
{
|
|
||||||
// ?
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 }
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
void printMessageOne();
|
||||||
|
void printMessageTwo();
|
||||||
|
void printMessageThree();
|
||||||
|
void printStackPointerDiff();
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
char* get_full_greeting(char* greeting, char* name, int size);
|
||||||
@@ -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
@@ -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)
|
||||||
Reference in New Issue
Block a user