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
This commit is contained in:
Charles Kerr
2021-11-25 14:30:13 -06:00
committed by GitHub
parent de169c7ec3
commit 3d2fa18c61
4 changed files with 84 additions and 8 deletions

View File

@@ -359,6 +359,13 @@ void tr_bitfield::set(size_t nth, bool value)
/* Sets bit range [begin, end) to 1 */ /* Sets bit range [begin, end) to 1 */
void tr_bitfield::setSpan(size_t begin, size_t end, bool value) 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? // did anything change?
size_t const old_count = count(begin, end); size_t const old_count = count(begin, end);
size_t const new_count = value ? (end - begin) : 0; 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; return;
} }
// bounds check
--end; --end;
if (end >= bit_count_ || begin > end)
{
return;
}
if (!ensureNthBitAlloced(end)) if (!ensureNthBitAlloced(end))
{ {
return; return;

View File

@@ -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) if (piece_size == 0 || block_size == 0)
{ {
*this = {};
return; return;
} }

View File

@@ -6,7 +6,10 @@
* *
*/ */
#include <algorithm>
#include <array> #include <array>
#include <limits>
#include <vector>
#include "transmission.h" #include "transmission.h"
#include "crypto-utils.h" #include "crypto-utils.h"
@@ -15,7 +18,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
TEST(Bitfield, countRange) TEST(Bitfield, count)
{ {
auto constexpr IterCount = int{ 10000 }; auto constexpr IterCount = int{ 10000 };
@@ -59,6 +62,18 @@ TEST(Bitfield, countRange)
auto const count2 = bf.count(begin, end); auto const count2 = bf.count(begin, end);
EXPECT_EQ(count1, count2); 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) TEST(Bitfield, ctorFromFlagArray)
@@ -96,7 +111,7 @@ TEST(Bitfield, setRaw)
auto constexpr TestByte = uint8_t{ 10 }; auto constexpr TestByte = uint8_t{ 10 };
auto constexpr TestByteTrueBits = 2; auto constexpr TestByteTrueBits = 2;
auto const raw = std::vector<uint8_t>(100, TestByte); auto raw = std::vector<uint8_t>(100, TestByte);
auto bf = tr_bitfield(std::size(raw) * 8); auto bf = tr_bitfield(std::size(raw) * 8);
bf.setRaw(std::data(raw), std::size(raw)); bf.setRaw(std::data(raw), std::size(raw));
@@ -115,6 +130,24 @@ TEST(Bitfield, setRaw)
} }
EXPECT_EQ(TestByte, test); EXPECT_EQ(TestByte, test);
EXPECT_EQ(raw, bf.raw()); 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<unsigned char>::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) TEST(Bitfield, bitfields)
@@ -211,6 +244,32 @@ TEST(Bitfield, bitfields)
{ {
EXPECT_EQ(field.test(i), (4 <= i && i < 5)); 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) TEST(Bitfield, hasAllNone)

View File

@@ -35,6 +35,16 @@ TEST_F(BlockInfoTest, fieldsAreSet)
EXPECT_EQ(PieceSize, info.final_piece_size); EXPECT_EQ(PieceSize, info.final_piece_size);
EXPECT_EQ(PieceSize, info.piece_size); EXPECT_EQ(PieceSize, info.piece_size);
EXPECT_EQ(TotalSize, info.total_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) TEST_F(BlockInfoTest, handlesOddSize)
@@ -147,4 +157,9 @@ TEST_F(BlockInfoTest, blockSpanForPiece)
EXPECT_EQ(16, info.blockSpanForPiece(3).end); EXPECT_EQ(16, info.blockSpanForPiece(3).end);
EXPECT_EQ(16, info.blockSpanForPiece(4).begin); EXPECT_EQ(16, info.blockSpanForPiece(4).begin);
EXPECT_EQ(17, info.blockSpanForPiece(4).end); 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);
} }