/* ©AngelaMos | 2026 test_engine.cpp End-to-end tests for the crack engine Verifies Engine::crack with SHA256Hasher + DictionaryAttack finds "password" from the test wordlist. Confirms CrackError::Exhausted when the target hash is not in the wordlist. Tests salt support by cracking a prepend-salted hash. Connects to: core/Engine.hpp - Engine::crack tested hash/SHA256Hasher.hpp - SHA256Hasher used in all tests attack/DictionaryAttack.hpp - DictionaryAttack as the attack strategy tests/data/small_wordlist.txt - fixture wordlist */ #include "src/core/Engine.hpp" #include "src/hash/SHA256Hasher.hpp" #include TEST(EngineTest, CracksSHA256WithDictionary) { CrackConfig cfg; cfg.target_hash = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"; cfg.wordlist_path = "tests/data/small_wordlist.txt"; cfg.thread_count = 2; auto result = Engine::crack(cfg); ASSERT_TRUE(result.has_value()); EXPECT_EQ(result->plaintext, "password"); } TEST(EngineTest, ReturnsExhaustedWhenNotFound) { CrackConfig cfg; cfg.target_hash = std::string(64, 'f'); cfg.wordlist_path = "tests/data/small_wordlist.txt"; cfg.thread_count = 1; auto result = Engine::crack(cfg); EXPECT_FALSE(result.has_value()); EXPECT_EQ(result.error(), CrackError::Exhausted); } TEST(EngineTest, CracksWithSalt) { SHA256Hasher hasher; auto salted_hash = hasher.hash("saltpassword"); CrackConfig cfg; cfg.target_hash = salted_hash; cfg.wordlist_path = "tests/data/small_wordlist.txt"; cfg.salt = "salt"; cfg.salt_position = "prepend"; cfg.thread_count = 1; auto result = Engine::crack(cfg); ASSERT_TRUE(result.has_value()); EXPECT_EQ(result->plaintext, "password"); }