| @@ -52,14 +52,19 @@ expands to: | |||||
| }; | }; | ||||
| */ | */ | ||||
| #if defined(unix) || defined(__unix__) || defined(__unix) | |||||
| #define NULL_HANDLE "/dev/null" | |||||
| #else | |||||
| #define NULL_HANDLE "nul" | |||||
| #endif | |||||
| #define ignore_stdout \ | #define ignore_stdout \ | ||||
| if (0) \ | if (0) \ | ||||
| label(finished,__LINE__): ; \ | label(finished,__LINE__): ; \ | ||||
| else \ | else \ | ||||
| for (FILE* tmp = ftb_stdout;;) \ | |||||
| for (defer{ fclose(ftb_stdout); ftb_stdout= tmp; } ;;) \ | |||||
| for (FILE* label(fluid_let_, __LINE__) = ftb_stdout;;) \ | |||||
| for (defer{ fclose(ftb_stdout); ftb_stdout=label(fluid_let_, __LINE__) ; } ;;) \ | |||||
| if (1) { \ | if (1) { \ | ||||
| ftb_stdout = fopen("nul", "w"); \ | |||||
| ftb_stdout = fopen(NULL_HANDLE, "w"); \ | |||||
| goto label(body,__LINE__); \ | goto label(body,__LINE__); \ | ||||
| } \ | } \ | ||||
| else \ | else \ | ||||
| @@ -68,7 +73,6 @@ expands to: | |||||
| goto label(finished, __LINE__); \ | goto label(finished, __LINE__); \ | ||||
| } \ | } \ | ||||
| else label(body,__LINE__): | else label(body,__LINE__): | ||||
| /***************** | /***************** | ||||
| @@ -16,11 +16,15 @@ typedef s32 testresult; | |||||
| "\n\tgot anyways: " format "\n", \ | "\n\tgot anyways: " format "\n", \ | ||||
| __FILE__, __LINE__, (type)(value), (type)(variable)) | __FILE__, __LINE__, (type)(value), (type)(variable)) | ||||
| #define assert_equal_string(variable, value) \ | |||||
| if (!string_equal(variable, value)) { \ | |||||
| print_assert_equal_fail(&(variable), &(value), String*, "%{->Str}"); \ | |||||
| return fail; \ | |||||
| } | |||||
| #define assert_equal_string(variable, value) \ | |||||
| do { \ | |||||
| auto v1{variable}; \ | |||||
| auto v2{value}; \ | |||||
| if (!string_equal(v1, v2)) { \ | |||||
| print_assert_equal_fail(&(v1), &(v2), String*, "%{->Str}"); \ | |||||
| return fail; \ | |||||
| } \ | |||||
| } while (0) | |||||
| #define assert_equal_int(variable, value) \ | #define assert_equal_int(variable, value) \ | ||||
| if (variable != value) { \ | if (variable != value) { \ | ||||
| @@ -27,16 +27,49 @@ struct String { | |||||
| char* data; | char* data; | ||||
| }; | }; | ||||
| struct StringSlice { | |||||
| u64 length; | |||||
| const char* data; | |||||
| }; | |||||
| inline auto make_heap_string(const char* str) -> String { | inline auto make_heap_string(const char* str) -> String { | ||||
| String ret; | String ret; | ||||
| ret.length = strlen(str); | ret.length = strlen(str); | ||||
| ret.data = _strdup(str); | |||||
| ret.data = strdup(str); | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| inline const String make_static_string(char* str) { | |||||
| String ret; | |||||
| inline const StringSlice make_static_string(const char* str) { | |||||
| StringSlice ret; | |||||
| ret.length = strlen(str); | ret.length = strlen(str); | ||||
| ret.data = str; | ret.data = str; | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| auto inline string_equal(const char* input, const char* check) -> bool { | |||||
| return strcmp(input, check) == 0; | |||||
| } | |||||
| template <typename Str> | |||||
| auto inline string_equal(Str str, const char* check) -> bool { | |||||
| if (str.length != strlen(check)) | |||||
| return false; | |||||
| return strncmp(str.data, check, str.length) == 0; | |||||
| } | |||||
| template <typename Str> | |||||
| auto inline string_equal(const char* check, Str str) -> bool { | |||||
| if (str.length != strlen(check)) | |||||
| return false; | |||||
| return strncmp(str.data, check, str.length) == 0; | |||||
| } | |||||
| template <typename StrA, typename StrB> | |||||
| auto inline string_equal(StrA str1, StrB str2) -> bool { | |||||
| if (str1.length != str2.length) | |||||
| return false; | |||||
| return strncmp(str1.data, str2.data, str2.length) == 0; | |||||
| } | |||||
| template auto string_equal(StringSlice str1, StringSlice str2) -> bool; | |||||