| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stdio.h> | 5 #include <stdio.h> |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <sstream> | 8 #include <sstream> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "mojo/public/cpp/bindings/lib/message_header_validator.h" | 12 #include "mojo/public/cpp/bindings/lib/message_header_validator.h" |
| 13 #include "mojo/public/cpp/bindings/lib/validation_errors.h" | 13 #include "mojo/public/cpp/bindings/lib/validation_errors.h" |
| 14 #include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h" |
| 14 #include "mojo/public/cpp/test_support/test_support.h" | 15 #include "mojo/public/cpp/test_support/test_support.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
| 16 | 17 |
| 17 namespace mojo { | 18 namespace mojo { |
| 18 namespace test { | 19 namespace test { |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| 21 std::string ValidationErrorToResultString(internal::ValidationError error) { | 22 template <typename T> |
| 22 std::string result = internal::ValidationErrorToString(error); | 23 void Append(std::vector<uint8_t>* data_vector, T data) { |
| 23 result.push_back('\n'); | 24 size_t pos = data_vector->size(); |
| 24 return result; | 25 data_vector->resize(pos + sizeof(T)); |
| 26 memcpy(&(*data_vector)[pos], &data, sizeof(T)); |
| 27 } |
| 28 |
| 29 bool TestInputParser(const std::string& input, |
| 30 bool expected_result, |
| 31 const std::vector<uint8_t>& expected_parsed_input) { |
| 32 std::vector<uint8_t> parsed_input; |
| 33 std::string error_message; |
| 34 |
| 35 bool result = ParseValidationTestInput(input, &parsed_input, &error_message); |
| 36 if (expected_result) { |
| 37 if (result && error_message.empty() && |
| 38 expected_parsed_input == parsed_input) { |
| 39 return true; |
| 40 } |
| 41 |
| 42 // Compare with an empty string instead of checking |error_message.empty()|, |
| 43 // so that the message will be printed out if the two are not equal. |
| 44 EXPECT_EQ(std::string(), error_message); |
| 45 EXPECT_EQ(expected_parsed_input, parsed_input); |
| 46 return false; |
| 47 } |
| 48 |
| 49 EXPECT_FALSE(error_message.empty()); |
| 50 return !result && !error_message.empty(); |
| 25 } | 51 } |
| 26 | 52 |
| 27 std::vector<std::string> GetMatchingTests(const std::vector<std::string>& names, | 53 std::vector<std::string> GetMatchingTests(const std::vector<std::string>& names, |
| 28 const std::string& prefix) { | 54 const std::string& prefix) { |
| 29 const std::string suffix = ".data"; | 55 const std::string suffix = ".data"; |
| 30 std::vector<std::string> tests; | 56 std::vector<std::string> tests; |
| 31 for (size_t i = 0; i < names.size(); ++i) { | 57 for (size_t i = 0; i < names.size(); ++i) { |
| 32 if (names[i].size() >= suffix.size() && | 58 if (names[i].size() >= suffix.size() && |
| 33 names[i].substr(0, prefix.size()) == prefix && | 59 names[i].substr(0, prefix.size()) == prefix && |
| 34 names[i].substr(names[i].size() - suffix.size()) == suffix) | 60 names[i].substr(names[i].size() - suffix.size()) == suffix) |
| 35 tests.push_back(names[i].substr(0, names[i].size() - suffix.size())); | 61 tests.push_back(names[i].substr(0, names[i].size() - suffix.size())); |
| 36 } | 62 } |
| 37 return tests; | 63 return tests; |
| 38 } | 64 } |
| 39 | 65 |
| 40 bool ReadDataFile(const std::string& path, std::vector<uint8_t>* result) { | 66 bool ReadFile(const std::string& path, std::string* result) { |
| 41 FILE* fp = OpenSourceRootRelativeFile(path.c_str()); | 67 FILE* fp = OpenSourceRootRelativeFile(path.c_str()); |
| 42 if (!fp) { | 68 if (!fp) { |
| 43 ADD_FAILURE() << "File not found: " << path; | 69 ADD_FAILURE() << "File not found: " << path; |
| 44 return false; | 70 return false; |
| 45 } | 71 } |
| 46 for (;;) { | |
| 47 unsigned int value; | |
| 48 int rv = fscanf(fp, "%x", &value); | |
| 49 if (rv != 1) | |
| 50 break; | |
| 51 result->push_back(static_cast<uint8_t>(value & 0xFF)); | |
| 52 } | |
| 53 bool error = ferror(fp); | |
| 54 fclose(fp); | |
| 55 return !error; | |
| 56 } | |
| 57 | |
| 58 bool ReadResultFile(const std::string& path, std::string* result) { | |
| 59 FILE* fp = OpenSourceRootRelativeFile(path.c_str()); | |
| 60 if (!fp) | |
| 61 return false; | |
| 62 fseek(fp, 0, SEEK_END); | 72 fseek(fp, 0, SEEK_END); |
| 63 size_t size = static_cast<size_t>(ftell(fp)); | 73 size_t size = static_cast<size_t>(ftell(fp)); |
| 64 if (size == 0) { | 74 if (size == 0) { |
| 65 // Result files should never be empty. | 75 result->clear(); |
| 66 fclose(fp); | 76 fclose(fp); |
| 67 return false; | 77 return true; |
| 68 } | 78 } |
| 69 fseek(fp, 0, SEEK_SET); | 79 fseek(fp, 0, SEEK_SET); |
| 70 result->resize(size); | 80 result->resize(size); |
| 71 size_t size_read = fread(&result->at(0), 1, size, fp); | 81 size_t size_read = fread(&result->at(0), 1, size, fp); |
| 72 fclose(fp); | 82 fclose(fp); |
| 73 if (size != size_read) | 83 return size == size_read; |
| 84 } |
| 85 |
| 86 bool ReadAndParseDataFile(const std::string& path, std::vector<uint8_t>* data) { |
| 87 std::string input; |
| 88 if (!ReadFile(path, &input)) |
| 74 return false; | 89 return false; |
| 90 |
| 91 std::string error_message; |
| 92 if (!ParseValidationTestInput(input, data, &error_message)) { |
| 93 ADD_FAILURE() << error_message; |
| 94 return false; |
| 95 } |
| 96 |
| 97 return true; |
| 98 } |
| 99 |
| 100 bool ReadResultFile(const std::string& path, std::string* result) { |
| 101 if (!ReadFile(path, result)) |
| 102 return false; |
| 103 |
| 75 // Result files are new-line delimited text files. Remove any CRs. | 104 // Result files are new-line delimited text files. Remove any CRs. |
| 76 result->erase(std::remove(result->begin(), result->end(), '\r'), | 105 result->erase(std::remove(result->begin(), result->end(), '\r'), |
| 77 result->end()); | 106 result->end()); |
| 107 |
| 108 // Remove trailing LFs. |
| 109 size_t pos = result->find_last_not_of('\n'); |
| 110 if (pos == std::string::npos) |
| 111 result->clear(); |
| 112 else |
| 113 result->resize(pos + 1); |
| 114 |
| 78 return true; | 115 return true; |
| 79 } | 116 } |
| 80 | 117 |
| 81 std::string GetPath(const std::string& root, const std::string& suffix) { | 118 std::string GetPath(const std::string& root, const std::string& suffix) { |
| 82 return "mojo/public/interfaces/bindings/tests/data/" + root + suffix; | 119 return "mojo/public/interfaces/bindings/tests/data/" + root + suffix; |
| 83 } | 120 } |
| 84 | 121 |
| 85 void RunValidationTest(const std::string& root, std::string (*func)(Message*)) { | 122 void RunValidationTest(const std::string& root, std::string (*func)(Message*)) { |
| 86 std::vector<uint8_t> data; | 123 std::vector<uint8_t> data; |
| 87 ASSERT_TRUE(ReadDataFile(GetPath(root, ".data"), &data)); | 124 ASSERT_TRUE(ReadAndParseDataFile(GetPath(root, ".data"), &data)); |
| 88 | 125 |
| 89 std::string expected; | 126 std::string expected; |
| 90 ASSERT_TRUE(ReadResultFile(GetPath(root, ".expected"), &expected)); | 127 ASSERT_TRUE(ReadResultFile(GetPath(root, ".expected"), &expected)); |
| 91 | 128 |
| 92 Message message; | 129 Message message; |
| 93 message.AllocUninitializedData(static_cast<uint32_t>(data.size())); | 130 message.AllocUninitializedData(static_cast<uint32_t>(data.size())); |
| 94 if (!data.empty()) | 131 if (!data.empty()) |
| 95 memcpy(message.mutable_data(), &data[0], data.size()); | 132 memcpy(message.mutable_data(), &data[0], data.size()); |
| 96 | 133 |
| 97 std::string result = func(&message); | 134 std::string result = func(&message); |
| 98 EXPECT_EQ(expected, result) << "failed test: " << root; | 135 EXPECT_EQ(expected, result) << "failed test: " << root; |
| 99 } | 136 } |
| 100 | 137 |
| 101 class DummyMessageReceiver : public MessageReceiver { | 138 class DummyMessageReceiver : public MessageReceiver { |
| 102 public: | 139 public: |
| 103 virtual bool Accept(Message* message) MOJO_OVERRIDE { | 140 virtual bool Accept(Message* message) MOJO_OVERRIDE { |
| 104 return true; // Any message is OK. | 141 return true; // Any message is OK. |
| 105 } | 142 } |
| 106 }; | 143 }; |
| 107 | 144 |
| 108 std::string DumpMessageHeader(Message* message) { | 145 std::string DumpMessageHeader(Message* message) { |
| 109 internal::ValidationErrorObserverForTesting observer; | 146 internal::ValidationErrorObserverForTesting observer; |
| 110 DummyMessageReceiver not_reached_receiver; | 147 DummyMessageReceiver not_reached_receiver; |
| 111 internal::MessageHeaderValidator validator(¬_reached_receiver); | 148 internal::MessageHeaderValidator validator(¬_reached_receiver); |
| 112 bool rv = validator.Accept(message); | 149 bool rv = validator.Accept(message); |
| 113 if (!rv) { | 150 if (!rv) { |
| 114 EXPECT_NE(internal::VALIDATION_ERROR_NONE, observer.last_error()); | 151 EXPECT_NE(internal::VALIDATION_ERROR_NONE, observer.last_error()); |
| 115 return ValidationErrorToResultString(observer.last_error()); | 152 return internal::ValidationErrorToString(observer.last_error()); |
| 116 } | 153 } |
| 117 | 154 |
| 118 std::ostringstream os; | 155 std::ostringstream os; |
| 119 os << "num_bytes: " << message->header()->num_bytes << "\n" | 156 os << "num_bytes: " << message->header()->num_bytes << "\n" |
| 120 << "num_fields: " << message->header()->num_fields << "\n" | 157 << "num_fields: " << message->header()->num_fields << "\n" |
| 121 << "name: " << message->header()->name << "\n" | 158 << "name: " << message->header()->name << "\n" |
| 122 << "flags: " << message->header()->flags << "\n"; | 159 << "flags: " << message->header()->flags; |
| 123 return os.str(); | 160 return os.str(); |
| 124 } | 161 } |
| 125 | 162 |
| 163 TEST(ValidationTest, InputParser) { |
| 164 { |
| 165 // The parser, as well as Append() defined above, assumes that this code is |
| 166 // running on a little-endian platform. Test whether that is true. |
| 167 uint16_t x = 1; |
| 168 ASSERT_EQ(1, *(reinterpret_cast<char*>(&x))); |
| 169 } |
| 170 { |
| 171 // Test empty input. |
| 172 std::string input; |
| 173 std::vector<uint8_t> expected; |
| 174 |
| 175 EXPECT_TRUE(TestInputParser(input, true, expected)); |
| 176 } |
| 177 { |
| 178 // Test input that only consists of comments and whitespaces. |
| 179 std::string input = " \t // hello world \n\r \t// the answer is 42 "; |
| 180 std::vector<uint8_t> expected; |
| 181 |
| 182 EXPECT_TRUE(TestInputParser(input, true, expected)); |
| 183 } |
| 184 { |
| 185 std::string input = "[u1]0x10// hello world !! \n\r \t [u2]65535 \n" |
| 186 "[u4]65536 [u8]0xFFFFFFFFFFFFFFFF 0 0Xff"; |
| 187 std::vector<uint8_t> expected; |
| 188 Append(&expected, static_cast<uint8_t>(0x10)); |
| 189 Append(&expected, static_cast<uint16_t>(65535)); |
| 190 Append(&expected, static_cast<uint32_t>(65536)); |
| 191 Append(&expected, static_cast<uint64_t>(0xffffffffffffffff)); |
| 192 Append(&expected, static_cast<uint8_t>(0)); |
| 193 Append(&expected, static_cast<uint8_t>(0xff)); |
| 194 |
| 195 EXPECT_TRUE(TestInputParser(input, true, expected)); |
| 196 } |
| 197 { |
| 198 std::string input = "[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40"; |
| 199 std::vector<uint8_t> expected; |
| 200 Append(&expected, -static_cast<int64_t>(0x800)); |
| 201 Append(&expected, static_cast<int8_t>(-128)); |
| 202 Append(&expected, static_cast<int16_t>(0)); |
| 203 Append(&expected, static_cast<int32_t>(-40)); |
| 204 |
| 205 EXPECT_TRUE(TestInputParser(input, true, expected)); |
| 206 } |
| 207 { |
| 208 std::string input = "[b]00001011 [b]10000000 // hello world\r [b]00000000"; |
| 209 std::vector<uint8_t> expected; |
| 210 Append(&expected, static_cast<uint8_t>(11)); |
| 211 Append(&expected, static_cast<uint8_t>(128)); |
| 212 Append(&expected, static_cast<uint8_t>(0)); |
| 213 |
| 214 EXPECT_TRUE(TestInputParser(input, true, expected)); |
| 215 } |
| 216 { |
| 217 std::string input = "[f]+.3e9 [d]-10.03"; |
| 218 std::vector<uint8_t> expected; |
| 219 Append(&expected, +.3e9f); |
| 220 Append(&expected, -10.03); |
| 221 |
| 222 EXPECT_TRUE(TestInputParser(input, true, expected)); |
| 223 } |
| 224 { |
| 225 std::string input = "[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar"; |
| 226 std::vector<uint8_t> expected; |
| 227 Append(&expected, static_cast<uint32_t>(14)); |
| 228 Append(&expected, static_cast<uint8_t>(0)); |
| 229 Append(&expected, static_cast<uint64_t>(9)); |
| 230 Append(&expected, static_cast<uint8_t>(0)); |
| 231 |
| 232 EXPECT_TRUE(TestInputParser(input, true, expected)); |
| 233 } |
| 234 |
| 235 // Test some failure cases. |
| 236 { |
| 237 const char* error_inputs[] = { |
| 238 "/ hello world", |
| 239 "[u1]x", |
| 240 "[u1]0x100", |
| 241 "[s2]-0x8001", |
| 242 "[b]1", |
| 243 "[b]1111111k", |
| 244 "[dist4]unmatched", |
| 245 "[anchr]hello [dist8]hello", |
| 246 NULL |
| 247 }; |
| 248 |
| 249 for (size_t i = 0; error_inputs[i]; ++i) { |
| 250 std::vector<uint8_t> expected; |
| 251 if (!TestInputParser(error_inputs[i], false, expected)) |
| 252 ADD_FAILURE() << "Unexpected test result for: " << error_inputs[i]; |
| 253 } |
| 254 } |
| 255 } |
| 256 |
| 126 TEST(ValidationTest, TestAll) { | 257 TEST(ValidationTest, TestAll) { |
| 127 std::vector<std::string> names = | 258 std::vector<std::string> names = |
| 128 EnumerateSourceRootRelativeDirectory(GetPath("", "")); | 259 EnumerateSourceRootRelativeDirectory(GetPath("", "")); |
| 129 | 260 |
| 130 std::vector<std::string> header_tests = | 261 std::vector<std::string> header_tests = |
| 131 GetMatchingTests(names, "validate_header_"); | 262 GetMatchingTests(names, "validate_header_"); |
| 132 | 263 |
| 133 for (size_t i = 0; i < header_tests.size(); ++i) | 264 for (size_t i = 0; i < header_tests.size(); ++i) |
| 134 RunValidationTest(header_tests[i], &DumpMessageHeader); | 265 RunValidationTest(header_tests[i], &DumpMessageHeader); |
| 135 } | 266 } |
| 136 | 267 |
| 137 } // namespace | 268 } // namespace |
| 138 } // namespace test | 269 } // namespace test |
| 139 } // namespace mojo | 270 } // namespace mojo |
| OLD | NEW |