| // 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 <stddef.h> |
| #include <stdint.h> |
| |
| #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<uint32_t>(sizeof(TestOptions)); |
| |
| TEST(OptionsValidationTest, Valid) { |
| const TestOptions kOptions1 = { |
| kSizeOfTestOptions |
| }; |
| |
| EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(&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<uint32_t>(offsetof(TestOptions, struct_size) + sizeof(uint32_t)) |
| }; |
| EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(&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<uint32_t>(offsetof(TestOptions, flags) + sizeof(uint32_t)) |
| }; |
| EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(&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<TestOptions*>(buf); |
| options->struct_size = kSizeOfTestOptions + 1; |
| EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(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<TestOptions>(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<TestOptions>(NULL)); |
| |
| // Unaligned: |
| EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>( |
| reinterpret_cast<const void*>(1))); |
| EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>( |
| reinterpret_cast<const void*>(4))); |
| |
| // Size too small: |
| for (size_t i = 0; i < sizeof(uint32_t); i++) { |
| TestOptions options = {static_cast<uint32_t>(i)}; |
| EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>(&options)) |
| << i; |
| } |
| } |
| |
| TEST(OptionsValidationTest, CheckFlags) { |
| const TestOptions kOptions1 = {kSizeOfTestOptions, 0}; |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 0u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 1u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 3u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 7u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, ~0u)); |
| |
| const TestOptions kOptions2 = {kSizeOfTestOptions, 1}; |
| EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 0u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 1u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 3u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 7u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, ~0u)); |
| |
| const TestOptions kOptions3 = {kSizeOfTestOptions, 2}; |
| EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 0u)); |
| EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 1u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 3u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 7u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, ~0u)); |
| |
| const TestOptions kOptions4 = {kSizeOfTestOptions, 5}; |
| EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 0u)); |
| EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 1u)); |
| EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 3u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 7u)); |
| EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&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<TestOptions>( |
| &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<uint32_t>(sizeof(uint32_t)), 0u, 12u, 34u |
| }; |
| TestOptions validated_options = kDefaultOptions; |
| EXPECT_EQ(MOJO_RESULT_OK, |
| ValidateOptionsStructPointerSizeAndFlags<TestOptions>( |
| &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<TestOptions>( |
| reinterpret_cast<const TestOptions*>(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<TestOptions>( |
| &kOptions, 3u, &validated_options)); |
| } |
| |
| // Unknown |flag|: |
| { |
| const TestOptions kOptions = {kSizeOfTestOptions, 5u, 12u, 34u}; |
| TestOptions validated_options = kDefaultOptions; |
| EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, |
| ValidateOptionsStructPointerSizeAndFlags<TestOptions>( |
| &kOptions, 3u, &validated_options)); |
| } |
| } |
| |
| } // namespace |
| } // namespace system |
| } // namespace mojo |