test_shtr_isotope_metadata.c (20202B)
1 /* Copyright (C) 2022, 2025, 2026 |Méso|Star> (contact@meso-star.com) 2 * Copyright (C) 2025, 2026 Université de Lorraine 3 * Copyright (C) 2022 Centre National de la Recherche Scientifique 4 * Copyright (C) 2022 Université Paul Sabatier 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #include "shtr.h" 20 21 #include <rsys/mem_allocator.h> 22 #include <rsys/math.h> 23 24 #include <string.h> 25 26 static const struct shtr_isotope H2O_isotopes[] = { 27 {9.97317E-01, 1.7458E+02, 18.010565, 0, 1, 161}, 28 {1.99983E-03, 1.7605E+02, 20.014811, 0, 1, 181}, 29 {3.71884E-04, 1.0521E+03, 19.014780, 0, 6, 171}, 30 {3.10693E-04, 8.6474E+02, 19.016740, 0, 6, 162}, 31 {6.23003E-07, 8.7557E+02, 21.020985, 0, 6, 182}, 32 {1.15853E-07, 5.2268E+03, 20.020956, 0, 36, 172}, 33 {2.41974E-08, 1.0278E+03, 20.022915, 0, 1, 262} 34 }; 35 36 37 static const struct shtr_molecule H2O = { 38 "H2O", sizeof(H2O_isotopes)/sizeof(struct shtr_isotope), H2O_isotopes, 1, 39 }; 40 41 static const struct shtr_isotope CO2_isotopes[] = { 42 {9.84204E-01, 2.8609E+02, 43.989830, 1, 1, 626}, 43 {1.10574E-02, 5.7664E+02, 44.993185, 1, 2, 636}, 44 {3.94707E-03, 6.0781E+02, 45.994076, 1, 1, 628}, 45 {7.33989E-04, 3.5426E+03, 44.994045, 1, 6, 627}, 46 {4.43446E-05, 1.2255E+03, 46.997431, 1, 2, 638}, 47 {8.24623E-06, 7.1413E+03, 45.997400, 1, 12, 637}, 48 {3.95734E-06, 3.2342E+02, 47.998320, 1, 1, 828}, 49 {1.47180E-06, 3.7666E+03, 46.998291, 1, 6, 827}, 50 {1.36847E-07, 1.0972E+04, 45.998262, 1, 1, 727}, 51 {4.44600E-08, 6.5224E+02, 49.001675, 1, 2, 838}, 52 {1.65354E-08, 7.5950E+03, 48.001646, 1, 12, 837}, 53 {1.53745E-09, 2.2120E+04, 47.001618, 1, 2, 737} 54 }; 55 56 static const struct shtr_molecule CO2 = { 57 "CO2", sizeof(CO2_isotopes)/sizeof(struct shtr_isotope), CO2_isotopes, 2, 58 }; 59 60 static void 61 isotope_print(FILE* fp, const struct shtr_isotope* isotope) 62 { 63 CHK(fp && isotope); 64 fprintf(fp, " %d %.5E %.4E %d %.6f\n", 65 isotope->id, 66 isotope->abundance, 67 isotope->Q296K, 68 isotope->gj, 69 isotope->molar_mass); 70 } 71 72 static void 73 molecule_print(FILE* fp, const struct shtr_molecule* molecule) 74 { 75 size_t i; 76 CHK(fp && molecule); 77 78 fprintf(fp, " %s (%d)\n", molecule->name, molecule->id); 79 FOR_EACH(i, 0, molecule->nisotopes) { 80 isotope_print(fp, molecule->isotopes+i); 81 } 82 } 83 84 static int 85 isotope_eq(const struct shtr_isotope* i0, const struct shtr_isotope* i1) 86 { 87 CHK(i0 && i1); 88 return i0->abundance == i1->abundance 89 && i0->Q296K == i1->Q296K 90 && i0->molar_mass == i1->molar_mass 91 && i0->molecule_id_local == i1->molecule_id_local 92 && i0->gj == i1->gj 93 && i0->id == i1->id; 94 } 95 96 static int 97 molecule_eq(const struct shtr_molecule* m0, const struct shtr_molecule* m1) 98 { 99 size_t i; 100 101 CHK(m0 && m1); 102 if(strcmp(m0->name, m1->name) 103 || m0->id != m1->id 104 || m0->nisotopes != m1->nisotopes) 105 return 0; 106 107 FOR_EACH(i, 0, m0->nisotopes) { 108 if(!isotope_eq(m0->isotopes+i, m1->isotopes+i)) 109 return 0; 110 } 111 return 1; 112 } 113 114 static void 115 check_isotope 116 (struct shtr_isotope_metadata* mdata, 117 const struct shtr_molecule* molecule, 118 const struct shtr_isotope* isotope) 119 { 120 struct shtr_molecule molecule2 = SHTR_MOLECULE_NULL; 121 122 /* Check NaN */ 123 CHK(isotope->abundance == isotope->abundance); 124 CHK(isotope->Q296K == isotope->Q296K); 125 CHK(isotope->molar_mass == isotope->molar_mass); 126 127 CHK(isotope->abundance > 0 && isotope->abundance <= 1); 128 CHK(isotope->Q296K > 0); 129 CHK(isotope->molar_mass > 0); 130 CHK(isotope->id >= 0); 131 132 CHK(shtr_isotope_metadata_get_molecule 133 (mdata, isotope->molecule_id_local, &molecule2) == RES_OK); 134 CHK(molecule_eq(molecule, &molecule2)); 135 } 136 137 static void 138 check_molecule 139 (struct shtr_isotope_metadata* mdata, 140 struct shtr_molecule* molecule) 141 { 142 size_t i = 0; 143 144 CHK(mdata && molecule); 145 CHK(molecule->name); 146 CHK(molecule->id >= 0); 147 148 FOR_EACH(i, 0, molecule->nisotopes) { 149 check_isotope(mdata, molecule, molecule->isotopes+i); 150 } 151 } 152 153 static void 154 test_load(struct shtr* shtr) 155 { 156 struct shtr_molecule molecule = SHTR_MOLECULE_NULL; 157 const char* filename = "test_isotope_metadata.txt"; 158 struct shtr_isotope_metadata* mdata = NULL; 159 FILE* fp = NULL; 160 size_t nmolecules = 0; 161 size_t nisotopes = 0; 162 163 CHK(fp = fopen(filename, "w+")); 164 165 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 166 molecule_print(fp, &H2O); 167 molecule_print(fp, &CO2); 168 rewind(fp); 169 170 CHK(shtr_isotope_metadata_load_stream(NULL, fp, NULL, &mdata) == RES_BAD_ARG); 171 CHK(shtr_isotope_metadata_load_stream(shtr, NULL, NULL, &mdata) == RES_BAD_ARG); 172 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, NULL) == RES_BAD_ARG); 173 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_OK); 174 175 CHK(shtr_isotope_metadata_get_molecules_count(NULL, &nmolecules) == RES_BAD_ARG); 176 CHK(shtr_isotope_metadata_get_molecules_count(mdata, NULL) == RES_BAD_ARG); 177 CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); 178 CHK(nmolecules == 2); 179 180 CHK(shtr_isotope_metadata_get_isotopes_count(NULL, &nisotopes) == RES_BAD_ARG); 181 CHK(shtr_isotope_metadata_get_isotopes_count(mdata, NULL) == RES_BAD_ARG); 182 CHK(shtr_isotope_metadata_get_isotopes_count(mdata, &nisotopes) == RES_OK); 183 CHK(nisotopes == H2O.nisotopes + CO2.nisotopes); 184 185 CHK(shtr_isotope_metadata_get_molecule(NULL, 0, &molecule) == RES_BAD_ARG); 186 CHK(shtr_isotope_metadata_get_molecule(mdata, 2, &molecule) == RES_BAD_ARG); 187 188 CHK(shtr_isotope_metadata_get_molecule(mdata, 0, &molecule) == RES_OK); 189 CHK(molecule_eq(&molecule, &H2O)); 190 check_molecule(mdata, &molecule); 191 192 CHK(shtr_isotope_metadata_get_molecule(mdata, 1, &molecule) == RES_OK); 193 CHK(molecule_eq(&molecule, &CO2)); 194 check_molecule(mdata, &molecule); 195 196 CHK(shtr_isotope_metadata_find_molecule(NULL, 1, &molecule) == RES_BAD_ARG); 197 CHK(shtr_isotope_metadata_find_molecule(mdata, 1, NULL) == RES_BAD_ARG); 198 CHK(shtr_isotope_metadata_find_molecule(mdata, 1, &molecule) == RES_OK); 199 CHK(!SHTR_MOLECULE_IS_NULL(&molecule)); 200 CHK(molecule_eq(&molecule, &H2O)); 201 202 CHK(shtr_isotope_metadata_find_molecule(mdata, 2, &molecule) == RES_OK); 203 CHK(!SHTR_MOLECULE_IS_NULL(&molecule)); 204 CHK(molecule_eq(&molecule, &CO2)); 205 206 CHK(shtr_isotope_metadata_find_molecule(mdata, 0, &molecule) == RES_OK); 207 CHK(SHTR_MOLECULE_IS_NULL(&molecule)); 208 209 CHK(shtr_isotope_metadata_ref_get(NULL) == RES_BAD_ARG); 210 CHK(shtr_isotope_metadata_ref_get(mdata) == RES_OK); 211 CHK(shtr_isotope_metadata_ref_put(NULL) == RES_BAD_ARG); 212 CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); 213 CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); 214 215 CHK(fclose(fp) == 0); 216 217 CHK(shtr_isotope_metadata_load(NULL, filename, &mdata) == RES_BAD_ARG); 218 CHK(shtr_isotope_metadata_load(shtr, NULL, &mdata) == RES_BAD_ARG); 219 CHK(shtr_isotope_metadata_load(shtr, filename, NULL) == RES_BAD_ARG); 220 CHK(shtr_isotope_metadata_load(shtr, "no_file", &mdata) == RES_IO_ERR); 221 222 CHK(shtr_isotope_metadata_load(shtr, filename, &mdata) == RES_OK); 223 CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); 224 CHK(nmolecules == 2); 225 CHK(shtr_isotope_metadata_get_molecule(mdata, 0, &molecule) == RES_OK); 226 CHK(molecule_eq(&molecule, &H2O)); 227 CHK(shtr_isotope_metadata_get_molecule(mdata, 1, &molecule) == RES_OK); 228 CHK(molecule_eq(&molecule, &CO2)); 229 CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); 230 231 /* Empty file */ 232 CHK(fp = tmpfile()); 233 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_OK); 234 CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); 235 CHK(nmolecules == 0); 236 CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); 237 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 238 rewind(fp); 239 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_OK); 240 CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); 241 CHK(nmolecules == 0); 242 CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); 243 CHK(fclose(fp) == 0); 244 245 /* Molecule without isotope */ 246 CHK(fp = tmpfile()); 247 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 248 fprintf(fp, "%s (%d)\n", H2O.name, H2O.id); 249 fprintf(fp, "%s (%d)\n", CO2.name, CO2.id); 250 rewind(fp); 251 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_OK); 252 CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); 253 CHK(nmolecules == 2); 254 255 CHK(shtr_isotope_metadata_get_molecule(mdata, 0, &molecule) == RES_OK); 256 CHK(!strcmp(molecule.name, H2O.name)); 257 CHK(molecule.id == H2O.id); 258 CHK(molecule.nisotopes == 0); 259 CHK(molecule.isotopes == NULL); 260 261 CHK(shtr_isotope_metadata_get_molecule(mdata, 1, &molecule) == RES_OK); 262 CHK(!strcmp(molecule.name, CO2.name)); 263 CHK(molecule.id == CO2.id); 264 CHK(molecule.nisotopes == 0); 265 CHK(molecule.isotopes == NULL); 266 267 CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); 268 CHK(fclose(fp) == 0); 269 } 270 271 static void 272 check_equality 273 (const struct shtr_isotope_metadata* mdata1, 274 const struct shtr_isotope_metadata* mdata2) 275 { 276 hash256_T hash1; 277 hash256_T hash2; 278 size_t n1, n2; 279 size_t imol, nmol; 280 CHK(mdata1 && mdata2); 281 282 CHK(shtr_isotope_metadata_get_molecules_count(mdata1, &n1) == RES_OK); 283 CHK(shtr_isotope_metadata_get_molecules_count(mdata2, &n2) == RES_OK); 284 CHK(n1 == n2); 285 nmol = n1; 286 287 CHK(shtr_isotope_metadata_get_isotopes_count(mdata1, &n1) == RES_OK); 288 CHK(shtr_isotope_metadata_get_isotopes_count(mdata2, &n2) == RES_OK); 289 CHK(n1 == n2); 290 291 FOR_EACH(imol, 0, nmol) { 292 struct shtr_molecule mol1 = SHTR_MOLECULE_NULL; 293 struct shtr_molecule mol2 = SHTR_MOLECULE_NULL; 294 size_t iiso, niso; 295 296 CHK(shtr_isotope_metadata_get_molecule(mdata1, imol, &mol1) == RES_OK); 297 CHK(shtr_isotope_metadata_get_molecule(mdata2, imol, &mol2) == RES_OK); 298 CHK(!strcmp(mol1.name, mol2.name)); 299 CHK(mol1.id == mol2.id); 300 CHK(mol1.nisotopes == mol2.nisotopes); 301 niso = mol1.nisotopes; 302 303 FOR_EACH(iiso, 0, niso) { 304 CHK(mol1.isotopes[iiso].abundance == mol2.isotopes[iiso].abundance); 305 CHK(mol1.isotopes[iiso].Q296K == mol2.isotopes[iiso].Q296K); 306 CHK(mol1.isotopes[iiso].molar_mass == mol2.isotopes[iiso].molar_mass); 307 CHK(mol1.isotopes[iiso].molecule_id_local == mol2.isotopes[iiso].molecule_id_local); 308 CHK(mol1.isotopes[iiso].gj == mol2.isotopes[iiso].gj); 309 CHK(mol1.isotopes[iiso].id == mol2.isotopes[iiso].id); 310 } 311 } 312 313 CHK(shtr_isotope_metadata_hash(mdata1, hash1) == RES_OK); 314 CHK(shtr_isotope_metadata_hash(mdata2, hash2) == RES_OK); 315 CHK(hash256_eq(hash1, hash2) != 0); 316 } 317 318 static void 319 test_hash(struct shtr* shtr) 320 { 321 struct shtr_molecule CO2_custom = SHTR_MOLECULE_NULL; 322 struct shtr_isotope isotopes_custom[SHTR_MAX_ISOTOPE_COUNT]; 323 324 struct shtr_isotope_metadata* mdata1 = NULL; 325 struct shtr_isotope_metadata* mdata2 = NULL; 326 struct shtr_isotope_metadata* mdata3 = NULL; 327 struct shtr_isotope_metadata* mdata4 = NULL; 328 struct shtr_isotope_metadata* mdata5 = NULL; 329 struct shtr_isotope_metadata* mdata6 = NULL; 330 hash256_T hash1; 331 hash256_T hash2; 332 hash256_T hash3; 333 hash256_T hash4; 334 hash256_T hash5; 335 hash256_T hash6; 336 FILE* fp = NULL; 337 size_t i = 0; 338 339 /* Setup the metadata of the H2O and the CO2 molecules */ 340 CHK(fp = tmpfile()); 341 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 342 molecule_print(fp, &H2O); 343 molecule_print(fp, &CO2); 344 rewind(fp); 345 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata1) == RES_OK); 346 CHK(fclose(fp) == 0); 347 348 /* Check the hash API */ 349 CHK(shtr_isotope_metadata_hash(NULL, hash1) == RES_BAD_ARG); 350 CHK(shtr_isotope_metadata_hash(mdata1, NULL) == RES_BAD_ARG); 351 CHK(shtr_isotope_metadata_hash(mdata1, hash1) == RES_OK); 352 353 /* Setup the same metadata of the first one, in the same order */ 354 CHK(fp = tmpfile()); 355 fprintf(fp, "Molecule # Dummy comment\n"); 356 molecule_print(fp, &H2O); 357 molecule_print(fp, &CO2); 358 rewind(fp); 359 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata2) == RES_OK); 360 CHK(fclose(fp) == 0); 361 362 CHK(shtr_isotope_metadata_hash(mdata2, hash2) == RES_OK); 363 CHK(hash256_eq(hash2, hash1) != 0); 364 365 /* Configure metadata for H2O and CO2 molecules but in a different order. 366 * This may not change the hash */ 367 CHK(fp = tmpfile()); 368 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 369 molecule_print(fp, &CO2); 370 molecule_print(fp, &H2O); 371 rewind(fp); 372 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata3) == RES_OK); 373 CHK(fclose(fp) == 0); 374 375 CHK(shtr_isotope_metadata_hash(mdata3, hash3) == RES_OK); 376 CHK(hash256_eq(hash3, hash1) != 0); 377 378 /* Configure metadata for CO2 */ 379 CHK(fp = tmpfile()); 380 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 381 molecule_print(fp, &CO2); 382 rewind(fp); 383 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata4) == RES_OK); 384 CHK(fclose(fp) == 0); 385 386 CHK(shtr_isotope_metadata_hash(mdata4, hash4) == RES_OK); 387 CHK(hash256_eq(hash4, hash1) == 0); 388 389 /* Configure metadata for CO2 but print its isotope in different order. 390 * This may not change the hash */ 391 CO2_custom = CO2; 392 CO2_custom.isotopes = isotopes_custom; 393 FOR_EACH(i, 0, CO2.nisotopes) { 394 isotopes_custom[i] = CO2_isotopes[CO2.nisotopes-i-1]; 395 } 396 CHK(fp = tmpfile()); 397 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 398 molecule_print(fp, &CO2_custom); 399 rewind(fp); 400 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata5) == RES_OK); 401 CHK(fclose(fp) == 0); 402 403 CHK(shtr_isotope_metadata_hash(mdata5, hash5) == RES_OK); 404 CHK(hash256_eq(hash5, hash4) != 0); 405 406 /* Configure metadata for CO2 with only few isotopes */ 407 CO2_custom.nisotopes = CO2_custom.nisotopes/4; 408 CHK(fp = tmpfile()); 409 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 410 molecule_print(fp, &CO2_custom); 411 rewind(fp); 412 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata6) == RES_OK); 413 CHK(fclose(fp) == 0); 414 415 CHK(shtr_isotope_metadata_hash(mdata6, hash6) == RES_OK); 416 CHK(hash256_eq(hash6, hash5) == 0); 417 418 CHK(shtr_isotope_metadata_ref_put(mdata1) == RES_OK); 419 CHK(shtr_isotope_metadata_ref_put(mdata2) == RES_OK); 420 CHK(shtr_isotope_metadata_ref_put(mdata3) == RES_OK); 421 CHK(shtr_isotope_metadata_ref_put(mdata4) == RES_OK); 422 CHK(shtr_isotope_metadata_ref_put(mdata5) == RES_OK); 423 CHK(shtr_isotope_metadata_ref_put(mdata6) == RES_OK); 424 } 425 426 static void 427 test_serialization(struct shtr* shtr) 428 { 429 struct shtr_isotope_metadata* mdata1 = NULL; 430 struct shtr_isotope_metadata* mdata2 = NULL; 431 FILE* fp = NULL; 432 433 CHK(fp = tmpfile()); 434 435 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 436 molecule_print(fp, &H2O); 437 molecule_print(fp, &CO2); 438 rewind(fp); 439 440 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata1) == RES_OK); 441 fclose(fp); 442 443 CHK(fp = tmpfile()); 444 CHK(shtr_isotope_metadata_write(NULL, fp) == RES_BAD_ARG); 445 CHK(shtr_isotope_metadata_write(mdata1, NULL) == RES_BAD_ARG); 446 CHK(shtr_isotope_metadata_write(mdata1, fp) == RES_OK); 447 rewind(fp); 448 449 CHK(shtr_isotope_metadata_create_from_stream(NULL, fp, &mdata2) == RES_BAD_ARG); 450 CHK(shtr_isotope_metadata_create_from_stream(shtr, NULL, &mdata2) == RES_BAD_ARG); 451 CHK(shtr_isotope_metadata_create_from_stream(shtr, fp, NULL) == RES_BAD_ARG); 452 CHK(shtr_isotope_metadata_create_from_stream(shtr, fp, &mdata2) == RES_OK); 453 fclose(fp); 454 455 check_equality(mdata1, mdata2); 456 457 CHK(shtr_isotope_metadata_ref_put(mdata1) == RES_OK); 458 CHK(shtr_isotope_metadata_ref_put(mdata2) == RES_OK); 459 } 460 461 static void 462 test_load_failures(struct shtr* shtr) 463 { 464 struct shtr_isotope CO2_too_many_isotopes[SHTR_MAX_ISOTOPE_COUNT+1] = {0}; 465 struct shtr_molecule CO2_bad = SHTR_MOLECULE_NULL; 466 467 struct shtr_isotope isotope = SHTR_ISOTOPE_NULL; 468 struct shtr_isotope_metadata* mdata = NULL; 469 FILE* fp = NULL; 470 size_t i = 0; 471 472 CHK(shtr); 473 474 /* 1st line is missing */ 475 CHK(fp = tmpfile()); 476 molecule_print(fp, &H2O); 477 rewind(fp); 478 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); 479 CHK(fclose(fp) == 0); 480 481 /* Invalid molecule id */ 482 CHK(fp = tmpfile()); 483 fprintf(fp, "Comment line\n"); 484 fprintf(fp, "H2O 1\n"); 485 isotope_print(fp, &H2O_isotopes[0]); 486 rewind(fp); 487 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); 488 rewind(fp); 489 fprintf(fp, "Comment line\n"); 490 fprintf(fp, "H2O (-1)\n"); 491 isotope_print(fp, &H2O_isotopes[0]); 492 rewind(fp); 493 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); 494 CHK(fclose(fp) == 0); 495 496 /* Invalid isotope id */ 497 CHK(fp = tmpfile()); 498 fprintf(fp, "Comment line\n"); 499 fprintf(fp, "H2O (1)\n"); 500 isotope = H2O_isotopes[0]; 501 isotope.id = -1; 502 isotope_print(fp, &isotope); 503 rewind(fp); 504 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); 505 CHK(fclose(fp) == 0); 506 507 /* Invalid abundance */ 508 CHK(fp = tmpfile()); 509 fprintf(fp, "Comment line\n"); 510 fprintf(fp, "H2O (1)\n"); 511 isotope = H2O_isotopes[0]; 512 isotope.abundance = 0; 513 isotope_print(fp, &isotope); 514 rewind(fp); 515 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); 516 CHK(fclose(fp) == 0); 517 CHK(fp = tmpfile()); 518 fprintf(fp, "Comment line\n"); 519 fprintf(fp, "H2O (1)\n"); 520 isotope.abundance = 1.00001; 521 isotope_print(fp, &isotope); 522 rewind(fp); 523 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); 524 CHK(fclose(fp) == 0); 525 526 /* Invalid Q(296K) */ 527 CHK(fp = tmpfile()); 528 fprintf(fp, "Comment line\n"); 529 fprintf(fp, "H2O (1)\n"); 530 isotope = H2O_isotopes[0]; 531 isotope.Q296K = 0; 532 isotope_print(fp, &isotope); 533 rewind(fp); 534 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); 535 CHK(fclose(fp) == 0); 536 537 /* Invalid molar mass */ 538 CHK(fp = tmpfile()); 539 fprintf(fp, "Comment line\n"); 540 fprintf(fp, "H2O (1)\n"); 541 isotope = H2O_isotopes[0]; 542 isotope.molar_mass = 0; 543 isotope_print(fp, &isotope); 544 rewind(fp); 545 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); 546 CHK(fclose(fp) == 0); 547 548 /* Too many isotope for a molecule */ 549 FOR_EACH(i, 0, SHTR_MAX_ISOTOPE_COUNT+1) { 550 CO2_too_many_isotopes[i] = CO2_isotopes[i % CO2.nisotopes]; 551 CO2_too_many_isotopes[i].abundance = 1.0/(double)(SHTR_MAX_ISOTOPE_COUNT+1); 552 } 553 CHK(fp = tmpfile()); 554 CO2_bad = CO2; 555 CO2_bad.nisotopes = SHTR_MAX_ISOTOPE_COUNT+1; 556 CO2_bad.isotopes = CO2_too_many_isotopes; 557 fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 558 molecule_print(fp, &CO2_bad); 559 rewind(fp); 560 CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_MEM_ERR); 561 CHK(fclose(fp) == 0); 562 } 563 564 static void 565 test_load_file(struct shtr* shtr, const char* path) 566 { 567 struct shtr_isotope_metadata* mdata = NULL; 568 size_t i, n; 569 CHK(path); 570 printf("Loading `%s'.\n", path); 571 CHK(shtr_isotope_metadata_load(shtr, path, &mdata) == RES_OK); 572 CHK(shtr_isotope_metadata_get_molecules_count(mdata, &n) == RES_OK); 573 printf(" #molecules: %lu\n", n); 574 FOR_EACH(i, 0, n) { 575 struct shtr_molecule molecule = SHTR_MOLECULE_NULL; 576 CHK(shtr_isotope_metadata_get_molecule(mdata, i, &molecule) == RES_OK); 577 printf(" Checking %s\n", molecule.name); 578 check_molecule(mdata, &molecule); 579 } 580 CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); 581 } 582 583 int 584 main(int argc, char** argv) 585 { 586 struct shtr_create_args args = SHTR_CREATE_ARGS_DEFAULT; 587 struct shtr* shtr = NULL; 588 int i; 589 (void)argc, (void)argv; 590 591 args.verbose = 1; 592 CHK(shtr_create(&args, &shtr) == RES_OK); 593 594 test_load(shtr); 595 test_load_failures(shtr); 596 test_hash(shtr); 597 test_serialization(shtr); 598 FOR_EACH(i, 1, argc) { 599 test_load_file(shtr, argv[i]); 600 } 601 602 CHK(shtr_ref_put(shtr) == RES_OK); 603 CHK(mem_allocated_size() == 0); 604 return 0; 605 }