summaryrefslogtreecommitdiff
path: root/tests/test_disconnect.cc
blob: 2d040d89d8b88eb4ec4efbb8330462f38eeb757a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/* Copyright 2002, The libsigc++ Development Team
 *  Assigned to public domain.  Use as you wish without restriction.
 */

// sigc::signal<>.slots() is deprecated, but let's keep the test if possible.
// If libsigc++ is configured with -Dbuild-deprecated-api=false
// (--disable-deprecated-api), SIGCXX_DISABLE_DEPRECATED is defined in
// sigc++config.h. An undef at the start of this file has no effect.
#undef SIGCXX_DISABLE_DEPRECATED

#include "testutilities.h"
#include <sigc++/trackable.h>
#include <sigc++/signal.h>
#include <sigc++/connection.h>
#include <sigc++/adaptors/compose.h>
#include <sigc++/functors/ptr_fun.h>
#include <sigc++/functors/mem_fun.h>
#include <sstream>
#include <cstdlib>

//The Tru64 compiler seems to need this to avoid an unresolved symbol
//See bug #161503
#include <new>

namespace
{
std::ostringstream result_stream;

int foo(int i)
{
  result_stream << "foo(" << i << ") ";
  return 1;
}

int bar(double i)
{
  result_stream << "bar(" << i << ") ";
  return 1;
}

struct A : public sigc::trackable
{
  int foo(int i)
  {
    result_stream << "A::foo(" << i << ") ";
    return 1;
  }
};

void good_bye_world()
{
  result_stream << "Good bye world!";
}

struct B : public sigc::trackable
{
  B()
  {
    sig.connect(sigc::mem_fun(*this, &B::destroy));
    sig.connect(sigc::mem_fun(*this, &B::boom));
    sig.connect(sigc::ptr_fun(&good_bye_world));
  }

  void destroy()   // Calling destroy() during signal emission seems weird!
  {                // However, if this works, anything will work!
    delete this;   // valgrind reports a small memory leak, that's all.
  }

  void boom()
  {
    result_stream << "boom!";
  }

  void emit()
  {
    sig.emit();
  }

  sigc::signal<void> sig;
};

} // end anonymous namespace

int main(int argc, char* argv[])
{
  auto util = TestUtilities::get_instance();

  if (!util->check_command_args(argc, argv))
    return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;

  sigc::signal<int, int> sig;
  sigc::signal<int, int>::iterator confoo;
  sigc::signal<int, int>::iterator conbar;
  sigc::connection cona;  // connection objects are safe to use beyond the life time of a signal.

  {
    A a;
    sig.connect(sigc::mem_fun1(a, &A::foo));
    confoo = sig.connect(sigc::ptr_fun1(&foo));
    conbar = sig.connect(sigc::ptr_fun1(&bar));
    result_stream << "sig is connected to A::foo, foo, bar (size=" << sig.size() << "): ";
    sig(1);
    util->check_result(result_stream,
      "sig is connected to A::foo, foo, bar (size=3): A::foo(1) foo(1) bar(1) ");
  }                     // auto disconnection! iterators stay valid after disconnections.

  result_stream << "sig is connected to foo, bar (size=" << sig.size() << "): ";
  sig(2);
  util->check_result(result_stream, "sig is connected to foo, bar (size=2): foo(2) bar(2) ");

  A a;                  // iterators stay valid after further connections.
#ifndef SIGCXX_DISABLE_DEPRECATED
  cona = sig.slots().insert(conbar, sigc::mem_fun1(a, &A::foo));
#else
  cona = sig.connect(sigc::mem_fun1(a, &A::foo));
#endif
  result_stream << "sig is connected to foo, A::foo, bar (size=" << sig.size() << "): ";
  sig(3);
#ifndef SIGCXX_DISABLE_DEPRECATED
  util->check_result(result_stream,
    "sig is connected to foo, A::foo, bar (size=3): foo(3) A::foo(3) bar(3) ");
#else
  util->check_result(result_stream,
    "sig is connected to foo, A::foo, bar (size=3): foo(3) bar(3) A::foo(3) ");
#endif

  conbar->disconnect(); // manual disconnection
  result_stream << "sig is connected to foo, A::foo (size=" << sig.size() << "): ";
  sig(4);
  util->check_result(result_stream, "sig is connected to foo, A::foo (size=2): foo(4) A::foo(4) ");

  confoo->disconnect(); // manual disconnection
  result_stream << "sig is connected to A::foo (size=" << sig.size() << "): ";
  sig(5);
  util->check_result(result_stream, "sig is connected to A::foo (size=1): A::foo(5) ");

  cona.disconnect();    // manual disconnection
  result_stream << "sig is empty (size=" << sig.size() << "): ";
  sig(6);
  util->check_result(result_stream, "sig is empty (size=0): ");

  cona.disconnect();    // already disconnected -> legal with connection objects, however, nothing happens ...

  {
    A a2;
    sig.connect(sigc::compose(sigc::mem_fun(a2, &A::foo), &foo));
    result_stream << "sig is connected to compose(A::foo, foo) (size=" << sig.size() << "): ";
    sig(7);
    util->check_result(result_stream, "sig is connected to compose(A::foo, foo) (size=1): foo(7) A::foo(1) ");
  }
  result_stream << "sig is empty (size=" << sig.size() << "): ";
  sig(8);
  util->check_result(result_stream, "sig is empty (size=0): ");

  { // A slot# within a slot
    A a2;
    sigc::slot1<int, int> setter = sigc::mem_fun(a2, &A::foo);
    sig.connect(sigc::compose(setter, &foo));
    result_stream << "sig is connected to compose(slot1(A::foo), foo) (size=" << sig.size() << "): ";
    sig(9);
    util->check_result(result_stream, "sig is connected to compose(slot1(A::foo), foo) (size=1): foo(9) A::foo(1) ");
  }
  result_stream << "sig is empty (size=" << sig.size() << "): ";
  sig(10);
  util->check_result(result_stream, "sig is empty (size=0): ");

  { // A slot within a slot
    A a2;
    sigc::slot<int, int> setter = sigc::mem_fun(a2, &A::foo);
    sig.connect(sigc::compose(setter, &foo));
    result_stream << "sig is connected to compose(slot(A::foo), foo) (size=" << sig.size() << "): ";
    sig(11);
    util->check_result(result_stream, "sig is connected to compose(slot(A::foo), foo) (size=1): foo(11) A::foo(1) ");
  }
  result_stream << "sig is empty (size=" << sig.size() << "): ";
  sig(12);
  util->check_result(result_stream, "sig is empty (size=0): ");

  result_stream << "deleting a signal during emission... ";
  auto b = new B;
  b->emit();
  util->check_result(result_stream, "deleting a signal during emission... Good bye world!");

  return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
}