From 3d2fa18c613bb0ce912280ad95f486d69a4078ae Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 25 Nov 2021 14:30:13 -0600 Subject: [PATCH] test: improve tr_bitfield and tr_block_info coverage (#2226) * test: improve coverage in tr_bitfield::raw() * test: improve coverage in tr_bitfield::count() * test: improve coverage for edge cases in tr_bitfield::setSpan() * test: confirm that excess bits in setRaw() are set to zero * fix: edge case of tr_block_info::initBlocks() where piece_size is 0 this should not happen in production, but cover it anyway --- libtransmission/bitfield.cc | 13 ++--- libtransmission/block-info.cc | 1 + tests/libtransmission/bitfield-test.cc | 63 +++++++++++++++++++++++- tests/libtransmission/block-info-test.cc | 15 ++++++ 4 files changed, 84 insertions(+), 8 deletions(-) diff --git a/libtransmission/bitfield.cc b/libtransmission/bitfield.cc index 08e0e6a37..fab8aa7c4 100644 --- a/libtransmission/bitfield.cc +++ b/libtransmission/bitfield.cc @@ -359,6 +359,13 @@ void tr_bitfield::set(size_t nth, bool value) /* Sets bit range [begin, end) to 1 */ void tr_bitfield::setSpan(size_t begin, size_t end, bool value) { + // bounds check + end = std::min(end, bit_count_); + if (end == 0 || begin >= end) + { + return; + } + // did anything change? size_t const old_count = count(begin, end); size_t const new_count = value ? (end - begin) : 0; @@ -367,13 +374,7 @@ void tr_bitfield::setSpan(size_t begin, size_t end, bool value) return; } - // bounds check --end; - if (end >= bit_count_ || begin > end) - { - return; - } - if (!ensureNthBitAlloced(end)) { return; diff --git a/libtransmission/block-info.cc b/libtransmission/block-info.cc index 41f6f5978..52b2a36ed 100644 --- a/libtransmission/block-info.cc +++ b/libtransmission/block-info.cc @@ -44,6 +44,7 @@ void tr_block_info::initSizes(uint64_t total_size_in, uint64_t piece_size_in) if (piece_size == 0 || block_size == 0) { + *this = {}; return; } diff --git a/tests/libtransmission/bitfield-test.cc b/tests/libtransmission/bitfield-test.cc index 0f5872840..6a87a7ae2 100644 --- a/tests/libtransmission/bitfield-test.cc +++ b/tests/libtransmission/bitfield-test.cc @@ -6,7 +6,10 @@ * */ +#include #include +#include +#include #include "transmission.h" #include "crypto-utils.h" @@ -15,7 +18,7 @@ #include "gtest/gtest.h" -TEST(Bitfield, countRange) +TEST(Bitfield, count) { auto constexpr IterCount = int{ 10000 }; @@ -59,6 +62,18 @@ TEST(Bitfield, countRange) auto const count2 = bf.count(begin, end); EXPECT_EQ(count1, count2); } + + auto bf = tr_bitfield{ 0 }; + EXPECT_EQ(0, bf.count(0, 0)); + EXPECT_EQ(0, bf.count(0, 1)); + + bf = tr_bitfield{ 100 }; + EXPECT_EQ(0, bf.count(0, 0)); + EXPECT_EQ(0, bf.count(0, 100)); + bf.setHasAll(); + EXPECT_EQ(0, bf.count(0, 0)); + EXPECT_EQ(1, bf.count(0, 1)); + EXPECT_EQ(100, bf.count(0, 100)); } TEST(Bitfield, ctorFromFlagArray) @@ -96,7 +111,7 @@ TEST(Bitfield, setRaw) auto constexpr TestByte = uint8_t{ 10 }; auto constexpr TestByteTrueBits = 2; - auto const raw = std::vector(100, TestByte); + auto raw = std::vector(100, TestByte); auto bf = tr_bitfield(std::size(raw) * 8); bf.setRaw(std::data(raw), std::size(raw)); @@ -115,6 +130,24 @@ TEST(Bitfield, setRaw) } EXPECT_EQ(TestByte, test); EXPECT_EQ(raw, bf.raw()); + + // check that has-all bitfield gets all-true + bf = tr_bitfield(std::size(raw) * 8); + bf.setHasAll(); + raw = bf.raw(); + EXPECT_EQ(std::size(bf) / 8, std::size(raw)); + EXPECT_EQ(std::numeric_limits::max(), raw[0]); + + // check that the spare bits t the end are zero + bf = tr_bitfield{ 1 }; + uint8_t by = ~uint8_t{}; + bf.setRaw(&by, 1); + EXPECT_TRUE(bf.hasAll()); + EXPECT_FALSE(bf.hasNone()); + EXPECT_EQ(1, bf.count()); + raw = bf.raw(); + EXPECT_EQ(1, std::size(raw)); + EXPECT_EQ(1 << 7, raw[0]); } TEST(Bitfield, bitfields) @@ -211,6 +244,32 @@ TEST(Bitfield, bitfields) { EXPECT_EQ(field.test(i), (4 <= i && i < 5)); } + + /* test tr_bitfield::setSpan when end runs beyond the end of the bitfield */ + field.setHasNone(); + field.setSpan(100, 1000); + EXPECT_FALSE(field.hasNone()); + EXPECT_FALSE(field.hasAll()); + EXPECT_EQ(std::size(field) - 100, field.count()); + + /* test tr_bitfield::unsetSpan when it changes nothing */ + field.setHasNone(); + field.unsetSpan(0, 100); + EXPECT_TRUE(field.hasNone()); + EXPECT_FALSE(field.hasAll()); + EXPECT_EQ(0, field.count()); + + /* test tr_bitfield::setSpan when it changes nothing */ + field.setHasAll(); + field.setSpan(0, 100); + EXPECT_FALSE(field.hasNone()); + EXPECT_TRUE(field.hasAll()); + EXPECT_EQ(std::size(field), field.count()); + + /* test tr_bitfield::setSpan with an invalid span doesn't crash */ + field.setHasAll(); + field.setSpan(0, 0); + EXPECT_TRUE(field.hasAll()); } TEST(Bitfield, hasAllNone) diff --git a/tests/libtransmission/block-info-test.cc b/tests/libtransmission/block-info-test.cc index 82a062b95..995e95ec8 100644 --- a/tests/libtransmission/block-info-test.cc +++ b/tests/libtransmission/block-info-test.cc @@ -35,6 +35,16 @@ TEST_F(BlockInfoTest, fieldsAreSet) EXPECT_EQ(PieceSize, info.final_piece_size); EXPECT_EQ(PieceSize, info.piece_size); EXPECT_EQ(TotalSize, info.total_size); + + info.initSizes(0, 0); + EXPECT_EQ(0, info.block_size); + EXPECT_EQ(0, info.final_block_size); + EXPECT_EQ(0, info.n_blocks_in_final_piece); + EXPECT_EQ(0, info.n_blocks_in_piece); + EXPECT_EQ(0, info.n_pieces); + EXPECT_EQ(0, info.final_piece_size); + EXPECT_EQ(0, info.piece_size); + EXPECT_EQ(0, info.total_size); } TEST_F(BlockInfoTest, handlesOddSize) @@ -147,4 +157,9 @@ TEST_F(BlockInfoTest, blockSpanForPiece) EXPECT_EQ(16, info.blockSpanForPiece(3).end); EXPECT_EQ(16, info.blockSpanForPiece(4).begin); EXPECT_EQ(17, info.blockSpanForPiece(4).end); + + // test that uninitialized block_info returns an invalid span + info = tr_block_info{}; + EXPECT_EQ(0, info.blockSpanForPiece(0).begin); + EXPECT_EQ(0, info.blockSpanForPiece(0).end); }