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

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: rebase3 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 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(&not_reached_receiver); 148 internal::MessageHeaderValidator validator(&not_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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698