Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: mojo/public/cpp/bindings/tests/validation_unittest.cc

Issue 318123003: Add input data parser for Mojo message validation tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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(&not_reached_receiver); 145 internal::MessageHeaderValidator validator(&not_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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698