1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "mojo/system/options_validation.h" 6 7 #include <stddef.h> 8 #include <stdint.h> 9 10 #include "mojo/public/c/system/macros.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 13 namespace mojo { 14 namespace system { 15 namespace { 16 17 // Declare a test options struct just as we do in actual public headers. 18 19 typedef uint32_t TestOptionsFlags; 20 21 MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment); 22 struct MOJO_ALIGNAS(8) TestOptions { 23 uint32_t struct_size; 24 TestOptionsFlags flags; 25 uint32_t member1; 26 uint32_t member2; 27 }; 28 MOJO_COMPILE_ASSERT(sizeof(TestOptions) == 16, TestOptions_has_wrong_size); 29 30 const uint32_t kSizeOfTestOptions = static_cast<uint32_t>(sizeof(TestOptions)); 31 32 TEST(OptionsValidationTest, Valid) { 33 const TestOptions kOptions1 = { 34 kSizeOfTestOptions 35 }; 36 37 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(&kOptions1)); 38 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, &kOptions1)); 39 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, &kOptions1)); 40 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, &kOptions1)); 41 42 const TestOptions kOptions2 = { 43 static_cast<uint32_t>(offsetof(TestOptions, struct_size) + sizeof(uint32_t)) 44 }; 45 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(&kOptions2)); 46 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, &kOptions2)); 47 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, &kOptions2)); 48 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, &kOptions2)); 49 50 const TestOptions kOptions3 = { 51 static_cast<uint32_t>(offsetof(TestOptions, flags) + sizeof(uint32_t)) 52 }; 53 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(&kOptions3)); 54 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, &kOptions3)); 55 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, &kOptions3)); 56 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, &kOptions3)); 57 58 MOJO_ALIGNAS(8) char buf[sizeof(TestOptions) + 100] = {}; 59 TestOptions* options = reinterpret_cast<TestOptions*>(buf); 60 options->struct_size = kSizeOfTestOptions + 1; 61 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(options)); 62 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, options)); 63 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, options)); 64 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, options)); 65 66 options->struct_size = kSizeOfTestOptions + 4; 67 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(options)); 68 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, options)); 69 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, options)); 70 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, options)); 71 } 72 73 TEST(OptionsValidationTest, Invalid) { 74 // Null: 75 EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>(NULL)); 76 77 // Unaligned: 78 EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>( 79 reinterpret_cast<const void*>(1))); 80 EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>( 81 reinterpret_cast<const void*>(4))); 82 83 // Size too small: 84 for (size_t i = 0; i < sizeof(uint32_t); i++) { 85 TestOptions options = {static_cast<uint32_t>(i)}; 86 EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>(&options)) 87 << i; 88 } 89 } 90 91 TEST(OptionsValidationTest, CheckFlags) { 92 const TestOptions kOptions1 = {kSizeOfTestOptions, 0}; 93 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 0u)); 94 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 1u)); 95 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 3u)); 96 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 7u)); 97 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, ~0u)); 98 99 const TestOptions kOptions2 = {kSizeOfTestOptions, 1}; 100 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 0u)); 101 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 1u)); 102 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 3u)); 103 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 7u)); 104 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, ~0u)); 105 106 const TestOptions kOptions3 = {kSizeOfTestOptions, 2}; 107 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 0u)); 108 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 1u)); 109 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 3u)); 110 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 7u)); 111 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, ~0u)); 112 113 const TestOptions kOptions4 = {kSizeOfTestOptions, 5}; 114 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 0u)); 115 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 1u)); 116 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 3u)); 117 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 7u)); 118 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, ~0u)); 119 } 120 121 TEST(OptionsValidationTest, ValidateOptionsStructPointerSizeAndFlags) { 122 const TestOptions kDefaultOptions = {kSizeOfTestOptions, 1u, 123u, 456u}; 123 124 // Valid cases: 125 126 // "Normal": 127 { 128 const TestOptions kOptions = {kSizeOfTestOptions, 0u, 12u, 34u}; 129 TestOptions validated_options = kDefaultOptions; 130 EXPECT_EQ(MOJO_RESULT_OK, 131 ValidateOptionsStructPointerSizeAndFlags<TestOptions>( 132 &kOptions, 3u, &validated_options)); 133 EXPECT_EQ(kDefaultOptions.struct_size, validated_options.struct_size); 134 // Copied |flags|. 135 EXPECT_EQ(kOptions.flags, validated_options.flags); 136 // Didn't touch subsequent members. 137 EXPECT_EQ(kDefaultOptions.member1, validated_options.member1); 138 EXPECT_EQ(kDefaultOptions.member2, validated_options.member2); 139 } 140 141 // Doesn't actually have |flags|: 142 { 143 const TestOptions kOptions = { 144 static_cast<uint32_t>(sizeof(uint32_t)), 0u, 12u, 34u 145 }; 146 TestOptions validated_options = kDefaultOptions; 147 EXPECT_EQ(MOJO_RESULT_OK, 148 ValidateOptionsStructPointerSizeAndFlags<TestOptions>( 149 &kOptions, 3u, &validated_options)); 150 EXPECT_EQ(kDefaultOptions.struct_size, validated_options.struct_size); 151 // Didn't copy |flags|. 152 EXPECT_EQ(kDefaultOptions.flags, validated_options.flags); 153 // Didn't touch subsequent members. 154 EXPECT_EQ(kDefaultOptions.member1, validated_options.member1); 155 EXPECT_EQ(kDefaultOptions.member2, validated_options.member2); 156 } 157 158 // Invalid cases: 159 160 // Unaligned: 161 { 162 TestOptions validated_options = kDefaultOptions; 163 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, 164 ValidateOptionsStructPointerSizeAndFlags<TestOptions>( 165 reinterpret_cast<const TestOptions*>(1), 3u, 166 &validated_options)); 167 } 168 169 // |struct_size| too small: 170 { 171 const TestOptions kOptions = {1u, 0u, 12u, 34u}; 172 TestOptions validated_options = kDefaultOptions; 173 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, 174 ValidateOptionsStructPointerSizeAndFlags<TestOptions>( 175 &kOptions, 3u, &validated_options)); 176 } 177 178 // Unknown |flag|: 179 { 180 const TestOptions kOptions = {kSizeOfTestOptions, 5u, 12u, 34u}; 181 TestOptions validated_options = kDefaultOptions; 182 EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, 183 ValidateOptionsStructPointerSizeAndFlags<TestOptions>( 184 &kOptions, 3u, &validated_options)); 185 } 186 } 187 188 } // namespace 189 } // namespace system 190 } // namespace mojo 191