diff --git a/CMakeLists.txt b/CMakeLists.txt index 71f57b7ac..6875f4642 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1841,11 +1841,19 @@ if (BUILD_TESTS) PRIVATE libfastfetch ) + add_executable(fastfetch-test-duration + tests/duration.c + ) + target_link_libraries(fastfetch-test-duration + PRIVATE libfastfetch + ) + enable_testing() add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf) add_test(NAME test-list COMMAND fastfetch-test-list) add_test(NAME test-format COMMAND fastfetch-test-format) add_test(NAME test-color COMMAND fastfetch-test-color) + add_test(NAME test-duration COMMAND fastfetch-test-duration) endif() ################## diff --git a/src/common/parsing.c b/src/common/parsing.c index d427dbbea..84337a995 100644 --- a/src/common/parsing.c +++ b/src/common/parsing.c @@ -190,19 +190,26 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co } } -void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result) +void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result) { - if(days == 0 && hours == 0 && minutes == 0) + if(totalSeconds < 60) { - ffStrbufAppendF(result, "%u seconds", seconds); + ffStrbufAppendF(result, "%u second", (unsigned) totalSeconds); + if (totalSeconds != 1) + ffStrbufAppendC(result, 's'); return; } - if(seconds >= 30) - { - minutes++; - seconds = 0; - } + uint32_t seconds = totalSeconds % 60; + totalSeconds /= 60; + if (seconds >= 30) + totalSeconds++; + + uint32_t minutes = totalSeconds % 60; + totalSeconds /= 60; + uint32_t hours = totalSeconds % 24; + totalSeconds /= 24; + uint32_t days = (uint32_t) totalSeconds; if(days > 0) { diff --git a/src/common/parsing.h b/src/common/parsing.h index bc04cf2f0..af72f441d 100644 --- a/src/common/parsing.h +++ b/src/common/parsing.h @@ -27,4 +27,4 @@ int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2); void ffParseSize(uint64_t bytes, FFstrbuf* result); bool ffParseFrequency(uint32_t mhz, FFstrbuf* result); -void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result); +void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result); diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 20d10aab5..02f5ab36f 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -27,17 +27,6 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin })); } - - uint32_t timeRemaining = result->timeRemaining < 0 ? 0 : (uint32_t) result->timeRemaining; - - uint32_t seconds = timeRemaining % 60; - timeRemaining /= 60; - uint32_t minutes = timeRemaining % 60; - timeRemaining /= 60; - uint32_t hours = timeRemaining % 24; - timeRemaining /= 24; - uint32_t days = timeRemaining; - FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type; if(options->moduleArgs.outputFormat.length == 0) @@ -70,7 +59,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin if(str.length > 0) ffStrbufAppendS(&str, " ("); - ffParseDuration(days, hours, minutes, seconds, &str); + ffParseDuration((uint32_t) result->timeRemaining, &str); ffStrbufAppendS(&str, " remaining)"); } } @@ -95,6 +84,15 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin } else { + uint32_t timeRemaining = result->timeRemaining < 0 ? 0 : (uint32_t) result->timeRemaining; + uint32_t seconds = timeRemaining % 60; + timeRemaining /= 60; + uint32_t minutes = timeRemaining % 60; + timeRemaining /= 60; + uint32_t hours = timeRemaining % 24; + timeRemaining /= 24; + uint32_t days = timeRemaining; + FF_STRBUF_AUTO_DESTROY capacityNum = ffStrbufCreate(); if(percentType & FF_PERCENTAGE_TYPE_NUM_BIT) ffPercentAppendNum(&capacityNum, result->capacity, options->percent, false, &options->moduleArgs); diff --git a/src/modules/uptime/uptime.c b/src/modules/uptime/uptime.c index d76db17bf..6c3a3d2c2 100644 --- a/src/modules/uptime/uptime.c +++ b/src/modules/uptime/uptime.c @@ -7,7 +7,7 @@ void ffPrintUptime(FFUptimeOptions* options) { - FFUptimeResult result; + FFUptimeResult result = {}; const char* error = ffDetectUptime(&result); @@ -19,26 +19,26 @@ void ffPrintUptime(FFUptimeOptions* options) uint64_t uptime = result.uptime; - uint32_t milliseconds = (uint32_t) (uptime % 1000); - uptime /= 1000; - uint32_t seconds = (uint32_t) (uptime % 60); - uptime /= 60; - uint32_t minutes = (uint32_t) (uptime % 60); - uptime /= 60; - uint32_t hours = (uint32_t) (uptime % 24); - uptime /= 24; - uint32_t days = (uint32_t) uptime; - if(options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(FF_UPTIME_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); - ffParseDuration(days, hours, minutes, seconds, &buffer); + ffParseDuration((uptime + 500) / 1000, &buffer); ffStrbufPutTo(&buffer, stdout); } else { + uint32_t milliseconds = (uint32_t) (uptime % 1000); + uptime /= 1000; + uint32_t seconds = (uint32_t) (uptime % 60); + uptime /= 60; + uint32_t minutes = (uint32_t) (uptime % 60); + uptime /= 60; + uint32_t hours = (uint32_t) (uptime % 24); + uptime /= 24; + uint32_t days = (uint32_t) uptime; + FF_PRINT_FORMAT_CHECKED(FF_UPTIME_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]){ FF_FORMAT_ARG(days, "days"), FF_FORMAT_ARG(hours, "hours"), diff --git a/tests/duration.c b/tests/duration.c new file mode 100644 index 000000000..0e5c9fb07 --- /dev/null +++ b/tests/duration.c @@ -0,0 +1,71 @@ +#include "common/parsing.h" +#include "util/textModifier.h" +#include "fastfetch.h" + +#include + +static void verify(uint64_t totalSeconds, const char* expected, int lineNo) +{ + FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate(); + ffParseDuration(totalSeconds, &result); + if (!ffStrbufEqualS(&result, expected)) + { + fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] %llu: expected \"%s\", got \"%s\"\n" FASTFETCH_TEXT_MODIFIER_RESET, lineNo, (unsigned long long) totalSeconds, expected, result.chars); + exit(1); + } +} + +#define VERIFY(color, expected) verify((color), (expected), __LINE__) + +int main(void) +{ + // Test seconds less than 60 + VERIFY(0, "0 seconds"); + VERIFY(1, "1 second"); + VERIFY(2, "2 seconds"); + VERIFY(59, "59 seconds"); + + // Test minute rounding (when seconds >= 30) + VERIFY(60, "1 min"); + VERIFY(60 + 29, "1 min"); + VERIFY(60 + 30, "2 mins"); + + // Test only minutes + VERIFY(60 * 2 - 1, "2 mins"); + VERIFY(60 * 2, "2 mins"); + VERIFY(60 * 59 + 29, "59 mins"); + + // Test only hours (no minutes) + VERIFY(60 * 59 + 30, "1 hour"); + VERIFY(60 * 60, "1 hour"); + VERIFY(2 * 60 * 60, "2 hours"); + VERIFY(23 * 60 * 60, "23 hours"); + + // Test combination of hours and minutes + VERIFY(60 * 60 + 60, "1 hour, 1 min"); + VERIFY(60 * 60 + 60 * 2, "1 hour, 2 mins"); + VERIFY(60 * 60 * 2 + 60 + 29, "2 hours, 1 min"); + VERIFY(60 * 60 * 2 + 60 + 30, "2 hours, 2 mins"); + + // Test days + VERIFY(60 * 60 * 24, "1 day"); + VERIFY(60 * 60 * 24 - 1, "1 day"); + VERIFY(60 * 60 * 24 * 2, "2 days"); + + // Test combination of days and hours + VERIFY(60 * 60 * 24 + 60 * 60, "1 day, 1 hour"); + VERIFY(60 * 60 * 24 * 2 + 60 * 60, "2 days, 1 hour"); + VERIFY(60 * 60 * 24 * 2 + 60 * 60 * 2, "2 days, 2 hours"); + + // Test combination of days, hours, and minutes + VERIFY(60 * 60 * 24 + 60 * 60 + 60, "1 day, 1 hour, 1 min"); + VERIFY(60 * 60 * 24 * 2 + 60 * 60 + 60 * 2, "2 days, 1 hour, 2 mins"); + VERIFY(60 * 60 * 24 * 2 + 60 * 2, "2 days, 2 mins"); + + // Test very large number of days + VERIFY(60 * 60 * 24 * 100, "100 days(!)"); + VERIFY(60 * 60 * 24 * 200, "200 days(!)"); + + //Success + puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET); +}