C++程序  |  337行  |  11.58 KB

/*
 * Copyright (C) 2016, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <array>
#include <tuple>
#include <vector>

#include "gtest/gtest.h"

#include "wifilogd/message_buffer.h"

namespace android {
namespace wifilogd {
namespace {

constexpr size_t kBufferSizeBytes = 1024;
constexpr size_t kHeaderSizeBytes = MessageBuffer::GetHeaderSize();
constexpr std::array<uint8_t, 1> kSmallestMessage{};
constexpr std::array<uint8_t, kBufferSizeBytes - kHeaderSizeBytes>
    kLargestMessage{};

class MessageBufferTest : public ::testing::Test {
 public:
  MessageBufferTest() : buffer_{kBufferSizeBytes} {}

 protected:
  size_t FillBufferWithMultipleMessages() {
    constexpr std::array<uint8_t, kHeaderSizeBytes> message{};
    static_assert(kBufferSizeBytes % (kHeaderSizeBytes + message.size()) == 0,
                  "messages will not fill buffer to capacity");
    size_t n_written;
    for (n_written = 0;
         n_written < kBufferSizeBytes / (kHeaderSizeBytes + message.size());
         ++n_written) {
      EXPECT_TRUE(buffer_.Append(message.data(), message.size()));
    }
    EXPECT_EQ(0U, buffer_.GetFreeSize());
    return n_written;
  }

  std::vector<uint8_t> GetNextMessageAsByteVector() {
    const uint8_t* start;
    size_t len;
    std::tie(start, len) = buffer_.ConsumeNextMessage();
    return {start, start + len};
  }

  MessageBuffer buffer_;
};

}  // namespace

TEST_F(MessageBufferTest, AppendMinimalOnEmptyBufferSucceeds) {
  EXPECT_TRUE(buffer_.Append(kSmallestMessage.data(), kSmallestMessage.size()));
}

TEST_F(MessageBufferTest, AppendMaximalOnEmptyBufferSucceeds) {
  EXPECT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
}

TEST_F(MessageBufferTest, AppendMaximalAfterFillAndClearSucceeds) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  ASSERT_FALSE(buffer_.CanFitNow(1));

  buffer_.Clear();
  EXPECT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
}

TEST_F(MessageBufferTest, AppendUnalignedMessagesDoesNotCrash) {
  // Odd-length messages should trigger alignment problems, if any such
  // problems exist. We'll need more than one, though, since the first header
  // might be aligned by default.
  constexpr std::array<uint8_t, 1> message{};
  while (buffer_.CanFitNow(message.size())) {
    ASSERT_TRUE(buffer_.Append(message.data(), message.size()));
  }
}

TEST_F(MessageBufferTest, AppendLargerThanBufferFails) {
  constexpr std::array<uint8_t, kBufferSizeBytes + 1> oversized_message{};
  EXPECT_FALSE(
      buffer_.Append(oversized_message.data(), oversized_message.size()));
}

TEST_F(MessageBufferTest, AppendLargerThanFreeSpaceFails) {
  constexpr size_t expected_free = kBufferSizeBytes - kHeaderSizeBytes;
  ASSERT_FALSE(buffer_.CanFitNow(expected_free + 1));

  constexpr std::array<uint8_t, expected_free + 1> oversized_message{};
  EXPECT_FALSE(
      buffer_.Append(oversized_message.data(), oversized_message.size()));
}

TEST_F(MessageBufferTest, AppendMultipleMessagesToFillBufferDoesNotCrash) {
  FillBufferWithMultipleMessages();
}

TEST_F(MessageBufferTest, CanFitNowIsCorrectOnFreshBuffer) {
  EXPECT_TRUE(buffer_.CanFitNow(kLargestMessage.size()));
  EXPECT_FALSE(buffer_.CanFitNow(kLargestMessage.size() + 1));
}

TEST_F(MessageBufferTest, CanFitNowIsCorrectAfterSmallWrite) {
  ASSERT_TRUE(buffer_.Append(kSmallestMessage.data(), kSmallestMessage.size()));

  constexpr size_t expected_free =
      kBufferSizeBytes - (kSmallestMessage.size() + kHeaderSizeBytes) -
      kHeaderSizeBytes;
  EXPECT_TRUE(buffer_.CanFitNow(expected_free));
  EXPECT_FALSE(buffer_.CanFitNow(expected_free + 1));
}

TEST_F(MessageBufferTest, CanFitNowIsCorrectOnFullBuffer) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  EXPECT_FALSE(buffer_.CanFitNow(1));
}

TEST_F(MessageBufferTest, CanFitNowIsCorrectOnRewoundBuffer) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  buffer_.Rewind();
  EXPECT_FALSE(buffer_.CanFitNow(1));
}

TEST_F(MessageBufferTest, CanFitNowIsCorrectAfterClear) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  ASSERT_FALSE(buffer_.CanFitNow(1));

  buffer_.Clear();
  EXPECT_TRUE(buffer_.CanFitNow(kLargestMessage.size()));
}

TEST_F(MessageBufferTest, CanFitEverIsCorrectOnFreshBuffer) {
  EXPECT_TRUE(buffer_.CanFitEver(kLargestMessage.size()));
  EXPECT_FALSE(buffer_.CanFitEver(kLargestMessage.size() + 1));
}

TEST_F(MessageBufferTest, CanFitEverIsCorrectAfterSmallWrite) {
  ASSERT_TRUE(buffer_.Append(kSmallestMessage.data(), kSmallestMessage.size()));
  EXPECT_TRUE(buffer_.CanFitEver(kLargestMessage.size()));
  EXPECT_FALSE(buffer_.CanFitEver(kLargestMessage.size() + 1));
}

TEST_F(MessageBufferTest, CanFitEverIsCorrectOnFullBuffer) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  EXPECT_TRUE(buffer_.CanFitEver(kLargestMessage.size()));
  EXPECT_FALSE(buffer_.CanFitEver(kLargestMessage.size() + 1));
}

TEST_F(MessageBufferTest, CanFitEverIsCorrectAfterRewind) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  buffer_.Rewind();
  EXPECT_TRUE(buffer_.CanFitEver(kLargestMessage.size()));
  EXPECT_FALSE(buffer_.CanFitEver(kLargestMessage.size() + 1));
}

TEST_F(MessageBufferTest, CanFitEverIsCorrectAfterClear) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  buffer_.Clear();
  EXPECT_TRUE(buffer_.CanFitEver(kLargestMessage.size()));
  EXPECT_FALSE(buffer_.CanFitEver(kLargestMessage.size() + 1));
}

TEST_F(MessageBufferTest, ConsumeNextMessageReturnsNullOnFreshBuffer) {
  const std::tuple<const uint8_t*, size_t> expected{nullptr, 0};
  EXPECT_EQ(expected, buffer_.ConsumeNextMessage());
}

TEST_F(MessageBufferTest, ConsumeNextMessageReturnsNullAfterFillAndClear) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  buffer_.Clear();

  const std::tuple<const uint8_t*, size_t> expected{nullptr, 0};
  EXPECT_EQ(expected, buffer_.ConsumeNextMessage());
}

TEST_F(MessageBufferTest, ConsumeNextMessageCanReadMinimalMessage) {
  ASSERT_TRUE(buffer_.Append(kSmallestMessage.data(), kSmallestMessage.size()));

  const auto& ptr_and_size = buffer_.ConsumeNextMessage();
  EXPECT_NE(nullptr, std::get<0>(ptr_and_size));
  EXPECT_EQ(kSmallestMessage.size(), std::get<1>(ptr_and_size));
}

TEST_F(MessageBufferTest, ConsumeNextMessageCanReadMaximalMessage) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));

  const auto& ptr_and_size = buffer_.ConsumeNextMessage();
  EXPECT_NE(nullptr, std::get<0>(ptr_and_size));
  EXPECT_EQ(kLargestMessage.size(), std::get<1>(ptr_and_size));
}

TEST_F(MessageBufferTest,
       ConsumeNextMessageReturnsNullAfterMinimalMessageIsConsumed) {
  ASSERT_TRUE(buffer_.Append(kSmallestMessage.data(), kSmallestMessage.size()));
  buffer_.ConsumeNextMessage();

  constexpr std::tuple<const uint8_t*, size_t> expected{nullptr, 0};
  EXPECT_EQ(expected, buffer_.ConsumeNextMessage());
}

TEST_F(MessageBufferTest,
       ConsumeNextMessageReturnsNullAfterMaximalMessageIsConsumed) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  buffer_.ConsumeNextMessage();

  constexpr std::tuple<const uint8_t*, size_t> expected{nullptr, 0};
  EXPECT_EQ(expected, buffer_.ConsumeNextMessage());
}

TEST_F(MessageBufferTest,
       ConsumeNextMessageCanRetreiveAllMessagesFromFullBuffer) {
  const size_t n_written = FillBufferWithMultipleMessages();
  size_t n_read = 0;
  while (std::get<0>(buffer_.ConsumeNextMessage())) {
    ++n_read;
  }
  EXPECT_EQ(n_written, n_read);

  constexpr std::tuple<const uint8_t*, size_t> expected{nullptr, 0};
  EXPECT_EQ(expected, buffer_.ConsumeNextMessage());
}

TEST_F(MessageBufferTest,
       ConsumeNextMessageCanRetreiveAllMessagesFromRewoundBuffer) {
  const size_t n_written = FillBufferWithMultipleMessages();
  while (std::get<0>(buffer_.ConsumeNextMessage())) {
    // Silently consume message
  }
  buffer_.Rewind();

  size_t n_read = 0;
  while (std::get<0>(buffer_.ConsumeNextMessage())) {
    ++n_read;
  }
  EXPECT_EQ(n_written, n_read);
}

TEST_F(MessageBufferTest,
       ConsumeNextMessageCanRetreiveMultipleUnaliagnedMessages) {
  // As in AppendUnalignedMessagesDoesNotCrash, odd-length messages should
  // trigger alignment problems, if any such problems exist.
  const std::array<uint8_t, 1> message{};
  size_t n_written = 0;
  while (buffer_.CanFitNow(message.size())) {
    ASSERT_TRUE(buffer_.Append(message.data(), message.size()));
    ++n_written;
  }

  size_t n_read = 0;
  while (std::get<0>(buffer_.ConsumeNextMessage())) {
    ++n_read;
  }
  EXPECT_EQ(n_written, n_read);
}

TEST_F(MessageBufferTest, ConsumeNextMessageReturnsOurMessages) {
  const std::vector<uint8_t> message1{{'h', 'e', 'l', 'l', 'o'}};
  const std::vector<uint8_t> message2{{'w', 'o', 'r', 'l', 'd'}};
  ASSERT_TRUE(
      buffer_.Append(message1.data(), static_cast<uint16_t>(message1.size())));
  ASSERT_TRUE(
      buffer_.Append(message2.data(), static_cast<uint16_t>(message2.size())));
  EXPECT_EQ(message1, GetNextMessageAsByteVector());
  EXPECT_EQ(message2, GetNextMessageAsByteVector());
}

TEST_F(MessageBufferTest, GetFreeSizeIsCorrectOnFreshBuffer) {
  EXPECT_EQ(kBufferSizeBytes, buffer_.GetFreeSize());
}

TEST_F(MessageBufferTest, GetFreeSizeIsCorrectAfterSmallWrite) {
  ASSERT_TRUE(buffer_.Append(kSmallestMessage.data(), kSmallestMessage.size()));
  EXPECT_EQ(kBufferSizeBytes - kHeaderSizeBytes - kSmallestMessage.size(),
            buffer_.GetFreeSize());
}

TEST_F(MessageBufferTest, GetFreeSizeIsCorrectOnFullBuffer) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  EXPECT_EQ(0U, buffer_.GetFreeSize());
}

TEST_F(MessageBufferTest, GetFreeSizeIsCorrectAfterRewindOfFullBuffer) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  buffer_.Rewind();
  EXPECT_EQ(0U, buffer_.GetFreeSize());
}

TEST_F(MessageBufferTest, GetFreeSizeIsCorrectAfterClear) {
  ASSERT_TRUE(buffer_.Append(kLargestMessage.data(), kLargestMessage.size()));
  buffer_.Clear();
  EXPECT_EQ(kBufferSizeBytes, buffer_.GetFreeSize());
}

TEST_F(MessageBufferTest, RewindDoesNotAffectWritePointer) {
  const std::vector<uint8_t> message1{{'h', 'e', 'l', 'l', 'o'}};
  ASSERT_TRUE(
      buffer_.Append(message1.data(), static_cast<uint16_t>(message1.size())));
  buffer_.Rewind();

  const std::vector<uint8_t> message2{{'w', 'o', 'r', 'l', 'd'}};
  ASSERT_TRUE(
      buffer_.Append(message2.data(), static_cast<uint16_t>(message2.size())));

  EXPECT_EQ(message1, GetNextMessageAsByteVector());
  EXPECT_EQ(message2, GetNextMessageAsByteVector());
}

// Per
// github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#death-tests,
// death tests should be specially named.
using MessageBufferDeathTest = MessageBufferTest;

TEST_F(MessageBufferDeathTest, AppendZeroBytesCausesDeath) {
  constexpr std::array<uint8_t, 1> message{};
  EXPECT_DEATH(buffer_.Append(message.data(), 0), "Check failed");
}

TEST_F(MessageBufferDeathTest, ConstructionOfUselesslySmallBufferCausesDeath) {
  EXPECT_DEATH(MessageBuffer{kHeaderSizeBytes}, "Check failed");
}

}  // namespace wifilogd
}  // namespace android