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