Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions score/hash/code/common/algorithms_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const HashAlgorithm, const std::uint8_t>{
{HashAlgorithm::kCrc32, 4},
{HashAlgorithm::kCrc32Autosar, 4},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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{};
Expand Down Expand Up @@ -82,6 +90,13 @@ const std::vector<DataAndDigest> 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)
Expand All @@ -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<std::uint8_t> test_input{'1', '2', '3', 'a', 'b', 'c'};
Expand All @@ -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");
Comment on lines +130 to +131
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<std::uint8_t> test_input{'1', '2', '3', 'a', 'b', 'c'};
score::cpp::span<const std::uint8_t> data(test_input);
Expand All @@ -126,13 +153,27 @@ 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());
}

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<std::uint8_t> test_input{'1', '2', '3', 'a', 'b', 'c'};
score::cpp::span<const std::uint8_t> data(test_input);
Expand All @@ -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<std::uint8_t, kMaxDigestSize> expected_sha256{
Expand All @@ -160,6 +208,13 @@ TEST(HashCalculatorFactory, HashCalculatorStreamInput)

TEST(HashCalculatorFactory, FailedHashObjCreation)
{
RecordProperty("PartiallyVerifies", "comp_req__hash__calculation_interface");
RecordProperty("TestType", "fault-injection");
Comment on lines +211 to +212
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<std::uint8_t> test_input{'1', '2', '3', 'a', 'b', 'c'};
score::cpp::span<const std::uint8_t> data(test_input);
Expand All @@ -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");

Expand All @@ -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.");
Comment on lines +246 to +251

HashCalculatorFactory unit{};
score::cpp::span<const std::uint8_t> data;

Expand All @@ -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.");
Comment on lines +263 to +268

HashCalculatorFactory unit{};
std::istringstream test_input{};
test_input.setstate(std::ios::failbit);
Expand All @@ -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");

Expand All @@ -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<std::uint8_t, kMaxDigestSize> expected_sha256{
Expand All @@ -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)};
Expand All @@ -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");
Comment on lines +336 to +337
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<openssl::StructDigestCtx*>(0xC0DEBEEF)};
Expand All @@ -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");
Comment on lines +361 to +362
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());
}
Expand Down
67 changes: 67 additions & 0 deletions score/hash/code/core/hash_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Comment on lines +33 to +37

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.");
Comment on lines +44 to +49

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.");
Comment on lines +56 to +61

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<const std::uint8_t> expected_result(i1);
auto result = unit_.GetBytes();
Expand All @@ -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};
Expand All @@ -70,13 +102,28 @@ 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());
}

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");
Comment on lines +117 to +119
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<HashAlgorithm, StringPtr, Hash::ByteVector>;

Expand Down Expand Up @@ -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.");
Comment on lines +182 to +187

const score::cpp::pmr::string sha1 = "89fdde0b28373dc4f361cfb810b35342cc2c3232";

Result<Hash> sha1_hash_result = Hash::FromString(HashAlgorithm::kLast, sha1);
Expand All @@ -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";

Expand All @@ -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<Hash> sha1_hash_result = Hash::FromString(HashAlgorithm::kSha1, invalid_sha1);
Expand Down
Loading
Loading