Last active
February 26, 2021 11:37
-
-
Save invidian/175d8a635302917bdcb89be08d100482 to your computer and use it in GitHub Desktop.
C unit tests time formatting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Run using 'gcc main.c -g -O2 -pedantic -o main $(pkg-config gtk+-3.0 --cflags) && ./main' | |
#include <gdk/gdk.h> | |
#include <time.h> | |
#include <assert.h> | |
#include <limits.h> | |
static int hview_time_to_string(char *str, size_t maxsize, time_t time) { | |
struct tm *tm = gmtime(&time); | |
return strftime(str, maxsize, "%H:%M", tm); | |
} | |
// Using less than that may cause output to be truncated. | |
const int HVIEW_TIMES_TO_SPAN_MIN_BUF_SIZE = 14; | |
static void hview_times_to_span(char *time_span, size_t maxsize, time_t start_time, time_t end_time) { | |
char *ptr = time_span; | |
size_t charsWritten; | |
charsWritten = hview_time_to_string(ptr, maxsize, start_time); | |
maxsize -= charsWritten; | |
ptr += charsWritten; | |
int dataWritten = snprintf(ptr, maxsize, " - "); | |
if (dataWritten > 0 && dataWritten < maxsize) { | |
maxsize -= dataWritten; | |
ptr += dataWritten; | |
} | |
if(end_time) | |
{ | |
charsWritten = hview_time_to_string(ptr, maxsize, end_time); | |
maxsize -= charsWritten; | |
ptr += charsWritten; | |
} | |
// Terminate generated string after last character, if we have some buffer remaining, it will | |
// be done after last character, if not, last character in the buffer will be replaced and output | |
// will be truncated. | |
ptr -= maxsize; | |
ptr = '\0'; | |
} | |
static void hview_times_to_span_formats_both_start_and_end_time() { | |
char span[HVIEW_TIMES_TO_SPAN_MIN_BUF_SIZE]; | |
time_t start_time = 0; | |
time_t end_time = 86400-1; | |
hview_times_to_span(span, sizeof(span), start_time, end_time); | |
assert(strcmp(span, "00:00 - 23:59") == 0); | |
} | |
static void hview_times_to_span_only_prints_start_time_when_end_time_is_zero() { | |
char span[HVIEW_TIMES_TO_SPAN_MIN_BUF_SIZE]; | |
time_t start_time = 1; | |
time_t end_time = 0; | |
hview_times_to_span(span, sizeof(span), start_time, end_time); | |
assert(strcmp(span, "00:00 - ") == 0); | |
} | |
static void hview_times_to_span_writes_at_most_specified_amount_of_bytes() { | |
char span[HVIEW_TIMES_TO_SPAN_MIN_BUF_SIZE-1]; | |
time_t start_time = 0; | |
time_t end_time = 86400-1; | |
int maxLength = sizeof(span); | |
hview_times_to_span(span, maxLength, start_time, end_time); | |
assert(strcmp(span, "00:00 - 23:59") != 0); | |
assert(strlen(span) < maxLength); | |
} | |
static void hview_time_to_string_writes_at_most_specified_amount_of_bytes() { | |
char time_text[6] = ""; | |
time_t time = 86400-1; | |
int result = hview_time_to_string(time_text, sizeof(time_text)-1, time); | |
assert(strcmp(time_text, "23:59") != 0); | |
} | |
int main(int argc, char *argv[]) { | |
hview_time_to_string_writes_at_most_specified_amount_of_bytes(); | |
hview_times_to_span_formats_both_start_and_end_time(); | |
hview_times_to_span_only_prints_start_time_when_end_time_is_zero(); | |
hview_times_to_span_writes_at_most_specified_amount_of_bytes(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hm hm hm. This code could be fine if you assume that buffer is always big enough, because:
strftime(str, maxsize, "%H:%M", tm)
returns a length of a string produced from processing the format, or 0 ifstr
was too small (or rather,maxsize
was too low). So it's either all or nothing, basically. So you would need to check if return value is greater than 0 to detect the truncation.snprintf(ptr, maxsize, " - ")
will always return 3 (strlen(" - ")
), even ifmaxsize
is less than that. Which means you probably would need to check the return value against the maxsize to detect a truncation (seeRETURN VALUE
inman snprintf
).So you see, string handling in C is a PITA. I'll leave the decision to yout whether to be defensive against truncation or just assume that truncation won't happen. Probably the middle ground would be to assert that
strftime
's return value is greater than zero and that thesnprintf
's return value is less thanmaxsize
.Other than that:
ptr = ptr + charsWritten
could be written asptr += charsWritten
. :)strftime
returnssize_t
(orgsize
), so maybecharsWritten
could be alsogsize
, but on the other hand,snprintf
returns anint
, so meh. It probably can stay as is.Which leads me to another option you could consider. Since you are already using GLib, you could just use it:
Whether it's any better is for you to decide. :) Looks like more code and more memory allocations, but no fiddling with pointers and lengths.