This tests all of the known integer unwrappers in WebRTC * rtc::TimestampWrapAroundHandler * webrtc::Unwrapper<T> * webrtc::SequenceNumberUnwrapper<T> * dcsctp::UnwrappedSequenceNumber The conformance tests show differences between in behavior between the unwrappers. This change also adds const accessors for the internal values of dcsctp::UnwrappedSequenceNumber. Bug: webrtc:13982 Change-Id: Ia1b483d7ef5ceb43fa4d93013a76cd0251a58c22 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/287620 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Evan Shrubsole <eshr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38900}
203 lines
7.4 KiB
C++
203 lines
7.4 KiB
C++
/*
|
|
* Copyright (c) 2022 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 <cstdint>
|
|
#include <limits>
|
|
#include <type_traits>
|
|
|
|
#include "modules/include/module_common_types_public.h"
|
|
#include "net/dcsctp/common/sequence_numbers.h"
|
|
#include "rtc_base/numerics/sequence_number_util.h"
|
|
#include "rtc_base/strong_alias.h"
|
|
#include "rtc_base/time_utils.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
using ::testing::Test;
|
|
|
|
using dcsctp::UnwrappedSequenceNumber;
|
|
using Wrapped = webrtc::StrongAlias<class WrappedTag, uint32_t>;
|
|
using TestSequence = UnwrappedSequenceNumber<Wrapped>;
|
|
|
|
template <typename T>
|
|
class UnwrapperHelper;
|
|
|
|
template <>
|
|
class UnwrapperHelper<TestSequence::Unwrapper> {
|
|
public:
|
|
int64_t Unwrap(uint32_t val) {
|
|
TestSequence s = unwrapper_.Unwrap(Wrapped(val));
|
|
// UnwrappedSequenceNumber starts counting at 2^32.
|
|
constexpr int64_t kDcsctpUnwrapStart = int64_t{1} << 32;
|
|
return s.value() - kDcsctpUnwrapStart;
|
|
}
|
|
|
|
private:
|
|
TestSequence::Unwrapper unwrapper_;
|
|
};
|
|
|
|
// MaxVal is the max of the wrapped space, ie MaxVal + 1 = 0 when wrapped.
|
|
template <typename U, int64_t MaxVal = std::numeric_limits<uint32_t>::max()>
|
|
struct FixtureParams {
|
|
using Unwrapper = U;
|
|
static constexpr int64_t kMaxVal = MaxVal;
|
|
};
|
|
|
|
template <typename F>
|
|
class UnwrapperConformanceFixture : public Test {
|
|
public:
|
|
static constexpr int64_t kMaxVal = F::kMaxVal;
|
|
static constexpr int64_t kMaxIncrease = kMaxVal / 2;
|
|
static constexpr int64_t kMaxBackwardsIncrease = kMaxVal - kMaxIncrease + 1;
|
|
|
|
template <typename U>
|
|
static constexpr bool UnwrapperIs() {
|
|
return std::is_same<typename F::Unwrapper, U>();
|
|
}
|
|
|
|
typename F::Unwrapper ref_unwrapper_;
|
|
};
|
|
|
|
TYPED_TEST_SUITE_P(UnwrapperConformanceFixture);
|
|
|
|
TYPED_TEST_P(UnwrapperConformanceFixture, PositiveWrapAround) {
|
|
EXPECT_EQ(0, this->ref_unwrapper_.Unwrap(0));
|
|
EXPECT_EQ(TestFixture::kMaxIncrease,
|
|
this->ref_unwrapper_.Unwrap(TestFixture::kMaxIncrease));
|
|
EXPECT_EQ(2 * TestFixture::kMaxIncrease,
|
|
this->ref_unwrapper_.Unwrap(2 * TestFixture::kMaxIncrease));
|
|
// Now unwrapping 0 should wrap around to be kMaxVal + 1.
|
|
EXPECT_EQ(TestFixture::kMaxVal + 1, this->ref_unwrapper_.Unwrap(0));
|
|
EXPECT_EQ(TestFixture::kMaxVal + 1 + TestFixture::kMaxIncrease,
|
|
this->ref_unwrapper_.Unwrap(TestFixture::kMaxIncrease));
|
|
}
|
|
|
|
TYPED_TEST_P(UnwrapperConformanceFixture, NegativeUnwrap) {
|
|
using UnwrapperT = decltype(this->ref_unwrapper_);
|
|
// webrtc::TimestampUnwrapper known to not handle negative numbers.
|
|
// rtc::TimestampWrapAroundHandler does not wrap around correctly.
|
|
if constexpr (std::is_same<UnwrapperT, webrtc::TimestampUnwrapper>() ||
|
|
std::is_same<UnwrapperT, rtc::TimestampWrapAroundHandler>()) {
|
|
return;
|
|
}
|
|
EXPECT_EQ(0, this->ref_unwrapper_.Unwrap(0));
|
|
// Max backwards wrap is negative.
|
|
EXPECT_EQ(-TestFixture::kMaxIncrease,
|
|
this->ref_unwrapper_.Unwrap(this->kMaxBackwardsIncrease));
|
|
// Increase to a larger negative number.
|
|
EXPECT_EQ(-2, this->ref_unwrapper_.Unwrap(TestFixture::kMaxVal - 1));
|
|
// Increase back positive.
|
|
EXPECT_EQ(1, this->ref_unwrapper_.Unwrap(1));
|
|
}
|
|
|
|
TYPED_TEST_P(UnwrapperConformanceFixture, BackwardUnwrap) {
|
|
EXPECT_EQ(127, this->ref_unwrapper_.Unwrap(127));
|
|
EXPECT_EQ(128, this->ref_unwrapper_.Unwrap(128));
|
|
EXPECT_EQ(127, this->ref_unwrapper_.Unwrap(127));
|
|
}
|
|
|
|
TYPED_TEST_P(UnwrapperConformanceFixture, MultiplePositiveWrapArounds) {
|
|
using UnwrapperT = decltype(this->ref_unwrapper_);
|
|
// rtc::TimestampWrapAroundHandler does not wrap around correctly.
|
|
if constexpr (std::is_same<UnwrapperT, rtc::TimestampWrapAroundHandler>()) {
|
|
return;
|
|
}
|
|
int64_t val = 0;
|
|
uint32_t wrapped_val = 0;
|
|
for (int i = 0; i < 16; ++i) {
|
|
EXPECT_EQ(val, this->ref_unwrapper_.Unwrap(wrapped_val));
|
|
val += TestFixture::kMaxIncrease;
|
|
wrapped_val =
|
|
(wrapped_val + TestFixture::kMaxIncrease) % (TestFixture::kMaxVal + 1);
|
|
}
|
|
}
|
|
|
|
TYPED_TEST_P(UnwrapperConformanceFixture, WrapBoundaries) {
|
|
EXPECT_EQ(0, this->ref_unwrapper_.Unwrap(0));
|
|
EXPECT_EQ(TestFixture::kMaxIncrease,
|
|
this->ref_unwrapper_.Unwrap(TestFixture::kMaxIncrease));
|
|
// Increases by more than TestFixture::kMaxIncrease which indicates a negative
|
|
// rollback.
|
|
EXPECT_EQ(0, this->ref_unwrapper_.Unwrap(0));
|
|
EXPECT_EQ(10, this->ref_unwrapper_.Unwrap(10));
|
|
}
|
|
|
|
TYPED_TEST_P(UnwrapperConformanceFixture, MultipleNegativeWrapArounds) {
|
|
using UnwrapperT = decltype(this->ref_unwrapper_);
|
|
// webrtc::TimestampUnwrapper known to not handle negative numbers.
|
|
// webrtc::SequenceNumberUnwrapper can only wrap negative once.
|
|
// rtc::TimestampWrapAroundHandler does not wrap around correctly.
|
|
if constexpr (std::is_same<UnwrapperT, webrtc::TimestampUnwrapper>() ||
|
|
std::is_same<UnwrapperT,
|
|
UnwrapperHelper<TestSequence::Unwrapper>>() ||
|
|
std::is_same<UnwrapperT, rtc::TimestampWrapAroundHandler>()) {
|
|
return;
|
|
}
|
|
int64_t val = 0;
|
|
uint32_t wrapped_val = 0;
|
|
for (int i = 0; i < 16; ++i) {
|
|
EXPECT_EQ(val, this->ref_unwrapper_.Unwrap(wrapped_val));
|
|
val -= TestFixture::kMaxIncrease;
|
|
wrapped_val = (wrapped_val + this->kMaxBackwardsIncrease) %
|
|
(TestFixture::kMaxVal + 1);
|
|
}
|
|
}
|
|
|
|
REGISTER_TYPED_TEST_SUITE_P(UnwrapperConformanceFixture,
|
|
NegativeUnwrap,
|
|
PositiveWrapAround,
|
|
BackwardUnwrap,
|
|
WrapBoundaries,
|
|
MultiplePositiveWrapArounds,
|
|
MultipleNegativeWrapArounds);
|
|
|
|
constexpr int64_t k15BitMax = (int64_t{1} << 15) - 1;
|
|
using UnwrapperTypes = ::testing::Types<
|
|
FixtureParams<rtc::TimestampWrapAroundHandler>,
|
|
FixtureParams<webrtc::TimestampUnwrapper>,
|
|
FixtureParams<webrtc::SeqNumUnwrapper<uint32_t>>,
|
|
FixtureParams<UnwrapperHelper<TestSequence::Unwrapper>>,
|
|
// SeqNumUnwrapper supports arbitrary limits.
|
|
FixtureParams<webrtc::SeqNumUnwrapper<uint32_t, k15BitMax + 1>, k15BitMax>>;
|
|
|
|
class TestNames {
|
|
public:
|
|
template <typename T>
|
|
static std::string GetName(int) {
|
|
if constexpr (std::is_same<typename T::Unwrapper,
|
|
rtc::TimestampWrapAroundHandler>())
|
|
return "TimestampWrapAroundHandler";
|
|
if constexpr (std::is_same<typename T::Unwrapper,
|
|
webrtc::TimestampUnwrapper>())
|
|
return "TimestampUnwrapper";
|
|
if constexpr (std::is_same<typename T::Unwrapper,
|
|
webrtc::SeqNumUnwrapper<uint32_t>>())
|
|
return "SeqNumUnwrapper";
|
|
if constexpr (std::is_same<
|
|
typename T::Unwrapper,
|
|
webrtc::SeqNumUnwrapper<uint32_t, k15BitMax + 1>>())
|
|
return "SeqNumUnwrapper15bit";
|
|
if constexpr (std::is_same<typename T::Unwrapper,
|
|
UnwrapperHelper<TestSequence::Unwrapper>>())
|
|
return "UnwrappedSequenceNumber";
|
|
}
|
|
};
|
|
|
|
INSTANTIATE_TYPED_TEST_SUITE_P(UnwrapperConformanceTest,
|
|
UnwrapperConformanceFixture,
|
|
UnwrapperTypes,
|
|
TestNames);
|
|
|
|
} // namespace
|
|
} // namespace webrtc
|