Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/tests/gtest/TestObserverService.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "nsISupports.h"
7
#include "nsIComponentManager.h"
8
#include "nsIObserverService.h"
9
#include "nsIObserver.h"
10
#include "nsISimpleEnumerator.h"
11
#include "nsComponentManagerUtils.h"
12
13
#include "nsCOMPtr.h"
14
#include "nsString.h"
15
#include "nsWeakReference.h"
16
17
#include "mozilla/RefPtr.h"
18
19
#include "gtest/gtest.h"
20
21
0
static void testResult( nsresult rv ) {
22
0
  EXPECT_TRUE(NS_SUCCEEDED(rv)) << "0x" << std::hex << (int)rv;
23
0
}
24
25
class TestObserver final : public nsIObserver,
26
  public nsSupportsWeakReference
27
{
28
public:
29
  explicit TestObserver( const nsAString &name )
30
    : mName( name )
31
0
    , mObservations( 0 ) {
32
0
    }
33
  NS_DECL_ISUPPORTS
34
  NS_DECL_NSIOBSERVER
35
36
  nsString mName;
37
  int mObservations;
38
  static int sTotalObservations;
39
40
  nsString mExpectedData;
41
42
private:
43
0
  ~TestObserver() {}
44
};
45
46
NS_IMPL_ISUPPORTS( TestObserver, nsIObserver, nsISupportsWeakReference )
47
48
int TestObserver::sTotalObservations;
49
50
NS_IMETHODIMP
51
TestObserver::Observe(nsISupports *aSubject,
52
    const char *aTopic,
53
0
    const char16_t *someData ) {
54
0
  mObservations++;
55
0
  sTotalObservations++;
56
0
57
0
  if (!mExpectedData.IsEmpty()) {
58
0
    EXPECT_TRUE(mExpectedData.Equals(someData));
59
0
  }
60
0
61
0
  return NS_OK;
62
0
}
63
64
static nsISupports* ToSupports(TestObserver* aObs)
65
0
{
66
0
  return static_cast<nsIObserver*>(aObs);
67
0
}
68
69
static void TestExpectedCount(
70
    nsIObserverService* svc,
71
    const char* topic,
72
    size_t expected)
