master ohmu/fastfetch-openbsd / tests / temps.c
ohmu  ·  2026-10-15
  1#include "common/option.h"
  2#include "common/temps.h"
  3#include "common/textModifier.h"
  4#include "fastfetch.h"
  5
  6#include <float.h>
  7#include <stdio.h>
  8#include <stdlib.h>
  9
 10static FFModuleArgs module;
 11
 12static void verify(double celsius, FFColorRangeConfig config, const char* expected, int lineNo) {
 13    FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate();
 14    ffTempsAppendNum(celsius, &result, config, &module);
 15
 16    if (!ffStrbufEqualS(&result, expected)) {
 17        fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] ffTempsAppendNum(%f, {%u, %u}): expected \"%s\", got \"%s\"\n" FASTFETCH_TEXT_MODIFIER_RESET,
 18            lineNo, celsius, config.green, config.yellow, expected, result.chars);
 19        exit(1);
 20    }
 21}
 22
 23#define VERIFY_TEMP(celsius, config, expected) verify((celsius), (config), (expected), __LINE__)
 24
 25int main(void) {
 26    // Use the real defaults rather than a hand built config, so a changed default is caught here too
 27    ffOptionsInitDisplay(&instance.config.display);
 28    FFOptionsDisplay* options = &instance.config.display;
 29    ffOptionInitModuleArg(&module, "");
 30
 31    // Pin the threshold colors: the yellow and red defaults depend on whether the terminal is
 32    // detected as a light theme, which is not something a test should depend on.
 33    ffStrbufSetS(&options->tempColorGreen, "32");
 34    ffStrbufSetS(&options->tempColorYellow, "33");
 35    ffStrbufSetS(&options->tempColorRed, "31");
 36
 37    const FFColorRangeConfig config = { .green = 50, .yellow = 80 };
 38
 39    // An unknown temperature prints nothing at all, not even the unit
 40    {
 41        options->pipe = true;
 42        VERIFY_TEMP(-DBL_MAX, config, "");
 43    }
 44
 45    // The default unit is Celsius, with one digit after the point
 46    {
 47        options->pipe = true;
 48        VERIFY_TEMP(0, config, "0.0°C");
 49        VERIFY_TEMP(25.5, config, "25.5°C");
 50        VERIFY_TEMP(-10, config, "-10.0°C");
 51        VERIFY_TEMP(-273.15, config, "-273.1°C");
 52    }
 53
 54    // tempNdigits
 55    {
 56        options->pipe = true;
 57        options->tempNdigits = 0;
 58        VERIFY_TEMP(25.4, config, "25°C");
 59        VERIFY_TEMP(25.6, config, "26°C");
 60        VERIFY_TEMP(0, config, "0°C");
 61
 62        options->tempNdigits = 2;
 63        VERIFY_TEMP(25.5, config, "25.50°C");
 64
 65        options->tempNdigits = 1;
 66    }
 67
 68    // Celsius and Fahrenheit only take a space before the unit when it is forced on, while Kelvin
 69    // takes one by default. That asymmetry is deliberate and easy to break.
 70    {
 71        options->pipe = true;
 72        options->tempNdigits = 2; // so that 25.5 + 273.15 prints exactly
 73
 74        options->tempSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT;
 75        VERIFY_TEMP(25.5, config, "25.50°C");
 76        options->tempUnit = FF_TEMPERATURE_UNIT_KELVIN;
 77        VERIFY_TEMP(25.5, config, "298.65 K");
 78        options->tempUnit = FF_TEMPERATURE_UNIT_DEFAULT;
 79
 80        options->tempSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_NEVER;
 81        VERIFY_TEMP(25.5, config, "25.50°C");
 82        options->tempUnit = FF_TEMPERATURE_UNIT_KELVIN;
 83        VERIFY_TEMP(25.5, config, "298.65K");
 84        options->tempUnit = FF_TEMPERATURE_UNIT_DEFAULT;
 85
 86        options->tempSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_ALWAYS;
 87        VERIFY_TEMP(25.5, config, "25.50 °C");
 88        options->tempUnit = FF_TEMPERATURE_UNIT_KELVIN;
 89        VERIFY_TEMP(25.5, config, "298.65 K");
 90        options->tempUnit = FF_TEMPERATURE_UNIT_DEFAULT;
 91
 92        options->tempSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT;
 93        options->tempNdigits = 1;
 94    }
 95
 96    // Fahrenheit and Kelvin are conversions of the Celsius value that the thresholds were compared
 97    // against, so the unit changes what is printed but never which band is picked.
 98    {
 99        options->pipe = true;
100
101        options->tempUnit = FF_TEMPERATURE_UNIT_FAHRENHEIT;
102        VERIFY_TEMP(0, config, "32.0°F");
103        VERIFY_TEMP(100, config, "212.0°F");
104        VERIFY_TEMP(37, config, "98.6°F");
105        VERIFY_TEMP(-40, config, "-40.0°F"); // the one point where the two scales meet
106
107        options->tempNdigits = 2;
108        options->tempUnit = FF_TEMPERATURE_UNIT_KELVIN;
109        VERIFY_TEMP(0, config, "273.15 K");
110        VERIFY_TEMP(100, config, "373.15 K");
111        VERIFY_TEMP(-273.15, config, "0.00 K");
112        options->tempNdigits = 1;
113
114        options->tempUnit = FF_TEMPERATURE_UNIT_DEFAULT;
115    }
116
117    // Colors, with the same band rules as the percentage module: the threshold itself belongs to the
118    // lower band, and the reset sequence is always emitted when colors are on.
119    {
120        options->pipe = false;
121
122        VERIFY_TEMP(0, config, "\e[32m0.0°C\e[m");
123        VERIFY_TEMP(50, config, "\e[32m50.0°C\e[m");
124        VERIFY_TEMP(51, config, "\e[33m51.0°C\e[m");
125        VERIFY_TEMP(80, config, "\e[33m80.0°C\e[m");
126        VERIFY_TEMP(81, config, "\e[31m81.0°C\e[m");
127        VERIFY_TEMP(100, config, "\e[31m100.0°C\e[m");
128
129        // The color is chosen from the Celsius value, so a display unit that is not Celsius does not
130        // move the threshold
131        options->tempUnit = FF_TEMPERATURE_UNIT_FAHRENHEIT;
132        VERIFY_TEMP(81, config, "\e[31m177.8°F\e[m");
133        options->tempUnit = FF_TEMPERATURE_UNIT_DEFAULT;
134
135        // An unknown temperature has no color at all
136        VERIFY_TEMP(-DBL_MAX, config, "");
137
138        // When `green > yellow` the bands are inverted, so a low value is the alarming one
139        const FFColorRangeConfig inverted = { .green = 80, .yellow = 50 };
140        VERIFY_TEMP(0, inverted, "\e[31m0.0°C\e[m");
141        VERIFY_TEMP(49, inverted, "\e[31m49.0°C\e[m");
142        VERIFY_TEMP(50, inverted, "\e[33m50.0°C\e[m");
143        VERIFY_TEMP(79, inverted, "\e[33m79.0°C\e[m");
144        VERIFY_TEMP(80, inverted, "\e[32m80.0°C\e[m");
145        VERIFY_TEMP(100, inverted, "\e[32m100.0°C\e[m");
146    }
147
148    // The color is restored to the module's output color, so the rest of the line keeps its own
149    {
150        options->pipe = false;
151        ffStrbufSetS(&module.outputColor, "94");
152        VERIFY_TEMP(0, config, "\e[32m0.0°C\e[m\e[94m");
153        ffStrbufClear(&module.outputColor);
154
155        // ... and it falls back to the global output color when the module has none
156        ffStrbufSetS(&options->colorOutput, "95");
157        VERIFY_TEMP(0, config, "\e[32m0.0°C\e[m\e[95m");
158        ffStrbufClear(&options->colorOutput);
159    }
160
161    // The result is appended to the buffer instead of replacing it
162    {
163        options->pipe = true;
164        FF_STRBUF_AUTO_DESTROY result = ffStrbufCreateS("Temp: ");
165        ffTempsAppendNum(25.5, &result, config, &module);
166        if (!ffStrbufEqualS(&result, "Temp: 25.5°C")) {
167            fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] ffTempsAppendNum did not append: got \"%s\"\n" FASTFETCH_TEXT_MODIFIER_RESET, __LINE__, result.chars);
168            exit(1);
169        }
170    }
171
172    ffOptionDestroyModuleArg(&module);
173    ffOptionsDestroyDisplay(options);
174
175    puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET);
176    return 0;
177}