| /* | |
| * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #include "net/dcsctp/packet/chunk_validators.h" | |
| #include <utility> | |
| #include "net/dcsctp/common/internal_types.h" | |
| #include "net/dcsctp/packet/chunk/sack_chunk.h" | |
| #include "test/gmock.h" | |
| #include "test/gtest.h" | |
| namespace dcsctp { | |
| namespace { | |
| using ::testing::ElementsAre; | |
| using ::testing::IsEmpty; | |
| TEST(ChunkValidatorsTest, NoGapAckBlocksAreValid) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, | |
| /*gap_ack_blocks=*/{}, {}); | |
| EXPECT_TRUE(ChunkValidators::Validate(sack)); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT(clean.gap_ack_blocks(), IsEmpty()); | |
| } | |
| TEST(ChunkValidatorsTest, OneValidAckBlock) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, {SackChunk::GapAckBlock(2, 3)}, {}); | |
| EXPECT_TRUE(ChunkValidators::Validate(sack)); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT(clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(2, 3))); | |
| } | |
| TEST(ChunkValidatorsTest, TwoValidAckBlocks) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, | |
| {SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(5, 6)}, | |
| {}); | |
| EXPECT_TRUE(ChunkValidators::Validate(sack)); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT( | |
| clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(5, 6))); | |
| } | |
| TEST(ChunkValidatorsTest, OneInvalidAckBlock) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, {SackChunk::GapAckBlock(1, 2)}, {}); | |
| EXPECT_FALSE(ChunkValidators::Validate(sack)); | |
| // It's not strictly valid, but due to the renegable nature of gap ack blocks, | |
| // the cum_ack_tsn can't simply be moved. | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT(clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(1, 2))); | |
| } | |
| TEST(ChunkValidatorsTest, RemovesInvalidGapAckBlockFromSack) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, | |
| {SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(6, 4)}, | |
| {}); | |
| EXPECT_FALSE(ChunkValidators::Validate(sack)); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT(clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(2, 3))); | |
| } | |
| TEST(ChunkValidatorsTest, SortsGapAckBlocksInOrder) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, | |
| {SackChunk::GapAckBlock(6, 7), SackChunk::GapAckBlock(3, 4)}, | |
| {}); | |
| EXPECT_FALSE(ChunkValidators::Validate(sack)); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT( | |
| clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(3, 4), SackChunk::GapAckBlock(6, 7))); | |
| } | |
| TEST(ChunkValidatorsTest, MergesAdjacentBlocks) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, | |
| {SackChunk::GapAckBlock(3, 4), SackChunk::GapAckBlock(5, 6)}, | |
| {}); | |
| EXPECT_FALSE(ChunkValidators::Validate(sack)); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT(clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(3, 6))); | |
| } | |
| TEST(ChunkValidatorsTest, MergesOverlappingByOne) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, | |
| {SackChunk::GapAckBlock(3, 4), SackChunk::GapAckBlock(4, 5)}, | |
| {}); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_FALSE(ChunkValidators::Validate(sack)); | |
| EXPECT_THAT(clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(3, 5))); | |
| } | |
| TEST(ChunkValidatorsTest, MergesOverlappingByMore) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, | |
| {SackChunk::GapAckBlock(3, 10), SackChunk::GapAckBlock(4, 5)}, | |
| {}); | |
| EXPECT_FALSE(ChunkValidators::Validate(sack)); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT(clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(3, 10))); | |
| } | |
| TEST(ChunkValidatorsTest, MergesBlocksStartingWithSameStartOffset) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, | |
| {SackChunk::GapAckBlock(3, 7), SackChunk::GapAckBlock(3, 5), | |
| SackChunk::GapAckBlock(3, 9)}, | |
| {}); | |
| EXPECT_FALSE(ChunkValidators::Validate(sack)); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT(clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(3, 9))); | |
| } | |
| TEST(ChunkValidatorsTest, MergesBlocksPartiallyOverlapping) { | |
| SackChunk sack(TSN(123), /*a_rwnd=*/456, | |
| {SackChunk::GapAckBlock(3, 7), SackChunk::GapAckBlock(5, 9)}, | |
| {}); | |
| EXPECT_FALSE(ChunkValidators::Validate(sack)); | |
| SackChunk clean = ChunkValidators::Clean(std::move(sack)); | |
| EXPECT_THAT(clean.gap_ack_blocks(), | |
| ElementsAre(SackChunk::GapAckBlock(3, 9))); | |
| } | |
| } // namespace | |
| } // namespace dcsctp |