| /* |
| * |
| * Tests for C++ wrappers. |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include <fstream> |
| #include <iostream> |
| #include <set> |
| #include <sstream> |
| |
| #include "tests/test_cpp.upbdefs.h" |
| #include "upb/def.h" |
| #include "upb/handlers.h" |
| #include "upb/pb/decoder.h" |
| #include "upb/pb/textprinter.h" |
| #include "upb/upb.h" |
| #include "upb_test.h" |
| |
| #include "upb/port_def.inc" |
| |
| template <class T> |
| void AssertInsert(T* const container, const typename T::value_type& val) { |
| bool inserted = container->insert(val).second; |
| ASSERT(inserted); |
| } |
| |
| // |
| // Tests for registering and calling handlers in all their variants. |
| // This test code is very repetitive because we have to declare each |
| // handler function variant separately, and they all have different |
| // signatures so it does not lend itself well to templates. |
| // |
| // We test three handler types: |
| // StartMessage (no data params) |
| // Int32 (1 data param (int32_t)) |
| // String Buf (2 data params (const char*, size_t)) |
| // |
| // For each handler type we test all 8 handler variants: |
| // (handler data?) x (function/method) x (returns {void, success}) |
| // |
| // The one notable thing we don't test at the moment is |
| // StartSequence/StartString handlers: these are different from StartMessage() |
| // in that they return void* for the sub-closure. But this is exercised in |
| // other tests. |
| // |
| |
| static const int kExpectedHandlerData = 1232323; |
| |
| class StringBufTesterBase { |
| public: |
| static const int kFieldNumber = 3; |
| |
| StringBufTesterBase() : seen_(false), handler_data_val_(0) {} |
| |
| void CallAndVerify(upb::Sink sink, upb::FieldDefPtr f) { |
| upb_selector_t start; |
| ASSERT(upb_handlers_getselector(f.ptr(), UPB_HANDLER_STARTSTR, &start)); |
| upb_selector_t str; |
| ASSERT(upb_handlers_getselector(f.ptr(), UPB_HANDLER_STRING, &str)); |
| |
| ASSERT(!seen_); |
| upb::Sink sub; |
| sink.StartMessage(); |
| sink.StartString(start, 0, &sub); |
| size_t ret = sub.PutStringBuffer(str, &buf_, 5, &handle_); |
| ASSERT(seen_); |
| ASSERT(len_ == 5); |
| ASSERT(ret == 5); |
| ASSERT(handler_data_val_ == kExpectedHandlerData); |
| } |
| |
| protected: |
| bool seen_; |
| int handler_data_val_; |
| size_t len_; |
| char buf_; |
| upb_bufhandle handle_; |
| }; |
| |
| // Test 8 combinations of: |
| // (handler data?) x (buffer handle?) x (function/method) |
| // |
| // Then we add one test each for this variation: to prevent combinatorial |
| // explosion of these tests we don't test the full 16 combinations, but |
| // rely on our knowledge that the implementation processes the return wrapping |
| // in a second separate and independent stage: |
| // |
| // (function/method) |
| |
| class StringBufTesterVoidMethodNoHandlerDataNoHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterVoidMethodNoHandlerDataNoHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| void Handler(const char *buf, size_t len) { |
| ASSERT(buf == &buf_); |
| seen_ = true; |
| len_ = len; |
| } |
| }; |
| |
| class StringBufTesterVoidMethodNoHandlerDataWithHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterVoidMethodNoHandlerDataWithHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| void Handler(const char *buf, size_t len, const upb_bufhandle* handle) { |
| ASSERT(buf == &buf_); |
| ASSERT(handle == &handle_); |
| seen_ = true; |
| len_ = len; |
| } |
| }; |
| |
| class StringBufTesterVoidMethodWithHandlerDataNoHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterVoidMethodWithHandlerDataNoHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler( |
| f, UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| void Handler(const int* hd, const char *buf, size_t len) { |
| ASSERT(buf == &buf_); |
| handler_data_val_ = *hd; |
| seen_ = true; |
| len_ = len; |
| } |
| }; |
| |
| class StringBufTesterVoidMethodWithHandlerDataWithHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterVoidMethodWithHandlerDataWithHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler( |
| f, UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| void Handler(const int* hd, const char* buf, size_t len, |
| const upb_bufhandle* handle) { |
| ASSERT(buf == &buf_); |
| ASSERT(handle == &handle_); |
| handler_data_val_ = *hd; |
| seen_ = true; |
| len_ = len; |
| } |
| }; |
| |
| class StringBufTesterVoidFunctionNoHandlerDataNoHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterVoidFunctionNoHandlerDataNoHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| static void Handler(ME* t, const char *buf, size_t len) { |
| ASSERT(buf == &t->buf_); |
| t->seen_ = true; |
| t->len_ = len; |
| } |
| }; |
| |
| class StringBufTesterVoidFunctionNoHandlerDataWithHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterVoidFunctionNoHandlerDataWithHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| static void Handler(ME* t, const char* buf, size_t len, |
| const upb_bufhandle* handle) { |
| ASSERT(buf == &t->buf_); |
| ASSERT(handle == &t->handle_); |
| t->seen_ = true; |
| t->len_ = len; |
| } |
| }; |
| |
| class StringBufTesterVoidFunctionWithHandlerDataNoHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterVoidFunctionWithHandlerDataNoHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler( |
| f, UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| static void Handler(ME* t, const int* hd, const char *buf, size_t len) { |
| ASSERT(buf == &t->buf_); |
| t->handler_data_val_ = *hd; |
| t->seen_ = true; |
| t->len_ = len; |
| } |
| }; |
| |
| class StringBufTesterVoidFunctionWithHandlerDataWithHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterVoidFunctionWithHandlerDataWithHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler( |
| f, UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| static void Handler(ME* t, const int* hd, const char* buf, size_t len, |
| const upb_bufhandle* handle) { |
| ASSERT(buf == &t->buf_); |
| ASSERT(handle == &t->handle_); |
| t->handler_data_val_ = *hd; |
| t->seen_ = true; |
| t->len_ = len; |
| } |
| }; |
| |
| class StringBufTesterSizeTMethodNoHandlerDataNoHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterSizeTMethodNoHandlerDataNoHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| size_t Handler(const char *buf, size_t len) { |
| ASSERT(buf == &buf_); |
| seen_ = true; |
| len_ = len; |
| return len; |
| } |
| }; |
| |
| class StringBufTesterBoolMethodNoHandlerDataNoHandle |
| : public StringBufTesterBase { |
| public: |
| typedef StringBufTesterBoolMethodNoHandlerDataNoHandle ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| bool Handler(const char *buf, size_t len) { |
| ASSERT(buf == &buf_); |
| seen_ = true; |
| len_ = len; |
| return true; |
| } |
| }; |
| |
| class StartMsgTesterBase { |
| public: |
| // We don't need the FieldDef it will create, but the test harness still |
| // requires that we provide one. |
| static const int kFieldNumber = 3; |
| |
| StartMsgTesterBase() : seen_(false), handler_data_val_(0) {} |
| |
| void CallAndVerify(upb::Sink sink, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(!seen_); |
| sink.StartMessage(); |
| ASSERT(seen_); |
| ASSERT(handler_data_val_ == kExpectedHandlerData); |
| } |
| |
| protected: |
| bool seen_; |
| int handler_data_val_; |
| }; |
| |
| // Test all 8 combinations of: |
| // (handler data?) x (function/method) x (returns {void, bool}) |
| |
| class StartMsgTesterVoidFunctionNoHandlerData : public StartMsgTesterBase { |
| public: |
| typedef StartMsgTesterVoidFunctionNoHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStartMessageHandler(UpbMakeHandler(&Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| //static void Handler(ME* t) { |
| static void Handler(ME* t) { |
| t->seen_ = true; |
| } |
| }; |
| |
| class StartMsgTesterBoolFunctionNoHandlerData : public StartMsgTesterBase { |
| public: |
| typedef StartMsgTesterBoolFunctionNoHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStartMessageHandler(UpbMakeHandler(&Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| static bool Handler(ME* t) { |
| t->seen_ = true; |
| return true; |
| } |
| }; |
| |
| class StartMsgTesterVoidMethodNoHandlerData : public StartMsgTesterBase { |
| public: |
| typedef StartMsgTesterVoidMethodNoHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStartMessageHandler(UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| void Handler() { |
| seen_ = true; |
| } |
| }; |
| |
| class StartMsgTesterBoolMethodNoHandlerData : public StartMsgTesterBase { |
| public: |
| typedef StartMsgTesterBoolMethodNoHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStartMessageHandler(UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| bool Handler() { |
| seen_ = true; |
| return true; |
| } |
| }; |
| |
| class StartMsgTesterVoidFunctionWithHandlerData : public StartMsgTesterBase { |
| public: |
| typedef StartMsgTesterVoidFunctionWithHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStartMessageHandler( |
| UpbBind(&Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| static void Handler(ME* t, const int* hd) { |
| t->handler_data_val_ = *hd; |
| t->seen_ = true; |
| } |
| }; |
| |
| class StartMsgTesterBoolFunctionWithHandlerData : public StartMsgTesterBase { |
| public: |
| typedef StartMsgTesterBoolFunctionWithHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStartMessageHandler( |
| UpbBind(&Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| static bool Handler(ME* t, const int* hd) { |
| t->handler_data_val_ = *hd; |
| t->seen_ = true; |
| return true; |
| } |
| }; |
| |
| class StartMsgTesterVoidMethodWithHandlerData : public StartMsgTesterBase { |
| public: |
| typedef StartMsgTesterVoidMethodWithHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStartMessageHandler( |
| UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| void Handler(const int* hd) { |
| handler_data_val_ = *hd; |
| seen_ = true; |
| } |
| }; |
| |
| class StartMsgTesterBoolMethodWithHandlerData : public StartMsgTesterBase { |
| public: |
| typedef StartMsgTesterBoolMethodWithHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| UPB_UNUSED(f); |
| ASSERT(h.SetStartMessageHandler( |
| UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| bool Handler(const int* hd) { |
| handler_data_val_ = *hd; |
| seen_ = true; |
| return true; |
| } |
| }; |
| |
| class Int32ValueTesterBase { |
| public: |
| static const int kFieldNumber = 1; |
| |
| Int32ValueTesterBase() : seen_(false), val_(0), handler_data_val_(0) {} |
| |
| void CallAndVerify(upb::Sink sink, upb::FieldDefPtr f) { |
| upb_selector_t s; |
| ASSERT(upb_handlers_getselector(f.ptr(), UPB_HANDLER_INT32, &s)); |
| |
| ASSERT(!seen_); |
| sink.PutInt32(s, 5); |
| ASSERT(seen_); |
| ASSERT(handler_data_val_ == kExpectedHandlerData); |
| ASSERT(val_ == 5); |
| } |
| |
| protected: |
| bool seen_; |
| int32_t val_; |
| int handler_data_val_; |
| }; |
| |
| // Test all 8 combinations of: |
| // (handler data?) x (function/method) x (returns {void, bool}) |
| |
| class ValueTesterInt32VoidFunctionNoHandlerData |
| : public Int32ValueTesterBase { |
| public: |
| typedef ValueTesterInt32VoidFunctionNoHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| ASSERT(h.SetInt32Handler(f, UpbMakeHandler(&Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| static void Handler(ME* t, int32_t val) { |
| t->val_ = val; |
| t->seen_ = true; |
| } |
| }; |
| |
| class ValueTesterInt32BoolFunctionNoHandlerData |
| : public Int32ValueTesterBase { |
| public: |
| typedef ValueTesterInt32BoolFunctionNoHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| ASSERT(h.SetInt32Handler(f, UpbMakeHandler(&Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| static bool Handler(ME* t, int32_t val) { |
| t->val_ = val; |
| t->seen_ = true; |
| return true; |
| } |
| }; |
| |
| class ValueTesterInt32VoidMethodNoHandlerData : public Int32ValueTesterBase { |
| public: |
| typedef ValueTesterInt32VoidMethodNoHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| ASSERT(h.SetInt32Handler(f, UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| void Handler(int32_t val) { |
| val_ = val; |
| seen_ = true; |
| } |
| }; |
| |
| class ValueTesterInt32BoolMethodNoHandlerData : public Int32ValueTesterBase { |
| public: |
| typedef ValueTesterInt32BoolMethodNoHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| ASSERT(h.SetInt32Handler(f, UpbMakeHandler(&ME::Handler))); |
| handler_data_val_ = kExpectedHandlerData; |
| } |
| |
| private: |
| bool Handler(int32_t val) { |
| val_ = val; |
| seen_ = true; |
| return true; |
| } |
| }; |
| |
| class ValueTesterInt32VoidFunctionWithHandlerData |
| : public Int32ValueTesterBase { |
| public: |
| typedef ValueTesterInt32VoidFunctionWithHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| ASSERT(h.SetInt32Handler( |
| f, UpbBind(&Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| static void Handler(ME* t, const int* hd, int32_t val) { |
| t->val_ = val; |
| t->handler_data_val_ = *hd; |
| t->seen_ = true; |
| } |
| }; |
| |
| class ValueTesterInt32BoolFunctionWithHandlerData |
| : public Int32ValueTesterBase { |
| public: |
| typedef ValueTesterInt32BoolFunctionWithHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| ASSERT(h.SetInt32Handler( |
| f, UpbBind(&Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| static bool Handler(ME* t, const int* hd, int32_t val) { |
| t->val_ = val; |
| t->handler_data_val_ = *hd; |
| t->seen_ = true; |
| return true; |
| } |
| }; |
| |
| class ValueTesterInt32VoidMethodWithHandlerData : public Int32ValueTesterBase { |
| public: |
| typedef ValueTesterInt32VoidMethodWithHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| ASSERT(h.SetInt32Handler( |
| f, UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| void Handler(const int* hd, int32_t val) { |
| val_ = val; |
| handler_data_val_ = *hd; |
| seen_ = true; |
| } |
| }; |
| |
| class ValueTesterInt32BoolMethodWithHandlerData : public Int32ValueTesterBase { |
| public: |
| typedef ValueTesterInt32BoolMethodWithHandlerData ME; |
| void Register(upb::HandlersPtr h, upb::FieldDefPtr f) { |
| ASSERT(h.SetInt32Handler( |
| f, UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); |
| } |
| |
| private: |
| bool Handler(const int* hd, int32_t val) { |
| val_ = val; |
| handler_data_val_ = *hd; |
| seen_ = true; |
| return true; |
| } |
| }; |
| |
| template <class T> |
| void RegisterHandlers(const void* closure, upb::Handlers* h_ptr) { |
| T* tester = const_cast<T*>(static_cast<const T*>(closure)); |
| upb::HandlersPtr h(h_ptr); |
| upb::FieldDefPtr f = h.message_def().FindFieldByNumber(T::kFieldNumber); |
| ASSERT(f); |
| tester->Register(h, f); |
| } |
| |
| template <class T> |
| void TestHandler() { |
| T tester; |
| upb::SymbolTable symtab; |
| upb::HandlerCache cache(&RegisterHandlers<T>, &tester); |
| upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr())); |
| ASSERT(md); |
| upb::FieldDefPtr f = md.FindFieldByNumber(T::kFieldNumber); |
| ASSERT(f); |
| |
| const upb::Handlers* h = cache.Get(md); |
| |
| upb::Sink sink(h, &tester); |
| tester.CallAndVerify(sink, f); |
| } |
| |
| class T1 {}; |
| class T2 {}; |
| |
| template <class C> |
| void DoNothingHandler(C* closure) { |
| UPB_UNUSED(closure); |
| } |
| |
| template <class C> |
| void DoNothingInt32Handler(C* closure, int32_t val) { |
| UPB_UNUSED(closure); |
| UPB_UNUSED(val); |
| } |
| |
| template <class R> |
| class DoNothingStartHandler { |
| public: |
| // We wrap these functions inside of a class for a somewhat annoying reason. |
| // UpbMakeHandler() is a macro, so we can't say |
| // UpbMakeHandler(DoNothingStartHandler<T1, T2>) |
| // |
| // because otherwise the preprocessor gets confused at the comma and tries to |
| // make it two macro arguments. The usual solution doesn't work either: |
| // UpbMakeHandler((DoNothingStartHandler<T1, T2>)) |
| // |
| // If we do that the macro expands correctly, but then it tries to pass that |
| // parenthesized expression as a template parameter, ie. Type<(F)>, which |
| // isn't legal C++ (Clang will compile it but complains with |
| // warning: address non-type template argument cannot be surrounded by |
| // parentheses |
| // |
| // This two-level thing allows us to effectively pass two template parameters, |
| // but without any commas: |
| // UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>) |
| template <class C> |
| static R* Handler(C* closure) { |
| UPB_UNUSED(closure); |
| return NULL; |
| } |
| |
| template <class C> |
| static R* String(C* closure, size_t size_len) { |
| UPB_UNUSED(closure); |
| UPB_UNUSED(size_len); |
| return NULL; |
| } |
| }; |
| |
| template <class C> |
| void DoNothingStringBufHandler(C* closure, const char *buf, size_t len) { |
| UPB_UNUSED(closure); |
| UPB_UNUSED(buf); |
| UPB_UNUSED(len); |
| } |
| |
| template <class C> |
| void DoNothingEndMessageHandler(C* closure, upb_status *status) { |
| UPB_UNUSED(closure); |
| UPB_UNUSED(status); |
| } |
| |
| void RegisterMismatchedTypes(const void* closure, upb::Handlers* h_ptr) { |
| upb::HandlersPtr h(h_ptr); |
| |
| upb::MessageDefPtr md(h.message_def()); |
| ASSERT(md); |
| upb::FieldDefPtr i32 = md.FindFieldByName("i32"); |
| upb::FieldDefPtr r_i32 = md.FindFieldByName("r_i32"); |
| upb::FieldDefPtr str = md.FindFieldByName("str"); |
| upb::FieldDefPtr r_str = md.FindFieldByName("r_str"); |
| upb::FieldDefPtr msg = md.FindFieldByName("msg"); |
| upb::FieldDefPtr r_msg = md.FindFieldByName("r_msg"); |
| ASSERT(i32); |
| ASSERT(r_i32); |
| ASSERT(str); |
| ASSERT(r_str); |
| ASSERT(msg); |
| ASSERT(r_msg); |
| |
| // Establish T1 as the top-level closure type. |
| ASSERT(h.SetInt32Handler(i32, UpbMakeHandler(DoNothingInt32Handler<T1>))); |
| |
| // Now any other attempt to set another handler with T2 as the top-level |
| // closure should fail. But setting these same handlers with T1 as the |
| // top-level closure will succeed. |
| ASSERT(!h.SetStartMessageHandler(UpbMakeHandler(DoNothingHandler<T2>))); |
| ASSERT(h.SetStartMessageHandler(UpbMakeHandler(DoNothingHandler<T1>))); |
| |
| ASSERT( |
| !h.SetEndMessageHandler(UpbMakeHandler(DoNothingEndMessageHandler<T2>))); |
| ASSERT( |
| h.SetEndMessageHandler(UpbMakeHandler(DoNothingEndMessageHandler<T1>))); |
| |
| ASSERT(!h.SetStartStringHandler( |
| str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T2>))); |
| ASSERT(h.SetStartStringHandler( |
| str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T1>))); |
| |
| ASSERT(!h.SetEndStringHandler(str, UpbMakeHandler(DoNothingHandler<T2>))); |
| ASSERT(h.SetEndStringHandler(str, UpbMakeHandler(DoNothingHandler<T1>))); |
| |
| ASSERT(!h.SetStartSubMessageHandler( |
| msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>))); |
| ASSERT(h.SetStartSubMessageHandler( |
| msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>))); |
| |
| ASSERT( |
| !h.SetEndSubMessageHandler(msg, UpbMakeHandler(DoNothingHandler<T2>))); |
| ASSERT( |
| h.SetEndSubMessageHandler(msg, UpbMakeHandler(DoNothingHandler<T1>))); |
| |
| ASSERT(!h.SetStartSequenceHandler( |
| r_i32, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>))); |
| ASSERT(h.SetStartSequenceHandler( |
| r_i32, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>))); |
| |
| ASSERT(!h.SetEndSequenceHandler( |
| r_i32, UpbMakeHandler(DoNothingHandler<T2>))); |
| ASSERT(h.SetEndSequenceHandler( |
| r_i32, UpbMakeHandler(DoNothingHandler<T1>))); |
| |
| ASSERT(!h.SetStartSequenceHandler( |
| r_msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>))); |
| ASSERT(h.SetStartSequenceHandler( |
| r_msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>))); |
| |
| ASSERT(!h.SetEndSequenceHandler( |
| r_msg, UpbMakeHandler(DoNothingHandler<T2>))); |
| ASSERT(h.SetEndSequenceHandler( |
| r_msg, UpbMakeHandler(DoNothingHandler<T1>))); |
| |
| ASSERT(!h.SetStartSequenceHandler( |
| r_str, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>))); |
| ASSERT(h.SetStartSequenceHandler( |
| r_str, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>))); |
| |
| ASSERT(!h.SetEndSequenceHandler( |
| r_str, UpbMakeHandler(DoNothingHandler<T2>))); |
| ASSERT(h.SetEndSequenceHandler( |
| r_str, UpbMakeHandler(DoNothingHandler<T1>))); |
| |
| // By setting T1 as the return type for the Start* handlers we have |
| // established T1 as the type of the sequence and string frames. |
| // Setting callbacks that use T2 should fail, but T1 should succeed. |
| ASSERT( |
| !h.SetStringHandler(str, UpbMakeHandler(DoNothingStringBufHandler<T2>))); |
| ASSERT( |
| h.SetStringHandler(str, UpbMakeHandler(DoNothingStringBufHandler<T1>))); |
| |
| ASSERT(!h.SetInt32Handler(r_i32, UpbMakeHandler(DoNothingInt32Handler<T2>))); |
| ASSERT(h.SetInt32Handler(r_i32, UpbMakeHandler(DoNothingInt32Handler<T1>))); |
| |
| ASSERT(!h.SetStartSubMessageHandler( |
| r_msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>))); |
| ASSERT(h.SetStartSubMessageHandler( |
| r_msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>))); |
| |
| ASSERT(!h.SetEndSubMessageHandler(r_msg, |
| UpbMakeHandler(DoNothingHandler<T2>))); |
| ASSERT(h.SetEndSubMessageHandler(r_msg, |
| UpbMakeHandler(DoNothingHandler<T1>))); |
| |
| ASSERT(!h.SetStartStringHandler( |
| r_str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T2>))); |
| ASSERT(h.SetStartStringHandler( |
| r_str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T1>))); |
| |
| ASSERT( |
| !h.SetEndStringHandler(r_str, UpbMakeHandler(DoNothingHandler<T2>))); |
| ASSERT(h.SetEndStringHandler(r_str, UpbMakeHandler(DoNothingHandler<T1>))); |
| |
| ASSERT(!h.SetStringHandler(r_str, |
| UpbMakeHandler(DoNothingStringBufHandler<T2>))); |
| ASSERT(h.SetStringHandler(r_str, |
| UpbMakeHandler(DoNothingStringBufHandler<T1>))); |
| } |
| |
| void RegisterMismatchedTypes2(const void* closure, upb::Handlers* h_ptr) { |
| upb::HandlersPtr h(h_ptr); |
| |
| upb::MessageDefPtr md(h.message_def()); |
| ASSERT(md); |
| upb::FieldDefPtr i32 = md.FindFieldByName("i32"); |
| upb::FieldDefPtr r_i32 = md.FindFieldByName("r_i32"); |
| upb::FieldDefPtr str = md.FindFieldByName("str"); |
| upb::FieldDefPtr r_str = md.FindFieldByName("r_str"); |
| upb::FieldDefPtr msg = md.FindFieldByName("msg"); |
| upb::FieldDefPtr r_msg = md.FindFieldByName("r_msg"); |
| ASSERT(i32); |
| ASSERT(r_i32); |
| ASSERT(str); |
| ASSERT(r_str); |
| ASSERT(msg); |
| ASSERT(r_msg); |
| |
| // For our second test we do the same in reverse. We directly set the type of |
| // the frame and then observe failures at registering a Start* handler that |
| // returns a different type. |
| |
| // First establish the type of a sequence frame directly. |
| ASSERT(h.SetInt32Handler(r_i32, UpbMakeHandler(DoNothingInt32Handler<T1>))); |
| |
| // Now setting a StartSequence callback that returns a different type should |
| // fail. |
| ASSERT(!h.SetStartSequenceHandler( |
| r_i32, UpbMakeHandler(DoNothingStartHandler<T2>::Handler<T1>))); |
| ASSERT(h.SetStartSequenceHandler( |
| r_i32, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>))); |
| |
| // Establish a string frame directly. |
| ASSERT(h.SetStringHandler(r_str, |
| UpbMakeHandler(DoNothingStringBufHandler<T1>))); |
| |
| // Fail setting a StartString callback that returns a different type. |
| ASSERT(!h.SetStartStringHandler( |
| r_str, UpbMakeHandler(DoNothingStartHandler<T2>::String<T1>))); |
| ASSERT(h.SetStartStringHandler( |
| r_str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T1>))); |
| |
| // The previous established T1 as the frame for the r_str sequence. |
| ASSERT(!h.SetStartSequenceHandler( |
| r_str, UpbMakeHandler(DoNothingStartHandler<T2>::Handler<T1>))); |
| ASSERT(h.SetStartSequenceHandler( |
| r_str, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>))); |
| } |
| |
| void TestMismatchedTypes() { |
| // First create a schema for our test. |
| upb::SymbolTable symtab; |
| upb::HandlerCache handler_cache(&RegisterMismatchedTypes, nullptr); |
| upb::HandlerCache handler_cache2(&RegisterMismatchedTypes2, nullptr); |
| const upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr())); |
| |
| // Now test the type-checking in handler registration. |
| handler_cache.Get(md); |
| handler_cache2.Get(md); |
| } |
| |
| class IntIncrementer { |
| public: |
| explicit IntIncrementer(int* x) : x_(x) { (*x_)++; } |
| ~IntIncrementer() { (*x_)--; } |
| |
| static void Handler(void* closure, const IntIncrementer* incrementer, |
| int32_t x) { |
| UPB_UNUSED(closure); |
| UPB_UNUSED(incrementer); |
| UPB_UNUSED(x); |
| } |
| |
| private: |
| int* x_; |
| }; |
| |
| void RegisterIncrementor(const void* closure, upb::Handlers* h_ptr) { |
| const int* x = static_cast<const int*>(closure); |
| upb::HandlersPtr h(h_ptr); |
| upb::FieldDefPtr f = h.message_def().FindFieldByName("i32"); |
| h.SetInt32Handler(f, UpbBind(&IntIncrementer::Handler, |
| new IntIncrementer(const_cast<int*>(x)))); |
| } |
| |
| void TestHandlerDataDestruction() { |
| int x = 0; |
| |
| { |
| upb::SymbolTable symtab; |
| upb::HandlerCache cache(&RegisterIncrementor, &x); |
| upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr())); |
| cache.Get(md); |
| ASSERT(x == 1); |
| } |
| |
| ASSERT(x == 0); |
| } |
| |
| void TestIteration() { |
| upb::SymbolTable symtab; |
| upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr())); |
| |
| // Test range-based for on both fields and oneofs (with the iterator adaptor). |
| int field_count = 0; |
| for (auto field : md.fields()) { |
| UPB_UNUSED(field); |
| field_count++; |
| } |
| ASSERT(field_count == md.field_count()); |
| |
| int oneof_count = 0; |
| for (auto oneof : md.oneofs()) { |
| UPB_UNUSED(oneof); |
| oneof_count++; |
| } |
| ASSERT(oneof_count == md.oneof_count()); |
| } |
| |
| extern "C" { |
| |
| int run_tests(int argc, char *argv[]) { |
| TestHandler<ValueTesterInt32VoidFunctionNoHandlerData>(); |
| TestHandler<ValueTesterInt32BoolFunctionNoHandlerData>(); |
| TestHandler<ValueTesterInt32VoidMethodNoHandlerData>(); |
| TestHandler<ValueTesterInt32BoolMethodNoHandlerData>(); |
| TestHandler<ValueTesterInt32VoidFunctionWithHandlerData>(); |
| TestHandler<ValueTesterInt32BoolFunctionWithHandlerData>(); |
| TestHandler<ValueTesterInt32VoidMethodWithHandlerData>(); |
| TestHandler<ValueTesterInt32BoolMethodWithHandlerData>(); |
| |
| TestHandler<StartMsgTesterVoidFunctionNoHandlerData>(); |
| TestHandler<StartMsgTesterBoolFunctionNoHandlerData>(); |
| TestHandler<StartMsgTesterVoidMethodNoHandlerData>(); |
| TestHandler<StartMsgTesterBoolMethodNoHandlerData>(); |
| TestHandler<StartMsgTesterVoidFunctionWithHandlerData>(); |
| TestHandler<StartMsgTesterBoolFunctionWithHandlerData>(); |
| TestHandler<StartMsgTesterVoidMethodWithHandlerData>(); |
| TestHandler<StartMsgTesterBoolMethodWithHandlerData>(); |
| |
| TestHandler<StringBufTesterVoidMethodNoHandlerDataNoHandle>(); |
| TestHandler<StringBufTesterVoidMethodNoHandlerDataWithHandle>(); |
| TestHandler<StringBufTesterVoidMethodWithHandlerDataNoHandle>(); |
| TestHandler<StringBufTesterVoidMethodWithHandlerDataWithHandle>(); |
| TestHandler<StringBufTesterVoidFunctionNoHandlerDataNoHandle>(); |
| TestHandler<StringBufTesterVoidFunctionNoHandlerDataWithHandle>(); |
| TestHandler<StringBufTesterVoidFunctionWithHandlerDataNoHandle>(); |
| TestHandler<StringBufTesterVoidFunctionWithHandlerDataWithHandle>(); |
| TestHandler<StringBufTesterSizeTMethodNoHandlerDataNoHandle>(); |
| TestHandler<StringBufTesterBoolMethodNoHandlerDataNoHandle>(); |
| |
| TestMismatchedTypes(); |
| |
| TestHandlerDataDestruction(); |
| TestIteration(); |
| |
| return 0; |
| } |
| |
| } |