| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| /// Test reference counting for object wrappers, threads_safe<> wrappers and returned<> wrappers. |
| /// |
| |
| #include "test_bits.hpp" |
| #include "test_dummy_container.hpp" |
| #include "proton_bits.hpp" |
| |
| #include "proton/thread_safe.hpp" |
| #include "proton/io/connection_engine.hpp" |
| #include "proton/io/link_namer.hpp" |
| |
| #include <proton/connection.h> |
| |
| namespace { |
| |
| using namespace proton; |
| using namespace test; |
| using namespace std; |
| |
| dummy_container cont; |
| |
| namespace { |
| struct linknames : io::link_namer { |
| std::string link_name() { return "X"; } |
| } dummy_link_namer; |
| } |
| |
| void test_new() { |
| pn_connection_t* c = 0; |
| thread_safe<connection>* p = 0; |
| { |
| io::connection_engine e(cont, dummy_link_namer, new dummy_event_loop); |
| c = unwrap(e.connection()); |
| int r = pn_refcount(c); |
| ASSERT(r >= 1); // engine may have internal refs (transport, collector). |
| p = make_thread_safe(e.connection()).release(); |
| ASSERT_EQUAL(r+1, pn_refcount(c)); |
| delete p; |
| ASSERT_EQUAL(r, pn_refcount(c)); |
| p = make_thread_safe(e.connection()).release(); |
| } |
| ASSERT_EQUAL(1, pn_refcount(c)); // Engine gone, thread_safe keeping c alive. |
| delete p; |
| |
| #if PN_CPP_HAS_CPP11 |
| { |
| std::shared_ptr<thread_safe<connection> > sp; |
| { |
| io::connection_engine e(cont, dummy_link_namer, new dummy_event_loop); |
| c = unwrap(e.connection()); |
| sp = make_shared_thread_safe(e.connection()); |
| } |
| ASSERT_EQUAL(1, pn_refcount(c)); // Engine gone, sp keeping c alive. |
| } |
| { |
| std::unique_ptr<thread_safe<connection> > up; |
| { |
| io::connection_engine e(cont, dummy_link_namer, new dummy_event_loop); |
| c = unwrap(e.connection()); |
| up = make_unique_thread_safe(e.connection()); |
| } |
| ASSERT_EQUAL(1, pn_refcount(c)); // Engine gone, sp keeping c alive. |
| } |
| #endif |
| } |
| |
| void test_convert() { |
| // Verify refcounts as expected with conversion between proton::object |
| // and thread_safe. |
| connection c; |
| pn_connection_t* pc = 0; |
| { |
| io::connection_engine eng(cont, dummy_link_namer, new dummy_event_loop); |
| c = eng.connection(); |
| pc = unwrap(c); // Unwrap in separate scope to avoid confusion from temp values. |
| } |
| { |
| ASSERT_EQUAL(1, pn_refcount(pc)); |
| returned<connection> pptr = make_thread_safe(c); |
| ASSERT_EQUAL(2, pn_refcount(pc)); |
| returned<connection> pp2 = pptr; |
| ASSERT(!pptr.release()); // Transferred to pp2 |
| ASSERT_EQUAL(2, pn_refcount(pc)); |
| connection c2 = pp2; // Transfer and convert to target |
| ASSERT_EQUAL(3, pn_refcount(pc)); // c, c2, thread_safe. |
| ASSERT(c == c2); |
| } |
| ASSERT_EQUAL(1, pn_refcount(pc)); // only c is left |
| } |
| |
| } |
| |
| int main(int, char**) { |
| int failed = 0; |
| RUN_TEST(failed, test_new()); |
| RUN_TEST(failed, test_convert()); |
| return failed; |
| } |