// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "mojo/system/options_validation.h" #include #include #include "mojo/public/c/system/macros.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { namespace system { namespace { // Declare a test options struct just as we do in actual public headers. typedef uint32_t TestOptionsFlags; MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment); struct MOJO_ALIGNAS(8) TestOptions { uint32_t struct_size; TestOptionsFlags flags; uint32_t member1; uint32_t member2; }; MOJO_COMPILE_ASSERT(sizeof(TestOptions) == 16, TestOptions_has_wrong_size); const uint32_t kSizeOfTestOptions = static_cast(sizeof(TestOptions)); TEST(OptionsValidationTest, Valid) { const TestOptions kOptions1 = { kSizeOfTestOptions }; EXPECT_TRUE(IsOptionsStructPointerAndSizeValid(&kOptions1)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, &kOptions1)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, &kOptions1)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, &kOptions1)); const TestOptions kOptions2 = { static_cast(offsetof(TestOptions, struct_size) + sizeof(uint32_t)) }; EXPECT_TRUE(IsOptionsStructPointerAndSizeValid(&kOptions2)); EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, &kOptions2)); EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, &kOptions2)); EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, &kOptions2)); const TestOptions kOptions3 = { static_cast(offsetof(TestOptions, flags) + sizeof(uint32_t)) }; EXPECT_TRUE(IsOptionsStructPointerAndSizeValid(&kOptions3)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, &kOptions3)); EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, &kOptions3)); EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, &kOptions3)); MOJO_ALIGNAS(8) char buf[sizeof(TestOptions) + 100] = {}; TestOptions* options = reinterpret_cast(buf); options->struct_size = kSizeOfTestOptions + 1; EXPECT_TRUE(IsOptionsStructPointerAndSizeValid(options)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, options)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, options)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, options)); options->struct_size = kSizeOfTestOptions + 4; EXPECT_TRUE(IsOptionsStructPointerAndSizeValid(options)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, options)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, options)); EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, options)); } TEST(OptionsValidationTest, Invalid) { // Null: EXPECT_FALSE(IsOptionsStructPointerAndSizeValid(NULL)); // Unaligned: EXPECT_FALSE(IsOptionsStructPointerAndSizeValid( reinterpret_cast(1))); EXPECT_FALSE(IsOptionsStructPointerAndSizeValid( reinterpret_cast(4))); // Size too small: for (size_t i = 0; i < sizeof(uint32_t); i++) { TestOptions options = {static_cast(i)}; EXPECT_FALSE(IsOptionsStructPointerAndSizeValid(&options)) << i; } } TEST(OptionsValidationTest, CheckFlags) { const TestOptions kOptions1 = {kSizeOfTestOptions, 0}; EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions1, 0u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions1, 1u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions1, 3u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions1, 7u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions1, ~0u)); const TestOptions kOptions2 = {kSizeOfTestOptions, 1}; EXPECT_FALSE(AreOptionsFlagsAllKnown(&kOptions2, 0u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions2, 1u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions2, 3u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions2, 7u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions2, ~0u)); const TestOptions kOptions3 = {kSizeOfTestOptions, 2}; EXPECT_FALSE(AreOptionsFlagsAllKnown(&kOptions3, 0u)); EXPECT_FALSE(AreOptionsFlagsAllKnown(&kOptions3, 1u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions3, 3u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions3, 7u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions3, ~0u)); const TestOptions kOptions4 = {kSizeOfTestOptions, 5}; EXPECT_FALSE(AreOptionsFlagsAllKnown(&kOptions4, 0u)); EXPECT_FALSE(AreOptionsFlagsAllKnown(&kOptions4, 1u)); EXPECT_FALSE(AreOptionsFlagsAllKnown(&kOptions4, 3u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions4, 7u)); EXPECT_TRUE(AreOptionsFlagsAllKnown(&kOptions4, ~0u)); } TEST(OptionsValidationTest, ValidateOptionsStructPointerSizeAndFlags) { const TestOptions kDefaultOptions = {kSizeOfTestOptions, 1u, 123u, 456u}; // Valid cases: // "Normal": { const TestOptions kOptions = {kSizeOfTestOptions, 0u, 12u, 34u}; TestOptions validated_options = kDefaultOptions; EXPECT_EQ(MOJO_RESULT_OK, ValidateOptionsStructPointerSizeAndFlags( &kOptions, 3u, &validated_options)); EXPECT_EQ(kDefaultOptions.struct_size, validated_options.struct_size); // Copied |flags|. EXPECT_EQ(kOptions.flags, validated_options.flags); // Didn't touch subsequent members. EXPECT_EQ(kDefaultOptions.member1, validated_options.member1); EXPECT_EQ(kDefaultOptions.member2, validated_options.member2); } // Doesn't actually have |flags|: { const TestOptions kOptions = { static_cast(sizeof(uint32_t)), 0u, 12u, 34u }; TestOptions validated_options = kDefaultOptions; EXPECT_EQ(MOJO_RESULT_OK, ValidateOptionsStructPointerSizeAndFlags( &kOptions, 3u, &validated_options)); EXPECT_EQ(kDefaultOptions.struct_size, validated_options.struct_size); // Didn't copy |flags|. EXPECT_EQ(kDefaultOptions.flags, validated_options.flags); // Didn't touch subsequent members. EXPECT_EQ(kDefaultOptions.member1, validated_options.member1); EXPECT_EQ(kDefaultOptions.member2, validated_options.member2); } // Invalid cases: // Unaligned: { TestOptions validated_options = kDefaultOptions; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, ValidateOptionsStructPointerSizeAndFlags( reinterpret_cast(1), 3u, &validated_options)); } // |struct_size| too small: { const TestOptions kOptions = {1u, 0u, 12u, 34u}; TestOptions validated_options = kDefaultOptions; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, ValidateOptionsStructPointerSizeAndFlags( &kOptions, 3u, &validated_options)); } // Unknown |flag|: { const TestOptions kOptions = {kSizeOfTestOptions, 5u, 12u, 34u}; TestOptions validated_options = kDefaultOptions; EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, ValidateOptionsStructPointerSizeAndFlags( &kOptions, 3u, &validated_options)); } } } // namespace } // namespace system } // namespace mojo