diff --git a/Makefile b/Makefile index fc99a6b..86b1e4a 100644 --- a/Makefile +++ b/Makefile @@ -49,5 +49,12 @@ output/noh.o: src/noh.h | output ################################################################################ +test: output/test +output/test: test/test_path.c $(SHARED_LIB_FILES) | output + gcc $(CFLAGS) -I./src -o output/test test/test_path.c $(SHARED_LIBS) + +################################################################################ + output: mkdir -p output + diff --git a/build.sh b/build.sh index 14e49a9..b282185 100755 --- a/build.sh +++ b/build.sh @@ -14,6 +14,12 @@ elif [ $1 = "run" ]; then make server ./output/server 5000 ./library "Testing library" +elif [ $1 = "test" ]; then + echo "Running tests" + + make test + ./output/test + elif [ $1 = "debug" ]; then echo "Debugging" diff --git a/src/noh.h b/src/noh.h index bec3710..d864aae 100644 --- a/src/noh.h +++ b/src/noh.h @@ -156,9 +156,21 @@ typedef enum { NOH_ERROR, } Noh_Log_Level; +// Options that can alter the behavior of noh_log. +typedef struct { + // Whether to write a line feed at the end of a log message. Default is true. + bool write_lf; + + // Whether to write a line feed at the end of a log message. Default is true. + bool write_prefix; +} Noh_Log_Options; + // Writes a formatted log message to stderr with the provided log level. void noh_log(Noh_Log_Level level, const char *fmt, ...); +// Returns a pointer to the noh_log options. +Noh_Log_Options *noh_log_get_opts(); + ///////////////////////// Dynamic array ///////////////////////// #define NOH_DA_INIT_CAP 256 @@ -609,27 +621,36 @@ void noh_time_add(struct timespec *time, int seconds, long milliseconds) { ///////////////////////// Logging ///////////////////////// +Noh_Log_Options *noh_log_get_opts() { + static Noh_Log_Options opts = { .write_lf = true, .write_prefix = true, }; + return &opts; +} + void noh_log(Noh_Log_Level level, const char *fmt, ...) { - switch (level) { - case NOH_INFO: - fprintf(stderr, "[INFO] "); - break; - case NOH_WARNING: - fprintf(stderr, "[WARNING] "); - break; - case NOH_ERROR: - fprintf(stderr, "[ERROR] "); - break; - default: - noh_assert(false && "Invalid log level"); + Noh_Log_Options *opts = noh_log_get_opts(); + + if (opts->write_prefix) { + switch (level) { + case NOH_INFO: + fprintf(stderr, "[INFO] "); + break; + case NOH_WARNING: + fprintf(stderr, "[WARNING] "); + break; + case NOH_ERROR: + fprintf(stderr, "[ERROR] "); + break; + default: + noh_assert(false && "Invalid log level"); + } } va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); - fprintf(stderr, "\n"); + if (opts->write_lf) fprintf(stderr, "\n"); } ///////////////////////// Arena ///////////////////////// diff --git a/src/path.c b/src/path.c index 5c7095e..01ed3fb 100644 --- a/src/path.c +++ b/src/path.c @@ -3,7 +3,7 @@ static inline bool byte_is_url_safe(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') - || (c >= '0' && c <+ '9') + || (c >= '0' && c <= '9') || (c >= '(' && c <= '*') || c == '!' || c == '-' || c == '.' || c == '_'; @@ -15,12 +15,12 @@ static bool needs_encoding(Noh_String string, int *unsafe_count) { *unsafe_count = 0; bool safe = true ; for (size_t i = 0; i < string.count; i++) { - bool needs_encode = byte_is_url_safe(string.elems[i]); + bool needs_encode = !byte_is_url_safe(string.elems[i]); if (needs_encode || string.elems[i] == ' ') safe = false; if (needs_encode) (*unsafe_count)++; } - return safe; + return !safe; } static inline char to_char_lower(int value) { @@ -55,6 +55,8 @@ void url_encode(Noh_String *string) { noh_da_append(&result, '%'); noh_da_append(&result, to_char_lower(cur >> 4)); noh_da_append(&result, to_char_lower(cur)); + } else { + noh_da_append(&result, cur); } } diff --git a/test/test_path.c b/test/test_path.c new file mode 100644 index 0000000..4686868 --- /dev/null +++ b/test/test_path.c @@ -0,0 +1,52 @@ +#include + +#include "path.h" +#include "noh.h" + +void check_string(size_t *good, size_t *bad, const char* input, const char *expected) { + Noh_String test = noh_string_from_cstr(input); + Noh_String_View expected_sv = noh_sv_from_cstr(expected); + + Noh_Log_Options *opts = noh_log_get_opts(); + + opts->write_lf = false; + noh_log(NOH_INFO, "Testing: \"%s\"...", input); + opts->write_lf = true; + opts->write_prefix = false; + + url_encode(&test); + bool correct = noh_sv_eq(noh_sv_from_string(test), expected_sv); + + if (!correct) { + noh_log(NOH_ERROR, " Incorrect."); + opts->write_prefix = true; + noh_log(NOH_ERROR, "Expected: "Nsv_Fmt, Nsv_Arg(expected_sv)); + noh_log(NOH_ERROR, "Got : "Nsv_Fmt, Nsv_Arg(test)); + (*bad)++; + } else { + noh_log(NOH_INFO, " Ok."); + opts->write_prefix = true; + (*good)++; + } +} + +int main() { + size_t good = 0; + size_t bad = 0; + + check_string(&good, &bad, + "abcdefghijklmnopqrstuvwxyz1023456789ABCDEFGHIJKLMNOPQRSTUVWXYZ()*!-._", + "abcdefghijklmnopqrstuvwxyz1023456789ABCDEFGHIJKLMNOPQRSTUVWXYZ()*!-._"); + + check_string(&good, &bad, + "~!@#$%^&*()_+-=", + "%7e!%40%23%24%25%5e%26*()_%2b-%3d"); + + if (bad == 0) { + noh_log(NOH_INFO, "%zu/%zu tests passed.", good, good); + return 0; + } else { + noh_log(NOH_ERROR, "%zu/%zu tests passed. %zu failures.", good, good + bad, bad); + return 1; + } +}