MetadataFormatHelperTests.cpp
1 #include "pch.h" 2 #include "MetadataFormatHelper.h" 3 #include <cmath> 4 5 using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 using namespace PowerRenameLib; 7 8 namespace MetadataFormatHelperTests 9 { 10 TEST_CLASS(FormatApertureTests) 11 { 12 public: 13 TEST_METHOD(FormatAperture_ValidValue) 14 { 15 // Test formatting a typical aperture value 16 std::wstring result = MetadataFormatHelper::FormatAperture(2.8); 17 Assert::AreEqual(L"f/2.8", result.c_str()); 18 } 19 20 TEST_METHOD(FormatAperture_SmallValue) 21 { 22 // Test small aperture (large f-number) 23 std::wstring result = MetadataFormatHelper::FormatAperture(1.4); 24 Assert::AreEqual(L"f/1.4", result.c_str()); 25 } 26 27 TEST_METHOD(FormatAperture_LargeValue) 28 { 29 // Test large aperture (small f-number) 30 std::wstring result = MetadataFormatHelper::FormatAperture(22.0); 31 Assert::AreEqual(L"f/22.0", result.c_str()); 32 } 33 34 TEST_METHOD(FormatAperture_RoundedValue) 35 { 36 // Test rounding to one decimal place 37 std::wstring result = MetadataFormatHelper::FormatAperture(5.66666); 38 Assert::AreEqual(L"f/5.7", result.c_str()); 39 } 40 41 TEST_METHOD(FormatAperture_Zero) 42 { 43 // Test zero value 44 std::wstring result = MetadataFormatHelper::FormatAperture(0.0); 45 Assert::AreEqual(L"f/0.0", result.c_str()); 46 } 47 }; 48 49 TEST_CLASS(FormatShutterSpeedTests) 50 { 51 public: 52 TEST_METHOD(FormatShutterSpeed_FastSpeed) 53 { 54 // Test fast shutter speed (fraction of second) 55 std::wstring result = MetadataFormatHelper::FormatShutterSpeed(0.002); 56 Assert::AreEqual(L"1/500s", result.c_str()); 57 } 58 59 TEST_METHOD(FormatShutterSpeed_VeryFastSpeed) 60 { 61 // Test very fast shutter speed 62 std::wstring result = MetadataFormatHelper::FormatShutterSpeed(0.0001); 63 Assert::AreEqual(L"1/10000s", result.c_str()); 64 } 65 66 TEST_METHOD(FormatShutterSpeed_SlowSpeed) 67 { 68 // Test slow shutter speed (more than 1 second) 69 std::wstring result = MetadataFormatHelper::FormatShutterSpeed(2.5); 70 Assert::AreEqual(L"2.5s", result.c_str()); 71 } 72 73 TEST_METHOD(FormatShutterSpeed_OneSecond) 74 { 75 // Test exactly 1 second 76 std::wstring result = MetadataFormatHelper::FormatShutterSpeed(1.0); 77 Assert::AreEqual(L"1.0s", result.c_str()); 78 } 79 80 TEST_METHOD(FormatShutterSpeed_VerySlowSpeed) 81 { 82 // Test very slow shutter speed (< 1 second but close) 83 std::wstring result = MetadataFormatHelper::FormatShutterSpeed(0.5); 84 Assert::AreEqual(L"1/2s", result.c_str()); 85 } 86 87 TEST_METHOD(FormatShutterSpeed_Zero) 88 { 89 // Test zero value 90 std::wstring result = MetadataFormatHelper::FormatShutterSpeed(0.0); 91 Assert::AreEqual(L"0", result.c_str()); 92 } 93 94 TEST_METHOD(FormatShutterSpeed_Negative) 95 { 96 // Test negative value (invalid but should handle gracefully) 97 std::wstring result = MetadataFormatHelper::FormatShutterSpeed(-1.0); 98 Assert::AreEqual(L"0", result.c_str()); 99 } 100 }; 101 102 TEST_CLASS(FormatISOTests) 103 { 104 public: 105 TEST_METHOD(FormatISO_TypicalValue) 106 { 107 // Test typical ISO value 108 std::wstring result = MetadataFormatHelper::FormatISO(400); 109 Assert::AreEqual(L"ISO 400", result.c_str()); 110 } 111 112 TEST_METHOD(FormatISO_LowValue) 113 { 114 // Test low ISO value 115 std::wstring result = MetadataFormatHelper::FormatISO(100); 116 Assert::AreEqual(L"ISO 100", result.c_str()); 117 } 118 119 TEST_METHOD(FormatISO_HighValue) 120 { 121 // Test high ISO value 122 std::wstring result = MetadataFormatHelper::FormatISO(12800); 123 Assert::AreEqual(L"ISO 12800", result.c_str()); 124 } 125 126 TEST_METHOD(FormatISO_Zero) 127 { 128 // Test zero value 129 std::wstring result = MetadataFormatHelper::FormatISO(0); 130 Assert::AreEqual(L"ISO", result.c_str()); 131 } 132 133 TEST_METHOD(FormatISO_Negative) 134 { 135 // Test negative value (invalid but should handle gracefully) 136 std::wstring result = MetadataFormatHelper::FormatISO(-100); 137 Assert::AreEqual(L"ISO", result.c_str()); 138 } 139 }; 140 141 TEST_CLASS(FormatFlashTests) 142 { 143 public: 144 TEST_METHOD(FormatFlash_Off) 145 { 146 // Test flash off (bit 0 = 0) 147 std::wstring result = MetadataFormatHelper::FormatFlash(0x0); 148 Assert::AreEqual(L"Flash Off", result.c_str()); 149 } 150 151 TEST_METHOD(FormatFlash_On) 152 { 153 // Test flash on (bit 0 = 1) 154 std::wstring result = MetadataFormatHelper::FormatFlash(0x1); 155 Assert::AreEqual(L"Flash On", result.c_str()); 156 } 157 158 TEST_METHOD(FormatFlash_OnWithAdditionalFlags) 159 { 160 // Test flash on with additional flags 161 std::wstring result = MetadataFormatHelper::FormatFlash(0x5); // 0b0101 = fired, return detected 162 Assert::AreEqual(L"Flash On", result.c_str()); 163 } 164 165 TEST_METHOD(FormatFlash_OffWithAdditionalFlags) 166 { 167 // Test flash off with additional flags 168 std::wstring result = MetadataFormatHelper::FormatFlash(0x10); // Bit 0 is 0 169 Assert::AreEqual(L"Flash Off", result.c_str()); 170 } 171 }; 172 173 TEST_CLASS(FormatCoordinateTests) 174 { 175 public: 176 TEST_METHOD(FormatCoordinate_NorthLatitude) 177 { 178 // Test north latitude 179 std::wstring result = MetadataFormatHelper::FormatCoordinate(40.7128, true); 180 Assert::AreEqual(L"40°42.77'N", result.c_str()); 181 } 182 183 TEST_METHOD(FormatCoordinate_SouthLatitude) 184 { 185 // Test south latitude 186 std::wstring result = MetadataFormatHelper::FormatCoordinate(-33.8688, true); 187 Assert::AreEqual(L"33°52.13'S", result.c_str()); 188 } 189 190 TEST_METHOD(FormatCoordinate_EastLongitude) 191 { 192 // Test east longitude 193 std::wstring result = MetadataFormatHelper::FormatCoordinate(151.2093, false); 194 Assert::AreEqual(L"151°12.56'E", result.c_str()); 195 } 196 197 TEST_METHOD(FormatCoordinate_WestLongitude) 198 { 199 // Test west longitude 200 std::wstring result = MetadataFormatHelper::FormatCoordinate(-74.0060, false); 201 Assert::AreEqual(L"74°0.36'W", result.c_str()); 202 } 203 204 TEST_METHOD(FormatCoordinate_ZeroLatitude) 205 { 206 // Test equator (0 degrees latitude) 207 std::wstring result = MetadataFormatHelper::FormatCoordinate(0.0, true); 208 Assert::AreEqual(L"0°0.00'N", result.c_str()); 209 } 210 211 TEST_METHOD(FormatCoordinate_ZeroLongitude) 212 { 213 // Test prime meridian (0 degrees longitude) 214 std::wstring result = MetadataFormatHelper::FormatCoordinate(0.0, false); 215 Assert::AreEqual(L"0°0.00'E", result.c_str()); 216 } 217 }; 218 219 TEST_CLASS(FormatSystemTimeTests) 220 { 221 public: 222 TEST_METHOD(FormatSystemTime_ValidDateTime) 223 { 224 // Test formatting a valid date and time 225 SYSTEMTIME st = { 0 }; 226 st.wYear = 2024; 227 st.wMonth = 3; 228 st.wDay = 15; 229 st.wHour = 14; 230 st.wMinute = 30; 231 st.wSecond = 45; 232 233 std::wstring result = MetadataFormatHelper::FormatSystemTime(st); 234 Assert::AreEqual(L"2024-03-15 14:30:45", result.c_str()); 235 } 236 237 TEST_METHOD(FormatSystemTime_Midnight) 238 { 239 // Test midnight time 240 SYSTEMTIME st = { 0 }; 241 st.wYear = 2024; 242 st.wMonth = 1; 243 st.wDay = 1; 244 st.wHour = 0; 245 st.wMinute = 0; 246 st.wSecond = 0; 247 248 std::wstring result = MetadataFormatHelper::FormatSystemTime(st); 249 Assert::AreEqual(L"2024-01-01 00:00:00", result.c_str()); 250 } 251 252 TEST_METHOD(FormatSystemTime_EndOfDay) 253 { 254 // Test end of day time 255 SYSTEMTIME st = { 0 }; 256 st.wYear = 2024; 257 st.wMonth = 12; 258 st.wDay = 31; 259 st.wHour = 23; 260 st.wMinute = 59; 261 st.wSecond = 59; 262 263 std::wstring result = MetadataFormatHelper::FormatSystemTime(st); 264 Assert::AreEqual(L"2024-12-31 23:59:59", result.c_str()); 265 } 266 }; 267 268 TEST_CLASS(ParseSingleRationalTests) 269 { 270 public: 271 TEST_METHOD(ParseSingleRational_ValidValue) 272 { 273 // Test parsing a valid rational: 5/2 = 2.5 274 uint8_t bytes[] = { 5, 0, 0, 0, 2, 0, 0, 0 }; 275 double result = MetadataFormatHelper::ParseSingleRational(bytes, 0); 276 Assert::AreEqual(2.5, result, 0.001); 277 } 278 279 TEST_METHOD(ParseSingleRational_IntegerResult) 280 { 281 // Test parsing rational that results in integer: 10/5 = 2.0 282 uint8_t bytes[] = { 10, 0, 0, 0, 5, 0, 0, 0 }; 283 double result = MetadataFormatHelper::ParseSingleRational(bytes, 0); 284 Assert::AreEqual(2.0, result, 0.001); 285 } 286 287 TEST_METHOD(ParseSingleRational_LargeNumerator) 288 { 289 // Test parsing with large numerator: 1000/100 = 10.0 290 uint8_t bytes[] = { 0xE8, 0x03, 0, 0, 100, 0, 0, 0 }; // 1000 in little-endian 291 double result = MetadataFormatHelper::ParseSingleRational(bytes, 0); 292 Assert::AreEqual(10.0, result, 0.001); 293 } 294 295 TEST_METHOD(ParseSingleRational_ZeroDenominator) 296 { 297 // Test parsing with zero denominator (should return 0.0) 298 uint8_t bytes[] = { 5, 0, 0, 0, 0, 0, 0, 0 }; 299 double result = MetadataFormatHelper::ParseSingleRational(bytes, 0); 300 Assert::AreEqual(0.0, result, 0.001); 301 } 302 303 TEST_METHOD(ParseSingleRational_ZeroNumerator) 304 { 305 // Test parsing with zero numerator: 0/5 = 0.0 306 uint8_t bytes[] = { 0, 0, 0, 0, 5, 0, 0, 0 }; 307 double result = MetadataFormatHelper::ParseSingleRational(bytes, 0); 308 Assert::AreEqual(0.0, result, 0.001); 309 } 310 311 TEST_METHOD(ParseSingleRational_WithOffset) 312 { 313 // Test parsing with offset 314 uint8_t bytes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 10, 0, 0, 0, 5, 0, 0, 0 }; // Offset = 4 315 double result = MetadataFormatHelper::ParseSingleRational(bytes, 4); 316 Assert::AreEqual(2.0, result, 0.001); 317 } 318 319 TEST_METHOD(ParseSingleRational_NullPointer) 320 { 321 // Test with null pointer (should return 0.0) 322 double result = MetadataFormatHelper::ParseSingleRational(nullptr, 0); 323 Assert::AreEqual(0.0, result, 0.001); 324 } 325 }; 326 327 TEST_CLASS(ParseSingleSRationalTests) 328 { 329 public: 330 TEST_METHOD(ParseSingleSRational_PositiveValue) 331 { 332 // Test parsing positive signed rational: 5/2 = 2.5 333 uint8_t bytes[] = { 5, 0, 0, 0, 2, 0, 0, 0 }; 334 double result = MetadataFormatHelper::ParseSingleSRational(bytes, 0); 335 Assert::AreEqual(2.5, result, 0.001); 336 } 337 338 TEST_METHOD(ParseSingleSRational_NegativeNumerator) 339 { 340 // Test parsing negative numerator: -5/2 = -2.5 341 uint8_t bytes[] = { 0xFB, 0xFF, 0xFF, 0xFF, 2, 0, 0, 0 }; // -5 in two's complement 342 double result = MetadataFormatHelper::ParseSingleSRational(bytes, 0); 343 Assert::AreEqual(-2.5, result, 0.001); 344 } 345 346 TEST_METHOD(ParseSingleSRational_NegativeDenominator) 347 { 348 // Test parsing negative denominator: 5/-2 = -2.5 349 uint8_t bytes[] = { 5, 0, 0, 0, 0xFE, 0xFF, 0xFF, 0xFF }; // -2 in two's complement 350 double result = MetadataFormatHelper::ParseSingleSRational(bytes, 0); 351 Assert::AreEqual(-2.5, result, 0.001); 352 } 353 354 TEST_METHOD(ParseSingleSRational_BothNegative) 355 { 356 // Test parsing both negative: -5/-2 = 2.5 357 uint8_t bytes[] = { 0xFB, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF }; 358 double result = MetadataFormatHelper::ParseSingleSRational(bytes, 0); 359 Assert::AreEqual(2.5, result, 0.001); 360 } 361 362 TEST_METHOD(ParseSingleSRational_ExposureBias) 363 { 364 // Test typical exposure bias value: -1/3 ≈ -0.333 365 uint8_t bytes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 3, 0, 0, 0 }; // -1/3 366 double result = MetadataFormatHelper::ParseSingleSRational(bytes, 0); 367 Assert::AreEqual(-0.333, result, 0.001); 368 } 369 370 TEST_METHOD(ParseSingleSRational_ZeroDenominator) 371 { 372 // Test with zero denominator (should return 0.0) 373 uint8_t bytes[] = { 5, 0, 0, 0, 0, 0, 0, 0 }; 374 double result = MetadataFormatHelper::ParseSingleSRational(bytes, 0); 375 Assert::AreEqual(0.0, result, 0.001); 376 } 377 378 TEST_METHOD(ParseSingleSRational_NullPointer) 379 { 380 // Test with null pointer (should return 0.0) 381 double result = MetadataFormatHelper::ParseSingleSRational(nullptr, 0); 382 Assert::AreEqual(0.0, result, 0.001); 383 } 384 }; 385 386 TEST_CLASS(SanitizeForFileNameTests) 387 { 388 public: 389 TEST_METHOD(SanitizeForFileName_ValidString) 390 { 391 // Test string without illegal characters 392 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"Canon EOS 5D"); 393 Assert::AreEqual(L"Canon EOS 5D", result.c_str()); 394 } 395 396 TEST_METHOD(SanitizeForFileName_WithColon) 397 { 398 // Test string with colon (illegal character) 399 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"Photo:001"); 400 Assert::AreEqual(L"Photo_001", result.c_str()); 401 } 402 403 TEST_METHOD(SanitizeForFileName_WithSlashes) 404 { 405 // Test string with forward and backward slashes 406 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"Photos/2024\\January"); 407 Assert::AreEqual(L"Photos_2024_January", result.c_str()); 408 } 409 410 TEST_METHOD(SanitizeForFileName_WithMultipleIllegalChars) 411 { 412 // Test string with multiple illegal characters 413 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"<Test>:File|Name*?.txt"); 414 Assert::AreEqual(L"_Test__File_Name__.txt", result.c_str()); 415 } 416 417 TEST_METHOD(SanitizeForFileName_WithQuotes) 418 { 419 // Test string with quotes 420 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"Photo \"Best Shot\""); 421 Assert::AreEqual(L"Photo _Best Shot_", result.c_str()); 422 } 423 424 TEST_METHOD(SanitizeForFileName_WithTrailingDot) 425 { 426 // Test string with trailing dot (should be removed) 427 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"filename."); 428 Assert::AreEqual(L"filename", result.c_str()); 429 } 430 431 TEST_METHOD(SanitizeForFileName_WithTrailingSpace) 432 { 433 // Test string with trailing space (should be removed) 434 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"filename "); 435 Assert::AreEqual(L"filename", result.c_str()); 436 } 437 438 TEST_METHOD(SanitizeForFileName_WithMultipleTrailingDotsAndSpaces) 439 { 440 // Test string with multiple trailing dots and spaces 441 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"filename. . "); 442 Assert::AreEqual(L"filename", result.c_str()); 443 } 444 445 TEST_METHOD(SanitizeForFileName_WithControlCharacters) 446 { 447 // Test string with control characters 448 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"File\x01Name\x1F"); 449 Assert::AreEqual(L"File_Name_", result.c_str()); 450 } 451 452 TEST_METHOD(SanitizeForFileName_EmptyString) 453 { 454 // Test empty string 455 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L""); 456 Assert::AreEqual(L"", result.c_str()); 457 } 458 459 TEST_METHOD(SanitizeForFileName_OnlyIllegalCharacters) 460 { 461 // Test string with only illegal characters 462 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"<>:\"/\\|?*"); 463 Assert::AreEqual(L"_________", result.c_str()); 464 } 465 466 TEST_METHOD(SanitizeForFileName_OnlyTrailingCharacters) 467 { 468 // Test string with only dots and spaces (should return empty) 469 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L". . "); 470 Assert::AreEqual(L"", result.c_str()); 471 } 472 473 TEST_METHOD(SanitizeForFileName_UnicodeCharacters) 474 { 475 // Test string with valid Unicode characters 476 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"照片_2024年"); 477 Assert::AreEqual(L"照片_2024年", result.c_str()); 478 } 479 480 TEST_METHOD(SanitizeForFileName_MixedContent) 481 { 482 // Test realistic metadata string with multiple issues 483 std::wstring result = MetadataFormatHelper::SanitizeForFileName(L"Copyright © 2024: John/Jane Doe. "); 484 Assert::AreEqual(L"Copyright © 2024_ John_Jane Doe", result.c_str()); 485 } 486 }; 487 }