harness.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #include <functional>
  2. #include <iostream>
  3. #if defined(WIN32)
  4. #include <stdio.h>
  5. #include <io.h>
  6. #include <fcntl.h>
  7. #endif
  8. #include "validate/validate.h"
  9. #include "tests/harness/cases/bool.pb.h"
  10. #include "tests/harness/cases/bool.pb.validate.h"
  11. #include "tests/harness/cases/bytes.pb.h"
  12. #include "tests/harness/cases/bytes.pb.validate.h"
  13. #include "tests/harness/cases/enums.pb.h"
  14. #include "tests/harness/cases/enums.pb.validate.h"
  15. #include "tests/harness/cases/filename-with-dash.pb.h"
  16. #include "tests/harness/cases/filename-with-dash.pb.validate.h"
  17. #include "tests/harness/cases/maps.pb.h"
  18. #include "tests/harness/cases/maps.pb.validate.h"
  19. #include "tests/harness/cases/messages.pb.h"
  20. #include "tests/harness/cases/messages.pb.validate.h"
  21. #include "tests/harness/cases/numbers.pb.h"
  22. #include "tests/harness/cases/numbers.pb.validate.h"
  23. #include "tests/harness/cases/oneofs.pb.h"
  24. #include "tests/harness/cases/oneofs.pb.validate.h"
  25. #include "tests/harness/cases/repeated.pb.h"
  26. #include "tests/harness/cases/repeated.pb.validate.h"
  27. #include "tests/harness/cases/strings.pb.h"
  28. #include "tests/harness/cases/strings.pb.validate.h"
  29. #include "tests/harness/cases/wkt_any.pb.h"
  30. #include "tests/harness/cases/wkt_any.pb.validate.h"
  31. #include "tests/harness/cases/wkt_duration.pb.h"
  32. #include "tests/harness/cases/wkt_duration.pb.validate.h"
  33. #include "tests/harness/cases/wkt_timestamp.pb.h"
  34. #include "tests/harness/cases/wkt_timestamp.pb.validate.h"
  35. #include "tests/harness/cases/wkt_wrappers.pb.h"
  36. #include "tests/harness/cases/wkt_wrappers.pb.validate.h"
  37. #include "tests/harness/cases/kitchen_sink.pb.h"
  38. #include "tests/harness/cases/kitchen_sink.pb.validate.h"
  39. #include "tests/harness/harness.pb.h"
  40. namespace {
  41. using tests::harness::TestCase;
  42. using tests::harness::TestResult;
  43. using google::protobuf::Any;
  44. std::ostream& operator<<(std::ostream& out, const TestResult& result) {
  45. if (result.reasons_size() > 0) {
  46. out << "valid: " << result.valid() << " reason: '" << result.reasons(0) << "'"
  47. << std::endl;
  48. } else {
  49. out << "valid: " << result.valid() << " reason: unknown"
  50. << std::endl;
  51. }
  52. return out;
  53. }
  54. void WriteTestResultAndExit(const TestResult& result) {
  55. if (!result.SerializeToOstream(&std::cout)) {
  56. std::cerr << "could not martial response: ";
  57. std::cerr << result << std::endl;
  58. exit(EXIT_FAILURE);
  59. }
  60. exit(EXIT_SUCCESS);
  61. }
  62. void ExitIfFailed(bool succeeded, const pgv::ValidationMsg& err_msg) {
  63. if (succeeded) {
  64. return;
  65. }
  66. TestResult result;
  67. result.set_error(true);
  68. result.add_reasons(pgv::String(err_msg));
  69. WriteTestResultAndExit(result);
  70. }
  71. std::function<TestResult()> GetValidationCheck(const Any& msg) {
  72. // This macro is intended to be called once for each message type with the
  73. // fully-qualified class name passed in as the only argument CLS. It checks
  74. // whether the msg argument above can be unpacked as a CLS. If so, it returns
  75. // a lambda that, when called, unpacks the message and validates it as a CLS.
  76. // This is here to work around the lack of duck-typing in C++, and because the
  77. // validation function can't be specified as a virtual method on the
  78. // google::protobuf::Message class.
  79. #define TRY_RETURN_VALIDATE_CALLABLE(CLS) \
  80. if (msg.Is<CLS>() && !msg.Is<::tests::harness::cases::MessageIgnored>()) { \
  81. return [msg] () { \
  82. pgv::ValidationMsg err_msg; \
  83. TestResult result; \
  84. CLS unpacked; \
  85. msg.UnpackTo(&unpacked); \
  86. try { \
  87. result.set_valid(Validate(unpacked, &err_msg)); \
  88. result.add_reasons(std::move(err_msg)); \
  89. } catch (pgv::UnimplementedException& e) { \
  90. /* don't fail for unimplemented validations */ \
  91. result.set_valid(false); \
  92. result.set_allowfailure(true); \
  93. result.add_reasons(e.what()); \
  94. } \
  95. return result; \
  96. }; \
  97. }
  98. // These macros are defined in the various validation headers and call the
  99. // above macro once for each message class in the header.
  100. X_TESTS_HARNESS_CASES_BOOL(TRY_RETURN_VALIDATE_CALLABLE)
  101. X_TESTS_HARNESS_CASES_BYTES(TRY_RETURN_VALIDATE_CALLABLE)
  102. X_TESTS_HARNESS_CASES_ENUMS(TRY_RETURN_VALIDATE_CALLABLE)
  103. X_TESTS_HARNESS_CASES_MAPS(TRY_RETURN_VALIDATE_CALLABLE)
  104. X_TESTS_HARNESS_CASES_MESSAGES(TRY_RETURN_VALIDATE_CALLABLE)
  105. X_TESTS_HARNESS_CASES_NUMBERS(TRY_RETURN_VALIDATE_CALLABLE)
  106. X_TESTS_HARNESS_CASES_ONEOFS(TRY_RETURN_VALIDATE_CALLABLE)
  107. X_TESTS_HARNESS_CASES_REPEATED(TRY_RETURN_VALIDATE_CALLABLE)
  108. X_TESTS_HARNESS_CASES_STRINGS(TRY_RETURN_VALIDATE_CALLABLE)
  109. X_TESTS_HARNESS_CASES_WKT_ANY(TRY_RETURN_VALIDATE_CALLABLE)
  110. X_TESTS_HARNESS_CASES_WKT_DURATION(TRY_RETURN_VALIDATE_CALLABLE)
  111. X_TESTS_HARNESS_CASES_WKT_TIMESTAMP(TRY_RETURN_VALIDATE_CALLABLE)
  112. X_TESTS_HARNESS_CASES_WKT_WRAPPERS(TRY_RETURN_VALIDATE_CALLABLE)
  113. X_TESTS_HARNESS_CASES_KITCHEN_SINK(TRY_RETURN_VALIDATE_CALLABLE)
  114. // TODO(akonradi) add macros as the C++ validation code gets fleshed out for
  115. // more field types.
  116. #undef TRY_RETURN_VALIDATE_CALLABLE
  117. // TODO(akonradi) remove this once all C++ validation code is done
  118. return []() {
  119. TestResult result;
  120. result.set_valid(false);
  121. result.set_allowfailure(true);
  122. result.add_reasons("not implemented");
  123. return result;
  124. };
  125. }
  126. } // namespace
  127. int main() {
  128. TestCase test_case;
  129. #if defined(WIN32)
  130. // need to explicitly set the stdin file mode to binary on Windows
  131. ExitIfFailed(_setmode(_fileno(stdin), _O_BINARY) != -1, "failed to set stdin to binary mode");
  132. #endif
  133. ExitIfFailed(test_case.ParseFromIstream(&std::cin), "failed to parse TestCase");
  134. auto validate_fn = GetValidationCheck(test_case.message());
  135. WriteTestResultAndExit(validate_fn());
  136. return 0;
  137. }