diff --git a/score/hash/code/common/algorithms_test.cpp b/score/hash/code/common/algorithms_test.cpp index 7ef916084f..f09ba2e557 100644 --- a/score/hash/code/common/algorithms_test.cpp +++ b/score/hash/code/common/algorithms_test.cpp @@ -122,6 +122,13 @@ TEST(HashIdentify, CanNotIdentifyBadHashesFromSize) TEST(HashIdentify, CorrectSizes) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_bytes, comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that HashSizeInBytes()/HashSizeInCharacters() report the correct byte and hex-character " + "lengths for every supported algorithm, and report no value for kNone/kLast."); + const auto expected_sizes_bytes = std::map{ {HashAlgorithm::kCrc32, 4}, {HashAlgorithm::kCrc32Autosar, 4}, diff --git a/score/hash/code/core/factory/impl/hash_calculator_factory_ieee_test.cpp b/score/hash/code/core/factory/impl/hash_calculator_factory_ieee_test.cpp index 24f128b0e6..8957a55c24 100644 --- a/score/hash/code/core/factory/impl/hash_calculator_factory_ieee_test.cpp +++ b/score/hash/code/core/factory/impl/hash_calculator_factory_ieee_test.cpp @@ -37,6 +37,14 @@ TYPED_TEST_SUITE_P(HashCalculatorFactoryCreationTest); TYPED_TEST_P(HashCalculatorFactoryCreationTest, HashCalculatorFactorySuccessTest) { + this->RecordProperty("PartiallyVerifies", "comp_req__hash__factory_interface"); + this->RecordProperty("TestType", "requirements-based"); + this->RecordProperty("DerivationTechnique", "equivalence-classes"); + this->RecordProperty("Description", + "Check that the factory creates a hash calculator instance for a hash algorithm (SHA-256) " + "and a checksum algorithm (CRC-32) without the caller depending on the concrete " + "implementation type."); + for (auto algo : {HashAlgorithm::kSha256, HashAlgorithm::kCrc32}) { TypeParam unit{}; @@ -82,6 +90,13 @@ const std::vector data_and_digest{ TYPED_TEST_P(HashCalculatorFactoryCreationTest, CalculateSha256) { + this->RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface, comp_req__hash__sha_algorithms"); + this->RecordProperty("TestType", "requirements-based"); + this->RecordProperty("DerivationTechnique", "equivalence-classes"); + this->RecordProperty("Description", + "Check that a calculator created for SHA-256 computes the correct digest for inputs of " + "varying length, including multi-block inputs."); + TypeParam unit{}; for (const auto& dataset : data_and_digest) @@ -93,6 +108,11 @@ TYPED_TEST_P(HashCalculatorFactoryCreationTest, CalculateSha256) TYPED_TEST_P(HashCalculatorFactoryCreationTest, CalculateCrc32) { + this->RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface, comp_req__hash__crc32_algorithm"); + this->RecordProperty("TestType", "requirements-based"); + this->RecordProperty("DerivationTechnique", "equivalence-classes"); + this->RecordProperty("Description", "Check that a calculator created for CRC-32 computes the correct checksum."); + TypeParam unit{}; std::vector test_input{'1', '2', '3', 'a', 'b', 'c'}; @@ -106,6 +126,13 @@ TYPED_TEST_P(HashCalculatorFactoryCreationTest, CalculateCrc32) TYPED_TEST_P(HashCalculatorFactoryCreationTest, Crc32AutosarNotSupportedInIeeeVariant) { + this->RecordProperty("PartiallyVerifies", "comp_req__hash__crc32_algorithm"); + this->RecordProperty("TestType", "fault-injection"); + this->RecordProperty("DerivationTechnique", "boundary-values"); + this->RecordProperty("Description", + "Check that the IEEE-variant factory rejects the CRC-32-Autosar algorithm identifier, " + "since that variant is not supported by this factory."); + TypeParam unit{}; std::vector test_input{'1', '2', '3', 'a', 'b', 'c'}; score::cpp::span data(test_input); @@ -126,6 +153,13 @@ INSTANTIATE_TYPED_TEST_SUITE_P(WorkingDigests, HashCalculatorFactoryCreationTest TEST(HashCalculatorFactory, hashCalculatorFactoryFailTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__factory_interface, comp_req__hash__safe_computation"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that the factory returns an error, instead of a calculator, when asked to create a " + "calculator for HashAlgorithm::kNone."); + HashCalculatorFactory unit{}; auto hash_factory = unit.CreateHashCalculator(HashAlgorithm::kNone); ASSERT_FALSE(hash_factory.has_value()); @@ -133,6 +167,13 @@ TEST(HashCalculatorFactory, hashCalculatorFactoryFailTest) TEST(HashCalculatorFactory, HashCalculatorSpanInput) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that HashCalculatorFactory::CalculateHash() computes the correct digest for a span of " + "bytes in a single call."); + HashCalculatorFactory unit{}; std::vector test_input{'1', '2', '3', 'a', 'b', 'c'}; score::cpp::span data(test_input); @@ -147,6 +188,13 @@ TEST(HashCalculatorFactory, HashCalculatorSpanInput) TEST(HashCalculatorFactory, HashCalculatorStreamInput) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that HashCalculatorFactory::CalculateHash() computes the correct digest for input " + "supplied via a std::istream."); + HashCalculatorFactory unit{}; std::istringstream test_input("123abc"); const score::cpp::static_vector expected_sha256{ @@ -160,6 +208,13 @@ TEST(HashCalculatorFactory, HashCalculatorStreamInput) TEST(HashCalculatorFactory, FailedHashObjCreation) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that CalculateHash() returns an error, instead of a value, for HashAlgorithm::kNone with " + "span input."); + HashCalculatorFactory unit{}; std::vector test_input{'1', '2', '3', 'a', 'b', 'c'}; score::cpp::span data(test_input); @@ -171,6 +226,13 @@ TEST(HashCalculatorFactory, FailedHashObjCreation) TEST(HashCalculatorFactory, FailedHashObjCreationStream) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that CalculateHash() returns an error, instead of a value, for HashAlgorithm::kNone with " + "stream input."); + HashCalculatorFactory unit{}; std::istringstream test_input("123abc"); @@ -181,6 +243,13 @@ TEST(HashCalculatorFactory, FailedHashObjCreationStream) TEST(HashCalculatorFactory, InvalidHashCalculatorSpanInput) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that CalculateHash() returns an error, instead of a value, for an empty (default " + "constructed) span."); + HashCalculatorFactory unit{}; score::cpp::span data; @@ -191,6 +260,13 @@ TEST(HashCalculatorFactory, InvalidHashCalculatorSpanInput) TEST(HashCalculatorFactory, InvalidhashCalculatorStreamInput) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that CalculateHash() returns an error, instead of a value, when the input stream is " + "already in a failed state."); + HashCalculatorFactory unit{}; std::istringstream test_input{}; test_input.setstate(std::ios::failbit); @@ -202,6 +278,13 @@ TEST(HashCalculatorFactory, InvalidhashCalculatorStreamInput) TEST(HashCalculatorFactory, FailHashObjCreationWithMaxRead) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that CalculateHash() with a max-read limit still returns an error for " + "HashAlgorithm::kNone."); + HashCalculatorFactory unit{}; std::istringstream test_input("123abcefg"); @@ -212,6 +295,13 @@ TEST(HashCalculatorFactory, FailHashObjCreationWithMaxRead) TEST(HashCalculatorFactory, HashCalculatorStreamInputWithMaxRead) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that CalculateHash() computes the digest only over the first max-read bytes of a " + "stream, ignoring the remainder."); + HashCalculatorFactory unit{}; std::istringstream test_input("123abcefg"); const score::cpp::static_vector expected_sha256{ @@ -225,6 +315,13 @@ TEST(HashCalculatorFactory, HashCalculatorStreamInputWithMaxRead) TEST(HashCalculatorFactory, InstantiateWithFailingOpenSslLib) { + RecordProperty("PartiallyVerifies", "comp_req__hash__factory_interface, comp_req__hash__safe_computation"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "error-guessing"); + RecordProperty("Description", + "Check that the factory propagates an instantiation error, instead of throwing, when the " + "underlying OpenSSL library fails to resolve the digest algorithm."); + openssl::OpensslLibMock open_ssl_lib_mock{}; EXPECT_CALL(open_ssl_lib_mock, DigestAlgoSha1()).WillOnce(::testing::Return(nullptr)); HashCalculatorFactory unit{std::cref(open_ssl_lib_mock)}; @@ -235,6 +332,13 @@ TEST(HashCalculatorFactory, InstantiateWithFailingOpenSslLib) TEST(HashCalculatorFactory, InstantiateWithSuccess) { + RecordProperty("PartiallyVerifies", "comp_req__hash__factory_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + RecordProperty("Description", + "Check that the factory successfully creates a calculator by driving the underlying OpenSSL " + "digest lookup, context creation and initialization calls in the expected order."); + openssl::OpensslLibMock open_ssl_lib_mock{}; { openssl::StructDigestCtx* digest_context{reinterpret_cast(0xC0DEBEEF)}; @@ -253,6 +357,13 @@ TEST(HashCalculatorFactory, InstantiateWithSuccess) TEST(SafeHashCalculatorFactory, TryToInstantiateNonexistentHash) { + RecordProperty("PartiallyVerifies", "comp_req__hash__factory_interface, comp_req__hash__safe_computation"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that SafeHashCalculatorFactory returns an error, instead of a calculator, for an " + "algorithm it does not support (SHA-1)."); + SafeHashCalculatorFactory unit{}; EXPECT_FALSE(unit.CreateHashCalculator(HashAlgorithm::kSha1).has_value()); } diff --git a/score/hash/code/core/hash_test.cpp b/score/hash/code/core/hash_test.cpp index 40d0b2b009..266053f7c9 100644 --- a/score/hash/code/core/hash_test.cpp +++ b/score/hash/code/core/hash_test.cpp @@ -30,21 +30,46 @@ class HashFixture : public ::testing::Test TEST_F(HashFixture, CanCompareEqual) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_bytes"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that two Hash instances with the same algorithm and byte content compare equal."); + EXPECT_EQ(unit_, (Hash{HashAlgorithm::kSha256, {0x01}})); } TEST_F(HashFixture, DoesNotCoompareEqualOnDifferentAlgorithm) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_bytes"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that two Hash instances with different algorithms but the same bytes do not compare " + "equal."); + EXPECT_FALSE(unit_ == (Hash{HashAlgorithm::kSha1, {0x01}})); } TEST_F(HashFixture, DoesNotCoompareEqualOnDifferentContent) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_bytes"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that two Hash instances with the same algorithm but different byte content do not " + "compare equal."); + EXPECT_TRUE(unit_ != (Hash{HashAlgorithm::kSha256, {0x02}})); } TEST_F(HashFixture, GetBytesAsSpan) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_bytes"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", "Check that GetBytes() returns a span over the hash's raw byte content."); + Hash::ByteVector i1 = {0x01}; score::cpp::span expected_result(i1); auto result = unit_.GetBytes(); @@ -53,6 +78,13 @@ TEST_F(HashFixture, GetBytesAsSpan) TEST(HashTest, CanCreateFromValidString) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that Hash::FromString() parses a valid hex digest string into a Hash with the correct " + "bytes, and ToString() round-trips back to the same string."); + const score::cpp::pmr::string sha1{"89fdde0b28373dc4f361cfb810b35342cc2c3232"}; Hash::ByteVector expected_bytes = {0x89, 0xFD, 0xDE, 0x0B, 0x28, 0x37, 0x3D, 0xC4, 0xF3, 0x61, 0xCF, 0xB8, 0x10, 0xB3, 0x53, 0x42, 0xCC, 0x2C, 0x32, 0x32}; @@ -70,6 +102,11 @@ TEST(HashTest, CanCreateFromValidString) TEST(HashTest, ToStringEmptyValueTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", "Check that ToString() on a Hash with algorithm kNone yields an empty string."); + Hash unit{HashAlgorithm::kNone, {0x01}}; score::cpp::pmr::string result_str = unit.ToString(); ASSERT_TRUE(result_str.empty()); @@ -77,6 +114,16 @@ TEST(HashTest, ToStringEmptyValueTest) TEST(HashTest, CanCreateFromValidStringCompleteSetOfAlgorithms) { + RecordProperty("PartiallyVerifies", + "comp_req__hash__value_retrieval_hex, comp_req__hash__value_retrieval_bytes, " + "comp_req__hash__sha_algorithms, comp_req__hash__crc32_algorithm"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that Hash::FromString()/GetBytes()/GetAlgorithm()/ToString() round-trip correctly for " + "a representative digest of every supported algorithm (CRC-32, SHA-1, SHA-256, SHA-384, " + "SHA-512)."); + using StringPtr = const char* const; using TestData = const std::tuple; @@ -132,6 +179,13 @@ TEST(HashTest, CanCreateFromValidStringCompleteSetOfAlgorithms) TEST(HashTest, ValidateAlgorithm) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that Hash::FromString() rejects an unsupported algorithm (kLast) by returning an " + "error instead of a value."); + const score::cpp::pmr::string sha1 = "89fdde0b28373dc4f361cfb810b35342cc2c3232"; Result sha1_hash_result = Hash::FromString(HashAlgorithm::kLast, sha1); @@ -140,6 +194,13 @@ TEST(HashTest, ValidateAlgorithm) TEST(HashTest, ValidateSize) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that Hash::FromString() rejects hex strings that are one character shorter or longer " + "than the expected digest size for the given algorithm."); + const score::cpp::pmr::string short_sha1 = "89fdde0b28373dc4f361cfb810b35342cc2c323"; const score::cpp::pmr::string long_sha1 = "89fdde0b28373dc4f361cfb810b35342cc2c3232A"; @@ -152,6 +213,12 @@ TEST(HashTest, ValidateSize) TEST(HashTest, ValidateContents) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that Hash::FromString() rejects a hex string containing non-hexadecimal characters."); + const score::cpp::pmr::string invalid_sha1 = "89fdde0b28373dc4f361cfb810b35342cc2BOGUS"; Result sha1_hash_result = Hash::FromString(HashAlgorithm::kSha1, invalid_sha1); diff --git a/score/hash/code/core/typed_hash_test.cpp b/score/hash/code/core/typed_hash_test.cpp index f050aaf903..7a67ba9545 100644 --- a/score/hash/code/core/typed_hash_test.cpp +++ b/score/hash/code/core/typed_hash_test.cpp @@ -33,16 +33,32 @@ class TypedHashFixture : public ::testing::Test TEST_F(TypedHashFixture, CanCompareEqual) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_bytes"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", "Check that two TypedHash instances with the same byte content compare equal."); + EXPECT_EQ(unit_, (TypedHash{{0x01}})); } TEST_F(TypedHashFixture, DoesNotCompareEqualOnDifferentContent) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_bytes"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that two TypedHash instances with different byte content do not compare equal."); + EXPECT_NE(unit_, (TypedHash{{0x02}})); } TEST_F(TypedHashFixture, GetBytesAsSpan) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_bytes"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", "Check that GetBytes() returns a span over the TypedHash's raw byte content."); + Hash::ByteVector i1 = {0x01}; score::cpp::span expected_result(i1); auto result = unit_.GetBytes(); @@ -51,6 +67,13 @@ TEST_F(TypedHashFixture, GetBytesAsSpan) TEST(TypedHashTest, CanCreateFromValidString) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that TypedHash::FromString() parses a valid hex digest string into a TypedHash with " + "the correct bytes, and ToString() round-trips back to the same string."); + const score::cpp::pmr::string sha1{"89fdde0b28373dc4f361cfb810b35342cc2c3232"}; Hash::ByteVector expected_bytes = {0x89, 0xFD, 0xDE, 0x0B, 0x28, 0x37, 0x3D, 0xC4, 0xF3, 0x61, 0xCF, 0xB8, 0x10, 0xB3, 0x53, 0x42, 0xCC, 0x2C, 0x32, 0x32}; @@ -71,6 +94,11 @@ TEST(TypedHashTest, CanCreateFromValidString) TEST(TypedHashTest, ToStringEmptyValueTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", "Check that ToString() on a TypedHash yields an empty string."); + TypedHash unit{{0x01}}; score::cpp::pmr::string result_str = unit.ToString(); ASSERT_TRUE(result_str.empty()); @@ -78,6 +106,13 @@ TEST(TypedHashTest, ToStringEmptyValueTest) TEST(TypedHashTest, CanSerializeToJsonAny) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that TypedHash::ToAny() serializes the hash as its hexadecimal string representation, " + "including the empty-string case for kNone."); + const TypedHash hash{{0xFF, 0x18, 0x25, 0x62, 0x92, 0xF5, 0xF2, 0xBA, 0x52, 0x61, 0xB5, 0x59, 0x40, 0xCD, 0xF1, 0x12, 0x5C, 0xE3, 0x0E, 0x97, 0xC2, 0x2A, 0xCE, 0x6A, 0xFA, 0x54, 0xB7, 0xAF, 0x38, 0x72, 0xC3, 0x51}}; @@ -95,6 +130,13 @@ TEST(TypedHashTest, CanSerializeToJsonAny) TEST(TypedHashTest, CanDeserializeFromJsonAny) { + RecordProperty("PartiallyVerifies", "comp_req__hash__value_retrieval_hex"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that TypedHash::FromAny() deserializes a hex string JSON value back into a TypedHash, " + "and rejects an unsupported algorithm or a non-string JSON value with the expected error."); + const TypedHash expected_hash{ {0xFF, 0x18, 0x25, 0x62, 0x92, 0xF5, 0xF2, 0xBA, 0x52, 0x61, 0xB5, 0x59, 0x40, 0xCD, 0xF1, 0x12, 0x5C, 0xE3, 0x0E, 0x97, 0xC2, 0x2A, 0xCE, 0x6A, 0xFA, 0x54, 0xB7, 0xAF, 0x38, 0x72, 0xC3, 0x51}}; diff --git a/score/hash/code/crc/crc32_ieee_test.cpp b/score/hash/code/crc/crc32_ieee_test.cpp index d0b8efdec3..d23dbc6c43 100644 --- a/score/hash/code/crc/crc32_ieee_test.cpp +++ b/score/hash/code/crc/crc32_ieee_test.cpp @@ -47,6 +47,13 @@ constexpr std::uint8_t Crc32IeeeTest::kExpectedBytes[]; TEST_F(Crc32IeeeTest, Hash) { + RecordProperty("PartiallyVerifies", "comp_req__hash__crc32_algorithm, comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + RecordProperty("Description", + "Check that Crc32IeeeHashCalculator computes the correct IEEE CRC-32 checksum for a known " + "input string, both as a raw checksum value and as a finalized Hash."); + // Given an input text const score::cpp::span input{kTest, sizeof(kTest) - 1}; @@ -60,6 +67,13 @@ TEST_F(Crc32IeeeTest, Hash) TEST_F(Crc32IeeeTest, TwoUpdates) { + RecordProperty("PartiallyVerifies", "comp_req__hash__crc32_algorithm, comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that splitting the input across two Update() calls accumulates state and yields the " + "same checksum as a single Update() call over the whole input."); + // Given an input text split in the middle at kPivot constexpr auto kPivot{sizeof(kTest) / 2U}; const score::cpp::span input1{kTest, kPivot}; diff --git a/score/hash/code/openssl/openssl_hash_calculator_test.cpp b/score/hash/code/openssl/openssl_hash_calculator_test.cpp index 5aa3960e53..cdaf3c14ce 100644 --- a/score/hash/code/openssl/openssl_hash_calculator_test.cpp +++ b/score/hash/code/openssl/openssl_hash_calculator_test.cpp @@ -78,6 +78,12 @@ void HashCalculatorTest::ExpectSha256Call() TEST_F(HashCalculatorTest, HashAlgorithmsSimpleSha1Test) { + RecordProperty("PartiallyVerifies", "comp_req__hash__sha_algorithms"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that OpensslHashCalculator::Create() successfully creates a SHA-1 calculator."); + const StructDigest* digest_type_sha1 = openssl_lib_.DigestAlgoSha1(); StructDigestCtx* digest_context_sha1 = openssl_lib_.CreateDigestCtx(); std::int32_t hash_digest_sha1 = openssl_lib_.InitDigestCtx(digest_context_sha1, digest_type_sha1, nullptr); @@ -95,6 +101,12 @@ TEST_F(HashCalculatorTest, HashAlgorithmsSimpleSha1Test) TEST_F(HashCalculatorTest, HashAlgorithmsSimpleSha256Test) { + RecordProperty("PartiallyVerifies", "comp_req__hash__sha_algorithms"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that OpensslHashCalculator::Create() successfully creates a SHA-256 calculator."); + ExpectSha256Call(); auto digest = OpensslHashCalculator::Create(HashAlgorithm::kSha256, openssl_lib_mock_); @@ -104,6 +116,12 @@ TEST_F(HashCalculatorTest, HashAlgorithmsSimpleSha256Test) TEST_F(HashCalculatorTest, HashAlgorithmsSimpleSha384Test) { + RecordProperty("PartiallyVerifies", "comp_req__hash__sha_algorithms"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that OpensslHashCalculator::Create() successfully creates a SHA-384 calculator."); + const StructDigest* digest_type_sha384 = openssl_lib_.DigestAlgoSha384(); StructDigestCtx* digest_context_sha384 = openssl_lib_.CreateDigestCtx(); std::int32_t hash_digest_sha384 = openssl_lib_.InitDigestCtx(digest_context_sha384, digest_type_sha384, nullptr); @@ -121,6 +139,13 @@ TEST_F(HashCalculatorTest, HashAlgorithmsSimpleSha384Test) TEST_F(HashCalculatorTest, HashAlgorithmsSimpleSha512Test) { + RecordProperty("PartiallyVerifies", "comp_req__hash__sha_algorithms, comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", + "Check that OpensslHashCalculator::Create() successfully creates a SHA-512 calculator, and " + "that Update() still functions correctly on a move-assigned-into calculator instance."); + const StructDigest* digest_type_sha512 = openssl_lib_.DigestAlgoSha512(); StructDigestCtx* digest_context_sha512 = openssl_lib_.CreateDigestCtx(); std::int32_t hash_digest_sha512 = openssl_lib_.InitDigestCtx(digest_context_sha512, digest_type_sha512, nullptr); @@ -147,6 +172,13 @@ TEST_F(HashCalculatorTest, HashAlgorithmsSimpleSha512Test) TEST_F(HashCalculatorTest, NullDigestTypeCreateAlgoTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__safe_computation"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "error-guessing"); + RecordProperty("Description", + "Check that Create() returns an instantiation error, instead of throwing, when the OpenSSL " + "library fails to resolve the digest type."); + EXPECT_CALL(openssl_lib_mock_, DigestAlgoSha256()).WillOnce(Return(nullptr)); auto digest = OpensslHashCalculator::Create(HashAlgorithm::kSha256, openssl_lib_mock_); @@ -155,6 +187,13 @@ TEST_F(HashCalculatorTest, NullDigestTypeCreateAlgoTest) TEST_F(HashCalculatorTest, InvalidDigestCtxCreateAlgoTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__safe_computation"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "error-guessing"); + RecordProperty("Description", + "Check that Create() returns an instantiation error, instead of throwing, when the OpenSSL " + "library fails to create a digest context."); + ON_CALL(openssl_lib_mock_, DigestAlgoSha256()).WillByDefault(Return(digest_type_sha256)); ON_CALL(openssl_lib_mock_, CreateDigestCtx()).WillByDefault(Return(nullptr)); @@ -165,6 +204,13 @@ TEST_F(HashCalculatorTest, InvalidDigestCtxCreateAlgoTest) TEST_F(HashCalculatorTest, InvalidDigestInitCreateAlgoTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__safe_computation"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "error-guessing"); + RecordProperty("Description", + "Check that Create() returns an instantiation error, instead of throwing, when the OpenSSL " + "library fails to initialize the digest context."); + EXPECT_CALL(openssl_lib_mock_, DigestAlgoSha256()).WillOnce(Return(digest_type_sha256)); EXPECT_CALL(openssl_lib_mock_, CreateDigestCtx()).WillOnce(Return(digest_context_sha256)); EXPECT_CALL(openssl_lib_mock_, InitDigestCtx(_, _, _)).WillOnce(Return(0)); @@ -176,6 +222,13 @@ TEST_F(HashCalculatorTest, InvalidDigestInitCreateAlgoTest) TEST_F(HashCalculatorTest, InvalidCreateAlgorthimTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__safe_computation"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that Create() returns an instantiation error, instead of throwing, for the unsupported " + "kNone and kLast algorithm identifiers."); + auto hash_calculator = OpensslHashCalculator::Create(HashAlgorithm::kNone, openssl_lib_mock_); ASSERT_FALSE(hash_calculator.has_value()); EXPECT_EQ(hash_calculator.error(), ErrorCode::kCouldNotCreateDigest); @@ -187,6 +240,11 @@ TEST_F(HashCalculatorTest, InvalidCreateAlgorthimTest) TEST_F(HashCalculatorTest, UpdateStreamTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", "Check that Update() accepts a span of bytes and accumulates digest state."); + ExpectSha256Call(); EXPECT_CALL(openssl_lib_mock_, UpdateDigestCtx(_, _, _)).WillOnce(Return(1)); @@ -201,6 +259,11 @@ TEST_F(HashCalculatorTest, UpdateStreamTest) TEST_F(HashCalculatorTest, EmptyUpdateTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", "Check that Update() returns an error, instead of a value, for an empty span."); + ExpectSha256Call(); score::cpp::span data; @@ -213,6 +276,13 @@ TEST_F(HashCalculatorTest, EmptyUpdateTest) TEST_F(HashCalculatorTest, InvalidDigestUpdateTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "error-guessing"); + RecordProperty("Description", + "Check that Update() returns an error, instead of a value, when the OpenSSL library fails to " + "update the digest context."); + ExpectSha256Call(); EXPECT_CALL(openssl_lib_mock_, UpdateDigestCtx(_, _, _)).WillOnce(Return(0)); @@ -228,6 +298,11 @@ TEST_F(HashCalculatorTest, InvalidDigestUpdateTest) TEST_F(HashCalculatorTest, UpdateFromStreamTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", "Check that UpdateFromStream() accepts a std::istream and accumulates digest state."); + ExpectSha256Call(); EXPECT_CALL(openssl_lib_mock_, UpdateDigestCtx(_, _, _)).WillOnce(Return(1)); @@ -242,6 +317,13 @@ TEST_F(HashCalculatorTest, UpdateFromStreamTest) TEST_F(HashCalculatorTest, InvalidUpdateFromStreamTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "error-guessing"); + RecordProperty("Description", + "Check that UpdateFromStream() returns an error, instead of a value, when the OpenSSL library " + "fails to update the digest context."); + ExpectSha256Call(); EXPECT_CALL(openssl_lib_mock_, UpdateDigestCtx(_, _, _)).WillOnce(Return(0)); @@ -258,6 +340,13 @@ TEST_F(HashCalculatorTest, InvalidUpdateFromStreamTest) TEST_F(HashCalculatorTest, UpdateFromStreamGoesBadTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "error-guessing"); + RecordProperty("Description", + "Check that UpdateFromStream() returns an error, instead of a value, when the stream enters a " + "bad state while it is being read."); + ExpectSha256Call(); std::vector test_input{1, 2, 3, 4}; @@ -279,6 +368,13 @@ TEST_F(HashCalculatorTest, UpdateFromStreamGoesBadTest) TEST_F(HashCalculatorTest, BadInputUpdateFromStreamTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that UpdateFromStream() returns an error, instead of a value, when the input stream is " + "already in a failed state before reading."); + ExpectSha256Call(); std::stringstream input_stream; @@ -293,6 +389,13 @@ TEST_F(HashCalculatorTest, BadInputUpdateFromStreamTest) TEST_F(HashCalculatorTest, EmptyInputUpdateFromStreamTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "boundary-values"); + RecordProperty("Description", + "Check that UpdateFromStream() with an empty input stream still finalizes to the correct " + "well-known SHA-256 digest of the empty string."); + std::vector test_input{}; std::istringstream input_stream(std::string(test_input.begin(), test_input.end())); const score::cpp::static_vector expected_sha256{ @@ -310,6 +413,13 @@ TEST_F(HashCalculatorTest, EmptyInputUpdateFromStreamTest) TEST_F(HashCalculatorTest, InvalidFinalizeTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "fault-injection"); + RecordProperty("DerivationTechnique", "error-guessing"); + RecordProperty("Description", + "Check that Finalize() yields an empty (kNone) Hash when the OpenSSL library fails to " + "finalize the digest value."); + ExpectSha256Call(); EXPECT_CALL(openssl_lib_mock_, FinalizeDigestValue(_, _, _)).WillOnce(Return(0)); @@ -322,6 +432,13 @@ TEST_F(HashCalculatorTest, InvalidFinalizeTest) TEST(HashCalculatorSHATest, HashAlgorithmsSimpleTestSha256) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface, comp_req__hash__sha_algorithms"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + RecordProperty("Description", + "Check an end-to-end SHA-256 computation through the public API: Create(), Update() and " + "Finalize() together produce the correct digest for a known input."); + constexpr std::uint8_t test_input[]{'1', '2', '3', 'a', 'b', 'c'}; const score::cpp::static_vector expected_sha256{ 221, 19, 10, 132, 157, 123, 41, 229, 84, 27, 5, 210, 247, 248, 106, 74, diff --git a/score/hash/code/openssl/openssl_wrapper/openssl_lib_impl_test.cpp b/score/hash/code/openssl/openssl_wrapper/openssl_lib_impl_test.cpp index 78fb3bf270..7cc6b374f4 100644 --- a/score/hash/code/openssl/openssl_wrapper/openssl_lib_impl_test.cpp +++ b/score/hash/code/openssl/openssl_wrapper/openssl_lib_impl_test.cpp @@ -54,6 +54,11 @@ void OpensslLibTest::TearDown() TEST_F(OpensslLibTest, Sha1Test) { + RecordProperty("PartiallyVerifies", "comp_req__hash__sha_algorithms"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", "Check that the OpenSSL wrapper resolves a non-null SHA-1 digest type."); + auto result = unit_.DigestAlgoSha1(); EXPECT_NE(result, nullptr); @@ -61,11 +66,21 @@ TEST_F(OpensslLibTest, Sha1Test) TEST_F(OpensslLibTest, Sha256Test) { + RecordProperty("PartiallyVerifies", "comp_req__hash__sha_algorithms"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", "Check that a digest context created from the SHA-256 digest type is non-null."); + EXPECT_NE(digest_context_, nullptr); } TEST_F(OpensslLibTest, Sha384Test) { + RecordProperty("PartiallyVerifies", "comp_req__hash__sha_algorithms"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", "Check that the OpenSSL wrapper resolves a non-null SHA-384 digest type."); + auto result = unit_.DigestAlgoSha384(); EXPECT_NE(result, nullptr); @@ -73,6 +88,11 @@ TEST_F(OpensslLibTest, Sha384Test) TEST_F(OpensslLibTest, Sha512Test) { + RecordProperty("PartiallyVerifies", "comp_req__hash__sha_algorithms"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "equivalence-classes"); + RecordProperty("Description", "Check that the OpenSSL wrapper resolves a non-null SHA-512 digest type."); + auto result = unit_.DigestAlgoSha512(); EXPECT_NE(result, nullptr); @@ -80,11 +100,21 @@ TEST_F(OpensslLibTest, Sha512Test) TEST_F(OpensslLibTest, DigestCtxNewTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + RecordProperty("Description", "Check that CreateDigestCtx() returns a non-null digest context."); + EXPECT_NE(digest_context_, nullptr); } TEST_F(OpensslLibTest, DigestInitExTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + RecordProperty("Description", "Check that InitDigestCtx() successfully initializes a digest context."); + auto result = unit_.InitDigestCtx(digest_context_, digest_type_, nullptr); EXPECT_EQ(result, 1); @@ -92,6 +122,12 @@ TEST_F(OpensslLibTest, DigestInitExTest) TEST_F(OpensslLibTest, DigestUpdateTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + RecordProperty("Description", + "Check that UpdateDigestCtx() successfully feeds data into an initialized digest context."); + char msg[] = "Hello World\n"; unit_.InitDigestCtx(digest_context_, digest_type_, nullptr); @@ -103,6 +139,12 @@ TEST_F(OpensslLibTest, DigestUpdateTest) TEST_F(OpensslLibTest, DigestFinalExTest) { + RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface"); + RecordProperty("TestType", "requirements-based"); + RecordProperty("DerivationTechnique", "requirements-analysis"); + RecordProperty("Description", + "Check that FinalizeDigestValue() successfully finalizes a digest context to its output value."); + char msg[] = "Hello World\n"; unsigned char data[64]; unsigned int size;