test_smeteo_load.c (7663B)
1 /* Copyright (C) 2025 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redismeteobute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is dismeteobuted in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #define _POSIX_C_SOURCE 200112L /* strcasecmp */ 17 18 #include "smeteo.h" 19 20 #include <rsys/mem_allocator.h> 21 22 #include <string.h> 23 #include <strings.h> /* strcasecmp */ 24 25 /******************************************************************************* 26 * Helper functions 27 ******************************************************************************/ 28 static void 29 check_api(struct smeteo* smeteo) 30 { 31 struct smeteo_desc desc = SMETEO_DESC_NULL; 32 const char* filename = "test.txt"; 33 const double albedo = 0.314; 34 const double latitude = 43.559962; /* [deg] */ 35 const double longitude = 1.468150; /* [deg] */ 36 FILE* fp = NULL; 37 38 CHK((fp = fopen(filename, "w+")) != NULL); 39 40 #define CHECK_NO_DATA(Name) { \ 41 CHK(smeteo_get_desc(smeteo, &desc) == RES_OK); \ 42 CHK(!strcmp(desc.filename, Name)); \ 43 CHK(desc.albedo == albedo); \ 44 CHK(desc.longitude == longitude); \ 45 CHK(desc.latitude == latitude); \ 46 CHK(desc.entries == NULL); \ 47 CHK(desc.nentries == 0); \ 48 } (void)0 49 50 CHK(smeteo_load(smeteo, NULL) == RES_BAD_ARG); 51 CHK(smeteo_load(NULL, filename) == RES_BAD_ARG); 52 CHK(smeteo_load(smeteo, "none.txt") == RES_IO_ERR); 53 54 /* An empty file is not valid: at least the header is required */ 55 CHK(smeteo_load(smeteo, filename) == RES_BAD_ARG); 56 57 CHK(fprintf(fp, "%a # Albedo\n", albedo) > 0); 58 CHK(fprintf(fp, "%a # Longitude [deg]\n", longitude) > 0); 59 CHK(fprintf(fp, "%a # Latitude [deg]\n", latitude) > 0); 60 CHK(fprintf(fp, "0 # Date count\n") > 0); 61 CHK(fflush(fp) == 0); 62 63 CHK(smeteo_load(smeteo, filename) == RES_OK); 64 65 CHK(smeteo_get_desc(NULL, &desc) == RES_BAD_ARG); 66 CHK(smeteo_get_desc(smeteo, NULL) == RES_BAD_ARG); 67 68 CHECK_NO_DATA(filename); 69 70 rewind(fp); 71 CHK(smeteo_load_stream(NULL, fp, "foo") == RES_BAD_ARG); 72 CHK(smeteo_load_stream(smeteo, NULL, "foo") == RES_BAD_ARG); 73 CHK(smeteo_load_stream(smeteo, fp, NULL) == RES_BAD_ARG); 74 CHK(smeteo_load_stream(smeteo, fp, "foo") == RES_OK); 75 CHECK_NO_DATA("foo"); 76 77 #undef CHECK_EMPTY_FILE 78 79 CHK(fclose(fp) == 0); 80 } 81 82 static void 83 check_n_time_intervals 84 (struct smeteo* smeteo, 85 const double albedo, 86 const double longitude, /* [deg] */ 87 const double latitude, /* [deg] */ 88 const size_t nintervals, 89 const char* date[], 90 const double Tsrf[], /* [K] */ 91 const double Tatm[], /* [K] */ 92 const double Ahum[], /* [g(water)/kg(air)] */ 93 const double Rhum[], 94 const double SWdn_direct[], /* [W/m^2] */ 95 const double SWdn_diffuse[], /* [W/m^2] */ 96 const double SWup[], /* [W.m^2] */ 97 const double Trad[], /* [K] */ 98 const double H[], /* [W/K/m^2] */ 99 const double LE[], /* W/m^2] */ 100 const double day_1850[]) 101 { 102 struct smeteo_desc desc = SMETEO_DESC_NULL; 103 104 char buf[32] = {0}; 105 FILE* fp = NULL; 106 size_t i = 0; 107 108 CHK((fp = tmpfile()) != NULL); 109 110 CHK(fprintf(fp, "%a # albedo\n", albedo) > 0); 111 CHK(fprintf(fp, "%a # longitude [deg]\n", longitude) > 0); 112 CHK(fprintf(fp, "%a # latitude [deg]\n", latitude) > 0); 113 CHK(fprintf(fp, "%lu # Date count\n", (unsigned long)nintervals) > 0); 114 115 FOR_EACH(i, 0, nintervals) { 116 CHK(fprintf(fp, "%s %a %a %a %a %a %a %a %a %a %a %a %a\n", 117 date[i], 118 Tsrf[i], 119 Tatm[i], 120 Ahum[i], 121 Rhum[i], 122 SWdn_direct[i] + SWdn_diffuse[i], 123 SWdn_direct[i], 124 SWdn_diffuse[i], 125 SWup[i], 126 Trad[i], 127 H[i], 128 LE[i], 129 day_1850[i]) > 0); 130 } 131 132 rewind(fp); 133 134 CHK(smeteo_load_stream(smeteo, fp, "Test") == RES_OK); 135 CHK(smeteo_get_desc(smeteo, &desc) == RES_OK); 136 137 /* Check header */ 138 #define CHK_HEADER(Var) CHK(Var == desc.Var) 139 CHK_HEADER(albedo); 140 CHK_HEADER(longitude); 141 CHK_HEADER(latitude); 142 CHK(desc.nentries == nintervals); 143 #undef CHK_HEADER 144 145 #define CHK_ENTRY(Var) CHK(Var[i] == desc.entries[i].Var) 146 FOR_EACH(i, 0, nintervals) { 147 /* Check entry time */ 148 CHK(strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", &desc.entries[i].time)); 149 CHK(strcasecmp(buf, date[i]) == 0); 150 151 /* Check entry data */ 152 CHK_ENTRY(Tsrf); 153 CHK_ENTRY(Tatm); 154 CHK_ENTRY(Ahum); 155 CHK_ENTRY(Rhum); 156 CHK_ENTRY(SWdn_direct); 157 CHK_ENTRY(SWdn_diffuse); 158 CHK_ENTRY(SWup); 159 CHK_ENTRY(Trad); 160 CHK_ENTRY(H); 161 CHK_ENTRY(LE); 162 CHK_ENTRY(day_1850); 163 164 } 165 #undef CHK_ENTRY 166 167 CHK(fclose(fp) == 0); 168 } 169 170 static void 171 check_1_time_interval(struct smeteo* smeteo) 172 { 173 /* Header */ 174 const double albedo = 1; 175 const double longitude = 91.1; /* [deg] */ 176 const double latitude = 46.2; /* [deg] */ 177 178 /* Time interval data */ 179 const char* date = "01-JAN-1850 01:30:00"; 180 const double Tsrf = 287.85; /* [K] */ 181 const double Tatm = 289.62; /* [K] */ 182 const double Ahum = 4.23; /* [g(water)/kg(air)] */ 183 const double Rhum = 12.28; 184 const double SWdn_direct = 175.08; /* [W/m^2] */ 185 const double SWdn_diffuse = 0; /* [W/m^2] */ 186 const double SWup = 55.43; /* [W/m^2] */ 187 const double Trad = 271.21; /* [K] */ 188 const double H = 12.60; /* [W/K/m^2] */ 189 const double LE = 0.51; /* [W/m^2] */ 190 const double day_1850 = 0.0625; 191 192 check_n_time_intervals(smeteo, albedo, longitude, latitude, 1, &date, &Tsrf, 193 &Tatm, &Ahum, &Rhum, &SWdn_direct, &SWdn_diffuse, &SWup, &Trad, &H, &LE, 194 &day_1850); 195 } 196 197 static void 198 check_4_time_intervals(struct smeteo* smeteo) 199 { 200 /* Header */ 201 const double albedo = 0.31659812657071051; 202 const double longitude = 10.428827285766602; /* [deg] */ 203 const double latitude = 16.388128280639648; /* [deg] */ 204 205 /* Time interval data */ 206 const char* date[] = { 207 "01-JAN-1850 01:30:00", "01-JAN-1850 04:30:00", 208 "01-JAN-1850 07:30:00", "01-JAN-1850 10:30:00", 209 }; 210 const double Tsrf[] = { 287.85, 286.18, 293.25, 307.28 }; /* [K] */ 211 const double Tatm[] = { 289.62, 287.77, 291.16, 298.31 }; /* [K] */ 212 const double Ahum[] = { 4.23, 0, 0, 0 }; /* [g(water)/kg(air)] */ 213 const double Rhum[] = { 12.28, 0, 0, 0 }; 214 const double SWdn_direct[] = { 0, 0, 175.08, 679.01 }; /* [W/m^2] */ 215 const double SWdn_diffuse[] = { 0, 0, 0, 0 }; /* [W/m^2] */ 216 const double SWup[] = { 0, 0, 55.43, 213.37 }; /* [W/m^2] */ 217 const double Trad[] = { 271.21, 269.50, 268.62, 271.61 }; /* [K] */ 218 const double H[] = { 12.60, 8.74, 7.32, 17.80 }; /* [W/K/m^2] */ 219 const double LE[] = { 0.51, 0.52, 0.87, 1.78 }; /* [W/m^2] */ 220 const double day_1850[] = { 0.0625, 0.1875, 0.3125, 0.4375 }; 221 222 check_n_time_intervals(smeteo, albedo, longitude, latitude, 4, date, 223 Tsrf, Tatm, Ahum, Rhum, SWdn_direct, SWdn_diffuse, SWup, Trad, H, LE, 224 day_1850); 225 } 226 227 /******************************************************************************* 228 * The test 229 ******************************************************************************/ 230 int 231 main(void) 232 { 233 struct smeteo* smeteo = NULL; 234 struct smeteo_create_args args = SMETEO_CREATE_ARGS_DEFAULT; 235 236 args.verbose = 3; 237 CHK(smeteo_create(&args, &smeteo) == RES_OK); 238 239 check_api(smeteo); 240 check_1_time_interval(smeteo); 241 check_4_time_intervals(smeteo); 242 243 CHK(smeteo_ref_put(smeteo) == RES_OK); 244 CHK(mem_allocated_size() == 0); 245 return 0; 246 }