Tests and fixes for url_encode

This commit is contained in:
2026-06-17 17:34:07 +02:00
parent 4c1688730f
commit 434dca7fe7
5 changed files with 104 additions and 16 deletions

View File

@@ -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: output:
mkdir -p output mkdir -p output

View File

@@ -14,6 +14,12 @@ elif [ $1 = "run" ]; then
make server make server
./output/server 5000 ./library "Testing library" ./output/server 5000 ./library "Testing library"
elif [ $1 = "test" ]; then
echo "Running tests"
make test
./output/test
elif [ $1 = "debug" ]; then elif [ $1 = "debug" ]; then
echo "Debugging" echo "Debugging"

View File

@@ -156,9 +156,21 @@ typedef enum {
NOH_ERROR, NOH_ERROR,
} Noh_Log_Level; } 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. // Writes a formatted log message to stderr with the provided log level.
void noh_log(Noh_Log_Level level, const char *fmt, ...); 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 ///////////////////////// ///////////////////////// Dynamic array /////////////////////////
#define NOH_DA_INIT_CAP 256 #define NOH_DA_INIT_CAP 256
@@ -609,27 +621,36 @@ void noh_time_add(struct timespec *time, int seconds, long milliseconds) {
///////////////////////// Logging ///////////////////////// ///////////////////////// 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, ...) void noh_log(Noh_Log_Level level, const char *fmt, ...)
{ {
switch (level) { Noh_Log_Options *opts = noh_log_get_opts();
case NOH_INFO:
fprintf(stderr, "[INFO] "); if (opts->write_prefix) {
break; switch (level) {
case NOH_WARNING: case NOH_INFO:
fprintf(stderr, "[WARNING] "); fprintf(stderr, "[INFO] ");
break; break;
case NOH_ERROR: case NOH_WARNING:
fprintf(stderr, "[ERROR] "); fprintf(stderr, "[WARNING] ");
break; break;
default: case NOH_ERROR:
noh_assert(false && "Invalid log level"); fprintf(stderr, "[ERROR] ");
break;
default:
noh_assert(false && "Invalid log level");
}
} }
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vfprintf(stderr, fmt, args); vfprintf(stderr, fmt, args);
va_end(args); va_end(args);
fprintf(stderr, "\n"); if (opts->write_lf) fprintf(stderr, "\n");
} }
///////////////////////// Arena ///////////////////////// ///////////////////////// Arena /////////////////////////

View File

@@ -3,7 +3,7 @@
static inline bool byte_is_url_safe(char c) { static inline bool byte_is_url_safe(char c) {
return (c >= 'A' && c <= 'Z') return (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z') || (c >= 'a' && c <= 'z')
|| (c >= '0' && c <+ '9') || (c >= '0' && c <= '9')
|| (c >= '(' && c <= '*') || (c >= '(' && c <= '*')
|| c == '!' || c == '-' || c == '!' || c == '-'
|| c == '.' || c == '_'; || c == '.' || c == '_';
@@ -15,12 +15,12 @@ static bool needs_encoding(Noh_String string, int *unsafe_count) {
*unsafe_count = 0; *unsafe_count = 0;
bool safe = true ; bool safe = true ;
for (size_t i = 0; i < string.count; i++) { 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 || string.elems[i] == ' ') safe = false;
if (needs_encode) (*unsafe_count)++; if (needs_encode) (*unsafe_count)++;
} }
return safe; return !safe;
} }
static inline char to_char_lower(int value) { 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, '%');
noh_da_append(&result, to_char_lower(cur >> 4)); noh_da_append(&result, to_char_lower(cur >> 4));
noh_da_append(&result, to_char_lower(cur)); noh_da_append(&result, to_char_lower(cur));
} else {
noh_da_append(&result, cur);
} }
} }

52
test/test_path.c Normal file
View File

@@ -0,0 +1,52 @@
#include <stdio.h>
#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;
}
}