/* * 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 #include #include #include "modules/include/module_common_types_public.h" #include "rtc_base/numerics/sequence_number_unwrapper.h" #include "rtc_base/time_utils.h" #include "test/gmock.h" #include "test/gtest.h" namespace webrtc { namespace { using ::testing::Test; // MaxVal is the max of the wrapped space, ie MaxVal + 1 = 0 when wrapped. template ::max()> struct FixtureParams { using Unwrapper = U; static constexpr int64_t kMaxVal = MaxVal; }; template 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 static constexpr bool UnwrapperIs() { return std::is_same(); } 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_); // TimestampUnwrapper known to not handle negative numbers. // rtc::TimestampWrapAroundHandler does not wrap around correctly. if constexpr (std::is_same() || std::is_same()) { 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()) { 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_); // TimestampUnwrapper known to not handle negative numbers. // SequenceNumberUnwrapper can only wrap negative once. // rtc::TimestampWrapAroundHandler does not wrap around correctly. if constexpr (std::is_same() || std::is_same()) { 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, FixtureParams, FixtureParams, // SeqNumUnwrapper supports arbitrary limits. FixtureParams, k15BitMax>>; class TestNames { public: template static std::string GetName(int) { if constexpr (std::is_same()) return "TimestampWrapAroundHandler"; if constexpr (std::is_same()) return "TimestampUnwrapper"; if constexpr (std::is_same>()) return "SeqNumUnwrapper"; if constexpr (std::is_same>()) return "SeqNumUnwrapper15bit"; } }; INSTANTIATE_TYPED_TEST_SUITE_P(UnwrapperConformanceTest, UnwrapperConformanceFixture, UnwrapperTypes, TestNames); } // namespace } // namespace webrtc