blob: a95c6dd64afac86141d5f8e18d368d619f3bd149 [file]
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "google/protobuf/offset_ptr.h"
#include <cstddef>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <gtest/gtest.h>
#include "google/protobuf/unittest.pb.h"
namespace google {
namespace protobuf {
namespace internal {
namespace {
int array[10];
TEST(BasePtrTest, Basic) {
BasePointer<int, false> b(&array[5], &array);
EXPECT_EQ(&array[5], b.Resolve(&array));
}
TEST(BasePtrTest, Copyable) {
EXPECT_TRUE(
(std::is_trivially_copy_constructible_v<BasePointer<int, false>>));
EXPECT_TRUE((std::is_trivially_copy_assignable_v<BasePointer<int, false>>));
EXPECT_TRUE((std::is_trivially_destructible_v<BasePointer<int, false>>));
BasePointer<int, false> b(&array[7], &array);
EXPECT_EQ(&array[7], b.Resolve(&array));
auto b2 = b;
EXPECT_EQ(&array[7], b2.Resolve(&array));
}
TEST(BasePtrTest, BaseCanBeOnEitherSide) {
EXPECT_EQ(&array[7],
(BasePointer<int, false>(&array[7], &array[3])).Resolve(&array[3]));
EXPECT_EQ(&array[4],
(BasePointer<int, false>(&array[4], &array[7])).Resolve(&array[7]));
}
TEST(BasePtrTest, BaseCanBeSameAsPointer) {
int var = 0;
EXPECT_EQ(&var, (BasePointer<int, false>(&var, &var)).Resolve(&var));
}
TEST(BasePtrTest, NullIsAllowed) {
bool dummy = false;
BasePointer<int, true> b(nullptr, &dummy);
EXPECT_EQ(nullptr, b.Resolve(&dummy));
int p = 0;
EXPECT_DEATH((BasePointer<int, true>(&p, &p)),
"Nullable base pointer can't self reference");
EXPECT_DEATH((BasePointer<int, false>(nullptr, &dummy)),
"Non-nullable base pointer constructed with a null pointer");
}
TEST(BasePtrTest, OutOfScopeFails) {
// For this one we manufacture pointers to make sure they trigger out of scope
// failures.
if (sizeof(void*) == 4) {
GTEST_SKIP() << "We need 64-bit to have out-of-scope pointers.";
}
void* base =
reinterpret_cast<void*>(static_cast<uintptr_t>(0x123457890abcdef));
const auto make_ptr = [&](ptrdiff_t diff) {
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(base) + diff);
};
using T = BasePointer<void, false>;
// INT_MAX is fine.
EXPECT_EQ(T(make_ptr(std::numeric_limits<int>::max()), base).Resolve(base),
make_ptr(std::numeric_limits<int>::max()));
// INT_MAX+1 is too much.
EXPECT_DEATH(
T(make_ptr(ptrdiff_t{std::numeric_limits<int>::max()} + 1), base),
"Pointer out of scope for offset pointer");
// INT_MIN is fine.
EXPECT_EQ(T(make_ptr(std::numeric_limits<int>::min()), base).Resolve(base),
make_ptr(std::numeric_limits<int>::min()));
// INT_MIN-1 is too much.
EXPECT_DEATH(
T(make_ptr(ptrdiff_t{std::numeric_limits<int>::min()} - 1), base),
"Pointer out of scope for offset pointer");
}
TEST(OffsetPtrTest, Basic) {
// Collocate the pointer and the pointee in the same block of memory.
struct Object {
int array[10];
OffsetPtr<int, false> ptr;
} object{};
object.ptr = object.array + 3;
EXPECT_EQ(object.ptr, object.array + 3);
}
TEST(OffsetProtoPtr, Basic) {
using P = proto2_unittest::TestAllTypes;
// Collocate the pointer and the pointee in the same block of memory.
struct Object {
OffsetProtoPtr<const P> p;
P msg;
} object;
object.p = nullptr;
EXPECT_EQ(&P::default_instance(), object.p);
object.p = &object.msg;
EXPECT_EQ(&object.msg, object.p);
object.p = &P::default_instance();
EXPECT_EQ(&P::default_instance(), object.p);
}
} // namespace
} // namespace internal
} // namespace protobuf
} // namespace google