1#include "factory.h" 2#include "integer.h" 3#include "filters.h" 4#include "hex.h" 5#include "randpool.h" 6#include "files.h" 7#include "trunhash.h" 8#include "queue.h" 9#include "validate.h" 10#include <iostream> 11#include <memory> 12 13USING_NAMESPACE(CryptoPP) 14USING_NAMESPACE(std) 15 16typedef std::map<std::string, std::string> TestData; 17 18class TestFailure : public Exception 19{ 20public: 21 TestFailure() : Exception(OTHER_ERROR, "Validation test failed") {} 22}; 23 24static const TestData *s_currentTestData = NULL; 25 26static void OutputTestData(const TestData &v) 27{ 28 for (TestData::const_iterator i = v.begin(); i != v.end(); ++i) 29 { 30 cerr << i->first << ": " << i->second << endl; 31 } 32} 33 34static void SignalTestFailure() 35{ 36 OutputTestData(*s_currentTestData); 37 throw TestFailure(); 38} 39 40static void SignalTestError() 41{ 42 OutputTestData(*s_currentTestData); 43 throw Exception(Exception::OTHER_ERROR, "Unexpected error during validation test"); 44} 45 46bool DataExists(const TestData &data, const char *name) 47{ 48 TestData::const_iterator i = data.find(name); 49 return (i != data.end()); 50} 51 52const std::string & GetRequiredDatum(const TestData &data, const char *name) 53{ 54 TestData::const_iterator i = data.find(name); 55 if (i == data.end()) 56 SignalTestError(); 57 return i->second; 58} 59 60void PutDecodedDatumInto(const TestData &data, const char *name, BufferedTransformation &target) 61{ 62 std::string s1 = GetRequiredDatum(data, name), s2; 63 64 while (!s1.empty()) 65 { 66 while (s1[0] == ' ') 67 s1 = s1.substr(1); 68 69 int repeat = 1; 70 if (s1[0] == 'r') 71 { 72 repeat = atoi(s1.c_str()+1); 73 s1 = s1.substr(s1.find(' ')+1); 74 } 75 76 s2 = ""; // MSVC 6 doesn't have clear(); 77 78 if (s1[0] == '\"') 79 { 80 s2 = s1.substr(1, s1.find('\"', 1)-1); 81 s1 = s1.substr(s2.length() + 2); 82 } 83 else if (s1.substr(0, 2) == "0x") 84 { 85 StringSource(s1.substr(2, s1.find(' ')), true, new HexDecoder(new StringSink(s2))); 86 s1 = s1.substr(STDMIN(s1.find(' '), s1.length())); 87 } 88 else 89 { 90 StringSource(s1.substr(0, s1.find(' ')), true, new HexDecoder(new StringSink(s2))); 91 s1 = s1.substr(STDMIN(s1.find(' '), s1.length())); 92 } 93 94 ByteQueue q; 95 while (repeat--) 96 { 97 q.Put((const byte *)s2.data(), s2.size()); 98 if (q.MaxRetrievable() > 4*1024 || repeat == 0) 99 q.TransferTo(target); 100 } 101 } 102} 103 104std::string GetDecodedDatum(const TestData &data, const char *name) 105{ 106 std::string s; 107 PutDecodedDatumInto(data, name, StringSink(s).Ref()); 108 return s; 109} 110 111std::string GetOptionalDecodedDatum(const TestData &data, const char *name) 112{ 113 std::string s; 114 if (DataExists(data, name)) 115 PutDecodedDatumInto(data, name, StringSink(s).Ref()); 116 return s; 117} 118 119class TestDataNameValuePairs : public NameValuePairs 120{ 121public: 122 TestDataNameValuePairs(const TestData &data) : m_data(data) {} 123 124 virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const 125 { 126 TestData::const_iterator i = m_data.find(name); 127 if (i == m_data.end()) 128 { 129 if (std::string(name) == Name::DigestSize() && valueType == typeid(int)) 130 { 131 i = m_data.find("MAC"); 132 if (i == m_data.end()) 133 i = m_data.find("Digest"); 134 if (i == m_data.end()) 135 return false; 136 137 m_temp.resize(0); 138 PutDecodedDatumInto(m_data, i->first.c_str(), StringSink(m_temp).Ref()); 139 *reinterpret_cast<int *>(pValue) = (int)m_temp.size(); 140 return true; 141 } 142 else 143 return false; 144 } 145 146 const std::string &value = i->second; 147 148 if (valueType == typeid(int)) 149 *reinterpret_cast<int *>(pValue) = atoi(value.c_str()); 150 else if (valueType == typeid(Integer)) 151 *reinterpret_cast<Integer *>(pValue) = Integer((std::string(value) + "h").c_str()); 152 else if (valueType == typeid(ConstByteArrayParameter)) 153 { 154 m_temp.resize(0); 155 PutDecodedDatumInto(m_data, name, StringSink(m_temp).Ref()); 156 reinterpret_cast<ConstByteArrayParameter *>(pValue)->Assign((const byte *)m_temp.data(), m_temp.size(), false); 157 } 158 else 159 throw ValueTypeMismatch(name, typeid(std::string), valueType); 160 161 return true; 162 } 163 164private: 165 const TestData &m_data; 166 mutable std::string m_temp; 167}; 168 169void TestKeyPairValidAndConsistent(CryptoMaterial &pub, const CryptoMaterial &priv) 170{ 171 if (!pub.Validate(GlobalRNG(), 3)) 172 SignalTestFailure(); 173 if (!priv.Validate(GlobalRNG(), 3)) 174 SignalTestFailure(); 175 176/* EqualityComparisonFilter comparison; 177 pub.Save(ChannelSwitch(comparison, "0")); 178 pub.AssignFrom(priv); 179 pub.Save(ChannelSwitch(comparison, "1")); 180 comparison.ChannelMessageSeriesEnd("0"); 181 comparison.ChannelMessageSeriesEnd("1"); 182*/ 183} 184 185void TestSignatureScheme(TestData &v) 186{ 187 std::string name = GetRequiredDatum(v, "Name"); 188 std::string test = GetRequiredDatum(v, "Test"); 189 190 std::auto_ptr<PK_Signer> signer(ObjectFactoryRegistry<PK_Signer>::Registry().CreateObject(name.c_str())); 191 std::auto_ptr<PK_Verifier> verifier(ObjectFactoryRegistry<PK_Verifier>::Registry().CreateObject(name.c_str())); 192 193 TestDataNameValuePairs pairs(v); 194 std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); 195 196 if (keyFormat == "DER") 197 verifier->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); 198 else if (keyFormat == "Component") 199 verifier->AccessMaterial().AssignFrom(pairs); 200 201 if (test == "Verify" || test == "NotVerify") 202 { 203 VerifierFilter verifierFilter(*verifier, NULL, VerifierFilter::SIGNATURE_AT_BEGIN); 204 PutDecodedDatumInto(v, "Signature", verifierFilter); 205 PutDecodedDatumInto(v, "Message", verifierFilter); 206 verifierFilter.MessageEnd(); 207 if (verifierFilter.GetLastResult() == (test == "NotVerify")) 208 SignalTestFailure(); 209 } 210 else if (test == "PublicKeyValid") 211 { 212 if (!verifier->GetMaterial().Validate(GlobalRNG(), 3)) 213 SignalTestFailure(); 214 } 215 else 216 goto privateKeyTests; 217 218 return; 219 220privateKeyTests: 221 if (keyFormat == "DER") 222 signer->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); 223 else if (keyFormat == "Component") 224 signer->AccessMaterial().AssignFrom(pairs); 225 226 if (test == "KeyPairValidAndConsistent") 227 { 228 TestKeyPairValidAndConsistent(verifier->AccessMaterial(), signer->GetMaterial()); 229 } 230 else if (test == "Sign") 231 { 232 SignerFilter f(GlobalRNG(), *signer, new HexEncoder(new FileSink(cout))); 233 StringSource ss(GetDecodedDatum(v, "Message"), true, new Redirector(f)); 234 SignalTestFailure(); 235 } 236 else if (test == "DeterministicSign") 237 { 238 SignalTestError(); 239 assert(false); // TODO: implement 240 } 241 else if (test == "RandomSign") 242 { 243 SignalTestError(); 244 assert(false); // TODO: implement 245 } 246 else if (test == "GenerateKey") 247 { 248 SignalTestError(); 249 assert(false); 250 } 251 else 252 { 253 SignalTestError(); 254 assert(false); 255 } 256} 257 258void TestAsymmetricCipher(TestData &v) 259{ 260 std::string name = GetRequiredDatum(v, "Name"); 261 std::string test = GetRequiredDatum(v, "Test"); 262 263 std::auto_ptr<PK_Encryptor> encryptor(ObjectFactoryRegistry<PK_Encryptor>::Registry().CreateObject(name.c_str())); 264 std::auto_ptr<PK_Decryptor> decryptor(ObjectFactoryRegistry<PK_Decryptor>::Registry().CreateObject(name.c_str())); 265 266 std::string keyFormat = GetRequiredDatum(v, "KeyFormat"); 267 268 if (keyFormat == "DER") 269 { 270 decryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PrivateKey")).Ref()); 271 encryptor->AccessMaterial().Load(StringStore(GetDecodedDatum(v, "PublicKey")).Ref()); 272 } 273 else if (keyFormat == "Component") 274 { 275 TestDataNameValuePairs pairs(v); 276 decryptor->AccessMaterial().AssignFrom(pairs); 277 encryptor->AccessMaterial().AssignFrom(pairs); 278 } 279 280 if (test == "DecryptMatch") 281 { 282 std::string decrypted, expected = GetDecodedDatum(v, "Plaintext"); 283 StringSource ss(GetDecodedDatum(v, "Ciphertext"), true, new PK_DecryptorFilter(GlobalRNG(), *decryptor, new StringSink(decrypted))); 284 if (decrypted != expected) 285 SignalTestFailure(); 286 } 287 else if (test == "KeyPairValidAndConsistent") 288 { 289 TestKeyPairValidAndConsistent(encryptor->AccessMaterial(), decryptor->GetMaterial()); 290 } 291 else 292 { 293 SignalTestError(); 294 assert(false); 295 } 296} 297 298void TestSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters) 299{ 300 std::string name = GetRequiredDatum(v, "Name"); 301 std::string test = GetRequiredDatum(v, "Test"); 302 303 std::string key = GetDecodedDatum(v, "Key"); 304 std::string plaintext = GetDecodedDatum(v, "Plaintext"); 305 306 TestDataNameValuePairs testDataPairs(v); 307 CombinedNameValuePairs pairs(overrideParameters, testDataPairs); 308 309 if (test == "Encrypt" || test == "EncryptXorDigest" || test == "Resync") 310 { 311 static member_ptr<SymmetricCipher> encryptor, decryptor; 312 static std::string lastName; 313 314 if (name != lastName) 315 { 316 encryptor.reset(ObjectFactoryRegistry<SymmetricCipher, ENCRYPTION>::Registry().CreateObject(name.c_str())); 317 decryptor.reset(ObjectFactoryRegistry<SymmetricCipher, DECRYPTION>::Registry().CreateObject(name.c_str())); 318 lastName = name; 319 } 320 321 ConstByteArrayParameter iv; 322 if (pairs.GetValue(Name::IV(), iv) && iv.size() != encryptor->IVSize()) 323 SignalTestFailure(); 324 325 if (test == "Resync") 326 { 327 encryptor->Resynchronize(iv.begin(), (int)iv.size()); 328 decryptor->Resynchronize(iv.begin(), (int)iv.size()); 329 } 330 else 331 { 332 encryptor->SetKey((const byte *)key.data(), key.size(), pairs); 333 decryptor->SetKey((const byte *)key.data(), key.size(), pairs); 334 } 335 336 int seek = pairs.GetIntValueWithDefault("Seek", 0); 337 if (seek) 338 { 339 encryptor->Seek(seek); 340 decryptor->Seek(seek); 341 } 342 std::string encrypted, xorDigest, ciphertext, ciphertextXorDigest; 343 StringSource ss(plaintext, false, new StreamTransformationFilter(*encryptor, new StringSink(encrypted), StreamTransformationFilter::NO_PADDING)); 344 ss.Pump(plaintext.size()/2 + 1); 345 ss.PumpAll(); 346 /*{ 347 std::string z; 348 encryptor->Seek(seek); 349 StringSource ss(plaintext, false, new StreamTransformationFilter(*encryptor, new StringSink(z), StreamTransformationFilter::NO_PADDING)); 350 while (ss.Pump(64)) {} 351 ss.PumpAll(); 352 for (int i=0; i<z.length(); i++) 353 assert(encrypted[i] == z[i]); 354 }*/ 355 if (test != "EncryptXorDigest") 356 ciphertext = GetDecodedDatum(v, "Ciphertext"); 357 else 358 { 359 ciphertextXorDigest = GetDecodedDatum(v, "CiphertextXorDigest"); 360 xorDigest.append(encrypted, 0, 64); 361 for (size_t i=64; i<encrypted.size(); i++) 362 xorDigest[i%64] ^= encrypted[i]; 363 } 364 if (test != "EncryptXorDigest" ? encrypted != ciphertext : xorDigest != ciphertextXorDigest) 365 { 366 std::cout << "incorrectly encrypted: "; 367 StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout))); 368 xx.Pump(256); xx.Flush(false); 369 std::cout << "\n"; 370 SignalTestFailure(); 371 } 372 std::string decrypted; 373 StringSource dd(encrypted, false, new StreamTransformationFilter(*decryptor, new StringSink(decrypted), StreamTransformationFilter::NO_PADDING)); 374 dd.Pump(plaintext.size()/2 + 1); 375 dd.PumpAll(); 376 if (decrypted != plaintext) 377 { 378 std::cout << "incorrectly decrypted: "; 379 StringSource xx(decrypted, false, new HexEncoder(new FileSink(std::cout))); 380 xx.Pump(256); xx.Flush(false); 381 std::cout << "\n"; 382 SignalTestFailure(); 383 } 384 } 385 else 386 { 387 std::cout << "unexpected test name\n"; 388 SignalTestError(); 389 } 390} 391 392void TestAuthenticatedSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters) 393{ 394 std::string type = GetRequiredDatum(v, "AlgorithmType"); 395 std::string name = GetRequiredDatum(v, "Name"); 396 std::string test = GetRequiredDatum(v, "Test"); 397 std::string key = GetDecodedDatum(v, "Key"); 398 399 std::string plaintext = GetOptionalDecodedDatum(v, "Plaintext"); 400 std::string ciphertext = GetOptionalDecodedDatum(v, "Ciphertext"); 401 std::string header = GetOptionalDecodedDatum(v, "Header"); 402 std::string footer = GetOptionalDecodedDatum(v, "Footer"); 403 std::string mac = GetOptionalDecodedDatum(v, "MAC"); 404 405 TestDataNameValuePairs testDataPairs(v); 406 CombinedNameValuePairs pairs(overrideParameters, testDataPairs); 407 408 if (test == "Encrypt" || test == "EncryptXorDigest" || test == "NotVerify") 409 { 410 member_ptr<AuthenticatedSymmetricCipher> asc1, asc2; 411 asc1.reset(ObjectFactoryRegistry<AuthenticatedSymmetricCipher, ENCRYPTION>::Registry().CreateObject(name.c_str())); 412 asc2.reset(ObjectFactoryRegistry<AuthenticatedSymmetricCipher, DECRYPTION>::Registry().CreateObject(name.c_str())); 413 asc1->SetKey((const byte *)key.data(), key.size(), pairs); 414 asc2->SetKey((const byte *)key.data(), key.size(), pairs); 415 416 std::string encrypted, decrypted; 417 AuthenticatedEncryptionFilter ef(*asc1, new StringSink(encrypted)); 418 bool macAtBegin = !mac.empty() && !GlobalRNG().GenerateBit(); // test both ways randomly 419 AuthenticatedDecryptionFilter df(*asc2, new StringSink(decrypted), macAtBegin ? AuthenticatedDecryptionFilter::MAC_AT_BEGIN : 0); 420 421 if (asc1->NeedsPrespecifiedDataLengths()) 422 { 423 asc1->SpecifyDataLengths(header.size(), plaintext.size(), footer.size()); 424 asc2->SpecifyDataLengths(header.size(), plaintext.size(), footer.size()); 425 } 426 427 StringStore sh(header), sp(plaintext), sc(ciphertext), sf(footer), sm(mac); 428 429 if (macAtBegin) 430 sm.TransferTo(df); 431 sh.CopyTo(df, LWORD_MAX, AAD_CHANNEL); 432 sc.TransferTo(df); 433 sf.CopyTo(df, LWORD_MAX, AAD_CHANNEL); 434 if (!macAtBegin) 435 sm.TransferTo(df); 436 df.MessageEnd(); 437 438 sh.TransferTo(ef, sh.MaxRetrievable()/2+1, AAD_CHANNEL); 439 sh.TransferTo(ef, LWORD_MAX, AAD_CHANNEL); 440 sp.TransferTo(ef, sp.MaxRetrievable()/2+1); 441 sp.TransferTo(ef); 442 sf.TransferTo(ef, sf.MaxRetrievable()/2+1, AAD_CHANNEL); 443 sf.TransferTo(ef, LWORD_MAX, AAD_CHANNEL); 444 ef.MessageEnd(); 445 446 if (test == "Encrypt" && encrypted != ciphertext+mac) 447 { 448 std::cout << "incorrectly encrypted: "; 449 StringSource xx(encrypted, false, new HexEncoder(new FileSink(std::cout))); 450 xx.Pump(256); xx.Flush(false); 451 std::cout << "\n"; 452 SignalTestFailure(); 453 } 454 if (test == "Encrypt" && decrypted != plaintext) 455 { 456 std::cout << "incorrectly decrypted: "; 457 StringSource xx(decrypted, false, new HexEncoder(new FileSink(std::cout))); 458 xx.Pump(256); xx.Flush(false); 459 std::cout << "\n"; 460 SignalTestFailure(); 461 } 462 463 if (ciphertext.size()+mac.size()-plaintext.size() != asc1->DigestSize()) 464 { 465 std::cout << "bad MAC size\n"; 466 SignalTestFailure(); 467 } 468 if (df.GetLastResult() != (test == "Encrypt")) 469 { 470 std::cout << "MAC incorrectly verified\n"; 471 SignalTestFailure(); 472 } 473 } 474 else 475 { 476 std::cout << "unexpected test name\n"; 477 SignalTestError(); 478 } 479} 480 481void TestDigestOrMAC(TestData &v, bool testDigest) 482{ 483 std::string name = GetRequiredDatum(v, "Name"); 484 std::string test = GetRequiredDatum(v, "Test"); 485 const char *digestName = testDigest ? "Digest" : "MAC"; 486 487 member_ptr<MessageAuthenticationCode> mac; 488 member_ptr<HashTransformation> hash; 489 HashTransformation *pHash = NULL; 490 491 TestDataNameValuePairs pairs(v); 492 493 if (testDigest) 494 { 495 hash.reset(ObjectFactoryRegistry<HashTransformation>::Registry().CreateObject(name.c_str())); 496 pHash = hash.get(); 497 } 498 else 499 { 500 mac.reset(ObjectFactoryRegistry<MessageAuthenticationCode>::Registry().CreateObject(name.c_str())); 501 pHash = mac.get(); 502 std::string key = GetDecodedDatum(v, "Key"); 503 mac->SetKey((const byte *)key.c_str(), key.size(), pairs); 504 } 505 506 if (test == "Verify" || test == "VerifyTruncated" || test == "NotVerify") 507 { 508 int digestSize = -1; 509 if (test == "VerifyTruncated") 510 pairs.GetIntValue(Name::DigestSize(), digestSize); 511 HashVerificationFilter verifierFilter(*pHash, NULL, HashVerificationFilter::HASH_AT_BEGIN, digestSize); 512 PutDecodedDatumInto(v, digestName, verifierFilter); 513 PutDecodedDatumInto(v, "Message", verifierFilter); 514 verifierFilter.MessageEnd(); 515 if (verifierFilter.GetLastResult() == (test == "NotVerify")) 516 SignalTestFailure(); 517 } 518 else 519 { 520 SignalTestError(); 521 assert(false); 522 } 523} 524 525bool GetField(std::istream &is, std::string &name, std::string &value) 526{ 527 name.resize(0); // GCC workaround: 2.95.3 doesn't have clear() 528 is >> name; 529 if (name.empty()) 530 return false; 531 532 if (name[name.size()-1] != ':') 533 { 534 char c; 535 is >> skipws >> c; 536 if (c != ':') 537 SignalTestError(); 538 } 539 else 540 name.erase(name.size()-1); 541 542 while (is.peek() == ' ') 543 is.ignore(1); 544 545 // VC60 workaround: getline bug 546 char buffer[128]; 547 value.resize(0); // GCC workaround: 2.95.3 doesn't have clear() 548 bool continueLine; 549 550 do 551 { 552 do 553 { 554 is.get(buffer, sizeof(buffer)); 555 value += buffer; 556 } 557 while (buffer[0] != 0); 558 is.clear(); 559 is.ignore(); 560 561 if (!value.empty() && value[value.size()-1] == '\r') 562 value.resize(value.size()-1); 563 564 if (!value.empty() && value[value.size()-1] == '\\') 565 { 566 value.resize(value.size()-1); 567 continueLine = true; 568 } 569 else 570 continueLine = false; 571 572 std::string::size_type i = value.find('#'); 573 if (i != std::string::npos) 574 value.erase(i); 575 } 576 while (continueLine); 577 578 return true; 579} 580 581void OutputPair(const NameValuePairs &v, const char *name) 582{ 583 Integer x; 584 bool b = v.GetValue(name, x); 585 assert(b); 586 cout << name << ": \\\n "; 587 x.Encode(HexEncoder(new FileSink(cout), false, 64, "\\\n ").Ref(), x.MinEncodedSize()); 588 cout << endl; 589} 590 591void OutputNameValuePairs(const NameValuePairs &v) 592{ 593 std::string names = v.GetValueNames(); 594 string::size_type i = 0; 595 while (i < names.size()) 596 { 597 string::size_type j = names.find_first_of (';', i); 598 599 if (j == string::npos) 600 return; 601 else 602 { 603 std::string name = names.substr(i, j-i); 604 if (name.find(':') == string::npos) 605 OutputPair(v, name.c_str()); 606 } 607 608 i = j + 1; 609 } 610} 611 612void TestDataFile(const std::string &filename, const NameValuePairs &overrideParameters, unsigned int &totalTests, unsigned int &failedTests) 613{ 614 std::ifstream file(filename.c_str()); 615 if (!file.good()) 616 throw Exception(Exception::OTHER_ERROR, "Can not open file " + filename + " for reading"); 617 TestData v; 618 s_currentTestData = &v; 619 std::string name, value, lastAlgName; 620 621 while (file) 622 { 623 while (file.peek() == '#') 624 file.ignore(INT_MAX, '\n'); 625 626 if (file.peek() == '\n' || file.peek() == '\r') 627 v.clear(); 628 629 if (!GetField(file, name, value)) 630 break; 631 v[name] = value; 632 633 if (name == "Test") 634 { 635 bool failed = true; 636 std::string algType = GetRequiredDatum(v, "AlgorithmType"); 637 638 if (lastAlgName != GetRequiredDatum(v, "Name")) 639 { 640 lastAlgName = GetRequiredDatum(v, "Name"); 641 cout << "\nTesting " << algType.c_str() << " algorithm " << lastAlgName.c_str() << ".\n"; 642 } 643 644 try 645 { 646 if (algType == "Signature") 647 TestSignatureScheme(v); 648 else if (algType == "SymmetricCipher") 649 TestSymmetricCipher(v, overrideParameters); 650 else if (algType == "AuthenticatedSymmetricCipher") 651 TestAuthenticatedSymmetricCipher(v, overrideParameters); 652 else if (algType == "AsymmetricCipher") 653 TestAsymmetricCipher(v); 654 else if (algType == "MessageDigest") 655 TestDigestOrMAC(v, true); 656 else if (algType == "MAC") 657 TestDigestOrMAC(v, false); 658 else if (algType == "FileList") 659 TestDataFile(GetRequiredDatum(v, "Test"), g_nullNameValuePairs, totalTests, failedTests); 660 else 661 SignalTestError(); 662 failed = false; 663 } 664 catch (TestFailure &) 665 { 666 cout << "\nTest failed.\n"; 667 } 668 catch (CryptoPP::Exception &e) 669 { 670 cout << "\nCryptoPP::Exception caught: " << e.what() << endl; 671 } 672 catch (std::exception &e) 673 { 674 cout << "\nstd::exception caught: " << e.what() << endl; 675 } 676 677 if (failed) 678 { 679 cout << "Skipping to next test.\n"; 680 failedTests++; 681 } 682 else 683 cout << "." << flush; 684 685 totalTests++; 686 } 687 } 688} 689 690bool RunTestDataFile(const char *filename, const NameValuePairs &overrideParameters) 691{ 692 unsigned int totalTests = 0, failedTests = 0; 693 TestDataFile(filename, overrideParameters, totalTests, failedTests); 694 cout << "\nTests complete. Total tests = " << totalTests << ". Failed tests = " << failedTests << ".\n"; 695 if (failedTests != 0) 696 cout << "SOME TESTS FAILED!\n"; 697 return failedTests == 0; 698} 699