Index: mojo/public/cpp/bindings/tests/validation_unittest.cc |
diff --git a/mojo/public/cpp/bindings/tests/validation_unittest.cc b/mojo/public/cpp/bindings/tests/validation_unittest.cc |
index 4bd1cb594fdb07465790a8522418d1ad8feb19c7..f111091472309c9e0b19aa7faf14f03f908a486c 100644 |
--- a/mojo/public/cpp/bindings/tests/validation_unittest.cc |
+++ b/mojo/public/cpp/bindings/tests/validation_unittest.cc |
@@ -11,6 +11,7 @@ |
#include "mojo/public/cpp/bindings/lib/message_header_validator.h" |
#include "mojo/public/cpp/bindings/lib/validation_errors.h" |
+#include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h" |
#include "mojo/public/cpp/test_support/test_support.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -18,10 +19,35 @@ namespace mojo { |
namespace test { |
namespace { |
-std::string ValidationErrorToResultString(internal::ValidationError error) { |
- std::string result = internal::ValidationErrorToString(error); |
- result.push_back('\n'); |
- return result; |
+template <typename T> |
+void Append(std::vector<uint8_t>* data_vector, T data) { |
+ size_t pos = data_vector->size(); |
+ data_vector->resize(pos + sizeof(T)); |
+ memcpy(&(*data_vector)[pos], &data, sizeof(T)); |
+} |
+ |
+bool TestInputParser(const std::string& input, |
+ bool expected_result, |
+ const std::vector<uint8_t>& expected_parsed_input) { |
+ std::vector<uint8_t> parsed_input; |
+ std::string error_message; |
+ |
+ bool result = ParseValidationTestInput(input, &parsed_input, &error_message); |
+ if (expected_result) { |
+ if (result && error_message.empty() && |
+ expected_parsed_input == parsed_input) { |
+ return true; |
+ } |
+ |
+ // Compare with an empty string instead of checking |error_message.empty()|, |
+ // so that the message will be printed out if the two are not equal. |
+ EXPECT_EQ(std::string(), error_message); |
+ EXPECT_EQ(expected_parsed_input, parsed_input); |
+ return false; |
+ } |
+ |
+ EXPECT_FALSE(error_message.empty()); |
+ return !result && !error_message.empty(); |
} |
std::vector<std::string> GetMatchingTests(const std::vector<std::string>& names, |
@@ -37,44 +63,55 @@ std::vector<std::string> GetMatchingTests(const std::vector<std::string>& names, |
return tests; |
} |
-bool ReadDataFile(const std::string& path, std::vector<uint8_t>* result) { |
+bool ReadFile(const std::string& path, std::string* result) { |
FILE* fp = OpenSourceRootRelativeFile(path.c_str()); |
if (!fp) { |
ADD_FAILURE() << "File not found: " << path; |
return false; |
} |
- for (;;) { |
- unsigned int value; |
- int rv = fscanf(fp, "%x", &value); |
- if (rv != 1) |
- break; |
- result->push_back(static_cast<uint8_t>(value & 0xFF)); |
- } |
- bool error = ferror(fp); |
- fclose(fp); |
- return !error; |
-} |
- |
-bool ReadResultFile(const std::string& path, std::string* result) { |
- FILE* fp = OpenSourceRootRelativeFile(path.c_str()); |
- if (!fp) |
- return false; |
fseek(fp, 0, SEEK_END); |
size_t size = static_cast<size_t>(ftell(fp)); |
if (size == 0) { |
- // Result files should never be empty. |
+ result->clear(); |
fclose(fp); |
- return false; |
+ return true; |
} |
fseek(fp, 0, SEEK_SET); |
result->resize(size); |
size_t size_read = fread(&result->at(0), 1, size, fp); |
fclose(fp); |
- if (size != size_read) |
+ return size == size_read; |
+} |
+ |
+bool ReadAndParseDataFile(const std::string& path, std::vector<uint8_t>* data) { |
+ std::string input; |
+ if (!ReadFile(path, &input)) |
+ return false; |
+ |
+ std::string error_message; |
+ if (!ParseValidationTestInput(input, data, &error_message)) { |
+ ADD_FAILURE() << error_message; |
return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+bool ReadResultFile(const std::string& path, std::string* result) { |
+ if (!ReadFile(path, result)) |
+ return false; |
+ |
// Result files are new-line delimited text files. Remove any CRs. |
result->erase(std::remove(result->begin(), result->end(), '\r'), |
result->end()); |
+ |
+ // Remove trailing LFs. |
+ size_t pos = result->find_last_not_of('\n'); |
+ if (pos == std::string::npos) |
+ result->clear(); |
+ else |
+ result->resize(pos + 1); |
+ |
return true; |
} |
@@ -84,7 +121,7 @@ std::string GetPath(const std::string& root, const std::string& suffix) { |
void RunValidationTest(const std::string& root, std::string (*func)(Message*)) { |
std::vector<uint8_t> data; |
- ASSERT_TRUE(ReadDataFile(GetPath(root, ".data"), &data)); |
+ ASSERT_TRUE(ReadAndParseDataFile(GetPath(root, ".data"), &data)); |
std::string expected; |
ASSERT_TRUE(ReadResultFile(GetPath(root, ".expected"), &expected)); |
@@ -112,17 +149,111 @@ std::string DumpMessageHeader(Message* message) { |
bool rv = validator.Accept(message); |
if (!rv) { |
EXPECT_NE(internal::VALIDATION_ERROR_NONE, observer.last_error()); |
- return ValidationErrorToResultString(observer.last_error()); |
+ return internal::ValidationErrorToString(observer.last_error()); |
} |
std::ostringstream os; |
os << "num_bytes: " << message->header()->num_bytes << "\n" |
<< "num_fields: " << message->header()->num_fields << "\n" |
<< "name: " << message->header()->name << "\n" |
- << "flags: " << message->header()->flags << "\n"; |
+ << "flags: " << message->header()->flags; |
return os.str(); |
} |
+TEST(ValidationTest, InputParser) { |
+ { |
+ // The parser, as well as Append() defined above, assumes that this code is |
+ // running on a little-endian platform. Test whether that is true. |
+ uint16_t x = 1; |
+ ASSERT_EQ(1, *(reinterpret_cast<char*>(&x))); |
+ } |
+ { |
+ // Test empty input. |
+ std::string input; |
+ std::vector<uint8_t> expected; |
+ |
+ EXPECT_TRUE(TestInputParser(input, true, expected)); |
+ } |
+ { |
+ // Test input that only consists of comments and whitespaces. |
+ std::string input = " \t // hello world \n\r \t// the answer is 42 "; |
+ std::vector<uint8_t> expected; |
+ |
+ EXPECT_TRUE(TestInputParser(input, true, expected)); |
+ } |
+ { |
+ std::string input = "[u1]0x10// hello world !! \n\r \t [u2]65535 \n" |
+ "[u4]65536 [u8]0xFFFFFFFFFFFFFFFF 0 0Xff"; |
+ std::vector<uint8_t> expected; |
+ Append(&expected, static_cast<uint8_t>(0x10)); |
+ Append(&expected, static_cast<uint16_t>(65535)); |
+ Append(&expected, static_cast<uint32_t>(65536)); |
+ Append(&expected, static_cast<uint64_t>(0xffffffffffffffff)); |
+ Append(&expected, static_cast<uint8_t>(0)); |
+ Append(&expected, static_cast<uint8_t>(0xff)); |
+ |
+ EXPECT_TRUE(TestInputParser(input, true, expected)); |
+ } |
+ { |
+ std::string input = "[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40"; |
+ std::vector<uint8_t> expected; |
+ Append(&expected, -static_cast<int64_t>(0x800)); |
+ Append(&expected, static_cast<int8_t>(-128)); |
+ Append(&expected, static_cast<int16_t>(0)); |
+ Append(&expected, static_cast<int32_t>(-40)); |
+ |
+ EXPECT_TRUE(TestInputParser(input, true, expected)); |
+ } |
+ { |
+ std::string input = "[b]00001011 [b]10000000 // hello world\r [b]00000000"; |
+ std::vector<uint8_t> expected; |
+ Append(&expected, static_cast<uint8_t>(11)); |
+ Append(&expected, static_cast<uint8_t>(128)); |
+ Append(&expected, static_cast<uint8_t>(0)); |
+ |
+ EXPECT_TRUE(TestInputParser(input, true, expected)); |
+ } |
+ { |
+ std::string input = "[f]+.3e9 [d]-10.03"; |
+ std::vector<uint8_t> expected; |
+ Append(&expected, +.3e9f); |
+ Append(&expected, -10.03); |
+ |
+ EXPECT_TRUE(TestInputParser(input, true, expected)); |
+ } |
+ { |
+ std::string input = "[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar"; |
+ std::vector<uint8_t> expected; |
+ Append(&expected, static_cast<uint32_t>(14)); |
+ Append(&expected, static_cast<uint8_t>(0)); |
+ Append(&expected, static_cast<uint64_t>(9)); |
+ Append(&expected, static_cast<uint8_t>(0)); |
+ |
+ EXPECT_TRUE(TestInputParser(input, true, expected)); |
+ } |
+ |
+ // Test some failure cases. |
+ { |
+ const char* error_inputs[] = { |
+ "/ hello world", |
+ "[u1]x", |
+ "[u1]0x100", |
+ "[s2]-0x8001", |
+ "[b]1", |
+ "[b]1111111k", |
+ "[dist4]unmatched", |
+ "[anchr]hello [dist8]hello", |
+ NULL |
+ }; |
+ |
+ for (size_t i = 0; error_inputs[i]; ++i) { |
+ std::vector<uint8_t> expected; |
+ if (!TestInputParser(error_inputs[i], false, expected)) |
+ ADD_FAILURE() << "Unexpected test result for: " << error_inputs[i]; |
+ } |
+ } |
+} |
+ |
TEST(ValidationTest, TestAll) { |
std::vector<std::string> names = |
EnumerateSourceRootRelativeDirectory(GetPath("", "")); |