Imported Upstream version 2.99.2
[platform/upstream/libsigc++.git] / tests / test_track_obj.cc
1 /* Copyright (C) 2013 The libsigc++ Development Team
2  *
3  * This file is part of libsigc++.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 // The purpose of this test case is threefold.
20 // - Test sigc::track_obj().
21 // - Show that a slot with a C++11 lambda expression can be automatically
22 //   disconnected when an object derived from sigc::trackable is deleted,
23 //   provided sigc::track_obj() is used.
24 //   It's shown here as a preparation for deprecating and eventually
25 //   deleting the libsigc++ lambda expressions.
26 //   See https://bugzilla.gnome.org/show_bug.cgi?id=672555
27 // - Test the code example in the documentation in sigc++/adaptors/track_obj.h.
28 //
29 // To test the C++11 lambda expressions with gcc 4.6.3 (and probably some later
30 // versions of gcc; gcc 4.7.x also understands -std=c++11):
31 //   make CXXFLAGS='-g -O2 -std=c++0x' test_track_obj
32 //   ./test_track_obj
33 //   echo $?
34 // If test_track_obj writes nothing and the return code is 0, the test has passed.
35
36
37 #include "testutilities.h"
38 #include <string>
39 #include <iostream>
40 #include <sstream>
41 #include <cstdlib>
42 #include <sigc++/adaptors/track_obj.h>
43 #include <sigc++/signal.h>
44
45
46 namespace
47 {
48 std::ostringstream result_stream;
49
50 struct book : public sigc::trackable
51 {
52   explicit book(const std::string& name) : name_(name) {}
53   operator std::string& () { return name_; }
54   operator const std::string& () const { return name_; }
55   std::string name_;
56 };
57
58 struct bar_group4 : public sigc::trackable
59 {
60 };
61
62 class Functor1 : public sigc::functor_base
63 {
64 public:
65   using result_type = std::string;
66
67   Functor1(const bar_group4& bar)
68   : bar_(bar) {}
69
70   std::string operator()(int i)
71   {
72     return (i<0) ? "negative" : ((i>0) ? "positive" : "zero");
73   }
74
75 private:
76   const bar_group4& bar_;
77 };
78
79 class Functor2 : public sigc::functor_base
80 {
81 public:
82   using result_type = std::string;
83
84   Functor2(const bar_group4& bar, const book& aBook)
85   : bar_(bar), aBook_(aBook) {}
86
87   std::string operator()(int i, const std::string& str) const
88   {
89     std::string result = (i<0) ? "negative, " : ((i>0) ? "positive, " : "zero, ");
90     result += str;
91     result += aBook_;
92     return result;
93   }
94
95 private:
96   const bar_group4& bar_;
97   const book& aBook_;
98 };
99
100 //C++11 lamba expressions:
101
102 inline std::ostringstream& operator << (std::ostringstream& s, const book& b)
103 {
104   s << b.name_;
105   return s;
106 }
107
108 void egon(std::string& str)
109 {
110   result_stream << "egon(string '" << str << "')";
111   str = "egon was here";
112 }
113
114 void foo_group4(bar_group4&)
115 {
116   result_stream << "foo_group4(bar_group4&)";
117 }
118
119 } // end anonymous namespace
120
121
122 int main(int argc, char* argv[])
123 {
124   auto util = TestUtilities::get_instance();
125
126   if (!util->check_command_args(argc, argv))
127     return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
128
129   sigc::slot<std::string(int)> sl1;
130   {
131     bar_group4 bar4;
132     sl1 = sigc::track_obj(Functor1(bar4), bar4);
133     result_stream << sl1(-2);
134     util->check_result(result_stream, "negative");
135
136   } // auto-disconnect sl1
137
138   result_stream << sl1(-2);
139   util->check_result(result_stream, "");
140
141   // Allocate on the heap. valgrind can then find erroneous memory accesses.
142   // (There should be none, of course.)
143   auto psl2 = new sigc::slot<std::string(int, std::string)>;
144   bar_group4* pbar4 = new bar_group4;
145   book* pbook4 = new book("A Book");
146   *psl2 = sigc::track_obj(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
147   result_stream << (*psl2)(0, "Book title: ");
148   util->check_result(result_stream, "zero, Book title: A Book");
149
150   delete pbook4; // auto-disconnect *psl2
151   pbook4 = nullptr;
152   result_stream << (*psl2)(0, "Book title: ");
153   util->check_result(result_stream, "");
154   delete psl2;
155   psl2 = nullptr;
156   delete pbar4;
157   pbar4 = nullptr;
158
159
160 //C++11 lambda expressions:
161
162   // auto-disconnect
163   // If you want to auto-disconnect a slot with a C++11 lambda expression
164   // that contains references to sigc::trackable-derived objects, you must use
165   // sigc::track_obj().
166   sigc::slot<void(std::ostringstream&)> sl10;
167   {
168     book guest_book("karl");
169     // sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; }; // no auto-disconnect
170     sl10 = sigc::track_obj([&guest_book](std::ostringstream& stream){ stream << guest_book; }, guest_book);
171     sl10(result_stream);
172     util->check_result(result_stream, "karl");
173
174   } // auto-disconnect sl10
175
176   sl10(result_stream);
177   util->check_result(result_stream, "");
178
179   // auto-disconnect
180   sigc::slot<void()> sl20;
181   {
182     book guest_book("karl");
183     // sl2 = [&guest_book] () { egon(guest_book); }; // no auto-disconnect
184     // sl2 = std::bind(&egon, std::ref(guest_book)); // does not compile (gcc 4.6.3)
185     sl20 = sigc::track_obj([&guest_book] () { egon(guest_book); }, guest_book);
186     sl20();
187     util->check_result(result_stream, "egon(string 'karl')");
188
189     result_stream << static_cast<const std::string&>(guest_book);
190     util->check_result(result_stream, "egon was here");
191
192   } // auto-disconnect sl20
193
194   sl20();
195   util->check_result(result_stream, "");
196
197
198   // Code example in the documentation sigc++/adaptors/macros/track_obj.h.m4
199   // -----------------------------------------------------------------------
200   {
201     //struct bar : public sigc::trackable {} some_bar;
202     sigc::signal<void()> some_signal;
203     {
204       bar_group4 some_bar;
205       //some_signal.connect(sigc::group(&foo, std::ref(some_bar)));
206       // disconnected automatically if some_bar goes out of scope
207       //some_signal.connect([&some_bar](){ foo_group4(some_bar); }); // no auto-disconnect
208       //some_signal.connect(sigc::bind(&foo_group4, std::ref(some_bar))); // auto-disconnects, but we prefer C++11 lambda
209       some_signal.connect(sigc::track_obj([&some_bar](){ foo_group4(some_bar); }, some_bar));
210       some_signal.emit();
211       util->check_result(result_stream, "foo_group4(bar_group4&)");
212
213     } // auto-disconnect the lambda expression
214
215     some_signal.emit();
216     util->check_result(result_stream, "");
217   }
218
219
220   return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
221 }