73
0
{
74
0
  nsCOMPtr<nsISimpleEnumerator> e;
75
0
  nsresult rv = svc->EnumerateObservers(topic, getter_AddRefs(e));
76
0
  testResult(rv);
77
0
  EXPECT_TRUE(e);
78
0
79
0
  bool hasMore = false;
80
0
  rv = e->HasMoreElements(&hasMore);
81
0
  testResult(rv);
82
0
83
0
  if (expected == 0) {
84
0
    EXPECT_FALSE(hasMore);
85
0
    return;
86
0
  }
87
0
88
0
  size_t count = 0;
89
0
  while (hasMore) {
90
0
    count++;
91
0
92
0
    // Grab the element.
93
0
    nsCOMPtr<nsISupports> supports;
94
0
    e->GetNext(getter_AddRefs(supports));
95
0
    ASSERT_TRUE(supports);
96
0
97
0
    // Move on.
98
0
    rv = e->HasMoreElements(&hasMore);
99
0
    testResult(rv);
100
0
  }
101
0
102
0
  EXPECT_EQ(count, expected);
103
0
}
104
105
TEST(ObserverService, Creation)
106
0
{
107
0
  nsresult rv;
108
0
  nsCOMPtr<nsIObserverService> svc =
109
0
    do_CreateInstance("@mozilla.org/observer-service;1", &rv);
110
0
111
0
  ASSERT_EQ(rv, NS_OK);
112
0
  ASSERT_TRUE(svc);
113
0
}
114
115
TEST(ObserverService, AddObserver)
116
0
{
117
0
  nsCOMPtr<nsIObserverService> svc =
118
0
    do_CreateInstance("@mozilla.org/observer-service;1");
119
0
120
0
  // Add a strong ref.
121
0
  RefPtr<TestObserver> a = new TestObserver(NS_LITERAL_STRING("A"));
122
0
  nsresult rv = svc->AddObserver(a, "Foo", false);
123
0
  testResult(rv);
124
0
125
0
  // Add a few weak ref.
126
0
  RefPtr<TestObserver> b = new TestObserver(NS_LITERAL_STRING("B"));
127
0
  rv = svc->AddObserver(b, "Bar", true);
128
0
  testResult(rv);
129
0
}
130
131
TEST(ObserverService, RemoveObserver)
132
0
{
133
0
  nsCOMPtr<nsIObserverService> svc =
134
0
    do_CreateInstance("@mozilla.org/observer-service;1");
135
0
136
0
  RefPtr<TestObserver> a = new TestObserver(NS_LITERAL_STRING("A"));
137
0
  RefPtr<TestObserver> b = new TestObserver(NS_LITERAL_STRING("B"));
138
0
  RefPtr<TestObserver> c = new TestObserver(NS_LITERAL_STRING("C"));
139
0
140
0
  svc->AddObserver(a, "Foo", false);
141
0
  svc->AddObserver(b, "Foo", true);
142
0
143
0
  // Remove from non-existent topic.
144
0
  nsresult rv = svc->RemoveObserver(a, "Bar");
145
0
  ASSERT_TRUE(NS_FAILED(rv));
146
0
147
0
  // Remove a.
148
0
  testResult(svc->RemoveObserver(a, "Foo"));
149
0
150
0
  // Remove b.
151
0
  testResult(svc->RemoveObserver(b, "Foo"));
152
0
153
0
  // Attempt to remove c.
154
0
  rv = svc->RemoveObserver(c, "Foo");
155
0
  ASSERT_TRUE(NS_FAILED(rv));
156
0
}
157
158
TEST(ObserverService, EnumerateEmpty)
159
0
{
160
0
  nsCOMPtr<nsIObserverService> svc =
161
0
    do_CreateInstance("@mozilla.org/observer-service;1");
162
0
163
0
  // Try with no observers.
164
0
  TestExpectedCount(svc, "A", 0);
165
0
166
0
  // Now add an observer and enumerate an unobserved topic.
167
0
  RefPtr<TestObserver> a = new TestObserver(NS_LITERAL_STRING("A"));
168
0
  testResult(svc->AddObserver(a, "Foo", false));
169
0
170
0
  TestExpectedCount(svc, "A", 0);
171
0
}
172
173
TEST(ObserverService, Enumerate)
174
0
{
175
0
  nsCOMPtr<nsIObserverService> svc =
176
0
    do_CreateInstance("@mozilla.org/observer-service;1");
177
0
178
0
  const size_t kFooCount = 10;
179
0
  for (size_t i = 0; i < kFooCount; i++) {
180
0
    RefPtr<TestObserver> a = new TestObserver(NS_LITERAL_STRING("A"));
181
0
    testResult(svc->AddObserver(a, "Foo", false));
182
0
  }
183
0
184
0
  const size_t kBarCount = kFooCount / 2;
185
0
  for (size_t i = 0; i < kBarCount; i++) {
186
0
    RefPtr<TestObserver> a = new TestObserver(NS_LITERAL_STRING("A"));
187
0
    testResult(svc->AddObserver(a, "Bar", false));
188
0
  }
189
0
190
0
  // Enumerate "Foo".
191
0
  TestExpectedCount(svc, "Foo", kFooCount);
192
0
193
0
  // Enumerate "Bar".
194
0
  TestExpectedCount(svc, "Bar", kBarCount);
195
0
}
196
197
TEST(ObserverService, EnumerateWeakRefs)
198
0
{
199
0
  nsCOMPtr<nsIObserverService> svc =
200
0
    do_CreateInstance("@mozilla.org/observer-service;1");
201
0
202
0
  const size_t kFooCount = 10;
203
0
  for (size_t i = 0; i < kFooCount; i++) {
204
0
    RefPtr<TestObserver> a = new TestObserver(NS_LITERAL_STRING("A"));
205
0
    testResult(svc->AddObserver(a, "Foo", true));
206
0
  }
207
0
208
0
  // All refs are out of scope, expect enumeration to be empty.
209
0
  TestExpectedCount(svc, "Foo", 0);
210
0
211
0
  // Now test a mixture.
212
0
  for (size_t i = 0; i < kFooCount; i++) {
213
0
    RefPtr<TestObserver> a = new TestObserver(NS_LITERAL_STRING("A"));
214
0
    RefPtr<TestObserver> b = new TestObserver(NS_LITERAL_STRING("B"));
215
0
216
0
    // Register a as weak for "Foo".
217
0
    testResult(svc->AddObserver(a, "Foo", true));
218
0
219
0
    // Register b as strong for "Foo".
220
0
    testResult(svc->AddObserver(b, "Foo", false));
221
0
  }
222
0
223
0
  // Expect the b instances to stick around.
224
0
  TestExpectedCount(svc, "Foo", kFooCount);
225
0
226
0
  // Now add a couple weak refs, but don't go out of scope.
227
0
  RefPtr<TestObserver> a = new TestObserver(NS_LITERAL_STRING("A"));
228
0
  testResult(svc->AddObserver(a, "Foo", true));
229
0
  RefPtr<TestObserver> b = new TestObserver(NS_LITERAL_STRING("B"));
230
0
  testResult(svc->AddObserver(b, "Foo", true));
231
0
232
0
  // Expect all the observers from before and the two new ones.
233
0
  TestExpectedCount(svc, "Foo", kFooCount + 2);
234
0
}
235
236
TEST(ObserverService, TestNotify)
237
0
{
238
0
  nsCString topicA; topicA.Assign( "topic-A" );
239
0
  nsCString topicB; topicB.Assign( "topic-B" );
240
0
241
0
  nsCOMPtr<nsIObserverService> svc =
242
0
    do_CreateInstance("@mozilla.org/observer-service;1");
243
0
244
0
  RefPtr<TestObserver> aObserver = new TestObserver(NS_LITERAL_STRING("Observer-A"));
245
0
  RefPtr<TestObserver> bObserver = new TestObserver(NS_LITERAL_STRING("Observer-B"));
246
0
247
0
  // Add two observers for topicA.
248
0
  testResult(svc->AddObserver(aObserver, topicA.get(), false));
249
0
  testResult(svc->AddObserver(bObserver, topicA.get(), false));
250
0
251
0
  // Add one observer for topicB.
252
0
  testResult(svc->AddObserver(bObserver, topicB.get(), false));
253
0
254
0
  // Notify topicA.
255
0
  const char16_t* dataA = u"Testing Notify(observer-A, topic-A)";
256
0
  aObserver->mExpectedData = dataA;
257
0
  bObserver->mExpectedData = dataA;
258
0
  nsresult rv =
259
0
      svc->NotifyObservers(ToSupports(aObserver), topicA.get(), dataA);
260
0
  testResult(rv);
261
0
  ASSERT_EQ(aObserver->mObservations, 1);
262
0
  ASSERT_EQ(bObserver->mObservations, 1);
263
0
264
0
  // Notify topicB.
265
0
  const char16_t* dataB = u"Testing Notify(observer-B, topic-B)";
266
0
  bObserver->mExpectedData = dataB;
267
0
  rv = svc->NotifyObservers(ToSupports(bObserver), topicB.get(), dataB);
268
0
  testResult(rv);
269
0
  ASSERT_EQ(aObserver->mObservations, 1);
270
0
  ASSERT_EQ(bObserver->mObservations, 2);
271
0
272
0
  // Remove one of the topicA observers, make sure it's not notified.
273
0
  testResult(svc->RemoveObserver(aObserver, topicA.get()));
274
0
275
0
  // Notify topicA, only bObserver is expected to be notified.
276
0
  bObserver->mExpectedData = dataA;
277
0
  rv = svc->NotifyObservers(ToSupports(aObserver), topicA.get(), dataA);
278
0
  testResult(rv);
279
0
  ASSERT_EQ(aObserver->mObservations, 1);
280
0
  ASSERT_EQ(bObserver->mObservations, 3);
281
0
282
0
  // Remove the other topicA observer, make sure none are notified.
283
0
  testResult(svc->RemoveObserver(bObserver, topicA.get()));
284
0
  rv = svc->NotifyObservers(ToSupports(aObserver), topicA.get(), dataA);
285
0
  testResult(rv);
286
0
  ASSERT_EQ(aObserver->mObservations, 1);
287
0
  ASSERT_EQ(bObserver->mObservations, 3);
288
0
}