Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/gtest/TestMediaEventSource.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 "gtest/gtest.h"
7
8
#include "mozilla/SharedThreadPool.h"
9
#include "mozilla/TaskQueue.h"
10
#include "mozilla/UniquePtr.h"
11
#include "MediaEventSource.h"
12
#include "VideoUtils.h"
13
14
using namespace mozilla;
15
16
/*
17
 * Test if listeners receive the event data correctly.
18
 */
19
TEST(MediaEventSource, SingleListener)
20
0
{
21
0
  RefPtr<TaskQueue> queue = new TaskQueue(
22
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
23
0
24
0
  MediaEventProducer<int> source;
25
0
  int i = 0;
26
0
27
0
  auto func = [&] (int j) { i += j; };
28
0
  MediaEventListener listener = source.Connect(queue, func);
29
0
30
0
  // Call Notify 3 times. The listener should be also called 3 times.
31
0
  source.Notify(3);
32
0
  source.Notify(5);
33
0
  source.Notify(7);
34
0
35
0
  queue->BeginShutdown();
36
0
  queue->AwaitShutdownAndIdle();
37
0
38
0
  // Verify the event data is passed correctly to the listener.
39
0
  EXPECT_EQ(i, 15); // 3 + 5 + 7
40
0
  listener.Disconnect();
41
0
}
42
43
TEST(MediaEventSource, MultiListener)
44
0
{
45
0
  RefPtr<TaskQueue> queue = new TaskQueue(
46
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
47
0
48
0
  MediaEventProducer<int> source;
49
0
  int i = 0;
50
0
  int j = 0;
51
0
52
0
  auto func1 = [&] (int k) { i = k * 2; };
53
0
  auto func2 = [&] (int k) { j = k * 3; };
54
0
  MediaEventListener listener1 = source.Connect(queue, func1);
55
0
  MediaEventListener listener2 = source.Connect(queue, func2);
56
0
57
0
  // Both listeners should receive the event.
58
0
  source.Notify(11);
59
0
60
0
  queue->BeginShutdown();
61
0
  queue->AwaitShutdownAndIdle();
62
0
63
0
  // Verify the event data is passed correctly to the listener.
64
0
  EXPECT_EQ(i, 22); // 11 * 2
65
0
  EXPECT_EQ(j, 33); // 11 * 3
66
0
67
0
  listener1.Disconnect();
68
0
  listener2.Disconnect();
69
0
}
70
71
/*
72
 * Test if disconnecting a listener prevents events from coming.
73
 */
74
TEST(MediaEventSource, DisconnectAfterNotification)
75
0
{
76
0
  RefPtr<TaskQueue> queue = new TaskQueue(
77
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
78
0
79
0
  MediaEventProducer<int> source;
80
0
  int i = 0;
81
0
82
0
  MediaEventListener listener;
83
0
  auto func = [&] (int j) { i += j; listener.Disconnect(); };
84
0
  listener = source.Connect(queue, func);
85
0
86
0
  // Call Notify() twice. Since we disconnect the listener when receiving
87
0
  // the 1st event, the 2nd event should not reach the listener.
88
0
  source.Notify(11);
89
0
  source.Notify(11);
90
0
91
0
  queue->BeginShutdown();
92
0
  queue->AwaitShutdownAndIdle();
93
0
94
0
  // Check only the 1st event is received.
95
0
  EXPECT_EQ(i, 11);
96
0
}
97
98
TEST(MediaEventSource, DisconnectBeforeNotification)
99
0
{
100
0
  RefPtr<TaskQueue> queue = new TaskQueue(
101
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
102
0
103
0
  MediaEventProducer<int> source;
104
0
  int i = 0;
105
0
  int j = 0;
106
0
107
0
  auto func1 = [&] (int k) { i = k * 2; };
108
0
  auto func2 = [&] (int k) { j = k * 3; };
109
0
  MediaEventListener listener1 = source.Connect(queue, func1);
110
0
  MediaEventListener listener2 = source.Connect(queue, func2);
111
0
112
0
  // Disconnect listener2 before notification. Only listener1 should receive
113
0
  // the event.
114
0
  listener2.Disconnect();
115
0
  source.Notify(11);
116
0
117
0
  queue->BeginShutdown();
118
0
  queue->AwaitShutdownAndIdle();
119
0
120
0
  EXPECT_EQ(i, 22); // 11 * 2
121
0
  EXPECT_EQ(j, 0); // event not received
122
0
123
0
  listener1.Disconnect();
124
0
}
125
126
/*
127
 * Test we don't hit the assertion when calling Connect() and Disconnect()
128
 * repeatedly.
129
 */
130
TEST(MediaEventSource, DisconnectAndConnect)
131
0
{
132
0
  RefPtr<TaskQueue> queue;
133
0
  MediaEventProducerExc<int> source;
134
0
  MediaEventListener listener = source.Connect(queue, [](){});
135
0
  listener.Disconnect();
136
0
  listener = source.Connect(queue, [](){});
137
0
  listener.Disconnect();
138
0
}
139
140
/*
141
 * Test void event type.
142
 */
143
TEST(MediaEventSource, VoidEventType)
144
0
{
145
0
  RefPtr<TaskQueue> queue = new TaskQueue(
146
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
147
0
148
0
  MediaEventProducer<void> source;
149
0
  int i = 0;
150
0
151
0
  // Test function object.
152
0
  auto func = [&] () { ++i; };
153
0
  MediaEventListener listener1 = source.Connect(queue, func);
154
0
155
0
  // Test member function.
156
0
  struct Foo {
157
0
    Foo() : j(1) {}
158
0
    void OnNotify() {
159
0
      j *= 2;
160
0
    }
161
0
    int j;
162
0
  } foo;
163
0
  MediaEventListener listener2 = source.Connect(queue, &foo, &Foo::OnNotify);
164
0
165
0
  // Call Notify 2 times. The listener should be also called 2 times.
166
0
  source.Notify();
167
0
  source.Notify();
168
0
169
0
  queue->BeginShutdown();
170
0
  queue->AwaitShutdownAndIdle();
171
0
172
0
  // Verify the event data is passed correctly to the listener.
173
0
  EXPECT_EQ(i, 2); // ++i called twice
174
0
  EXPECT_EQ(foo.j, 4); // |j *= 2| called twice
175
0
  listener1.Disconnect();
176
0
  listener2.Disconnect();
177
0
}
178
179
/*
180
 * Test listeners can take various event types (T, T&&, const T& and void).
181
 */
182
TEST(MediaEventSource, ListenerType1)
183
0
{
184
0
  RefPtr<TaskQueue> queue = new TaskQueue(
185
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
186
0
187
0
  MediaEventProducer<int> source;
188
0
  int i = 0;
189
0
190
0
  // Test various argument types.
191
0
  auto func1 = [&] (int&& j) { i += j; };
192
0
  auto func2 = [&] (const int& j) { i += j; };
193
0
  auto func3 = [&] () { i += 1; };
194
0
  MediaEventListener listener1 = source.Connect(queue, func1);
195
0
  MediaEventListener listener2 = source.Connect(queue, func2);
196
0
  MediaEventListener listener3 = source.Connect(queue, func3);
197
0
198
0
  source.Notify(1);
199
0
200
0
  queue->BeginShutdown();
201
0
  queue->AwaitShutdownAndIdle();
202
0
203
0
  EXPECT_EQ(i, 3);
204
0
205
0
  listener1.Disconnect();
206
0
  listener2.Disconnect();
207
0
  listener3.Disconnect();
208
0
}
209
210
TEST(MediaEventSource, ListenerType2)
211
0
{
212
0
  RefPtr<TaskQueue> queue = new TaskQueue(
213
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
214
0
215
0
  MediaEventProducer<int> source;
216
0
217
0
  struct Foo {
218
0
    Foo() : mInt(0) {}
219
0
    void OnNotify1(int&& i) { mInt += i; }
220
0
    void OnNotify2(const int& i) { mInt += i; }
221
0
    void OnNotify3() { mInt += 1; }
222
0
    void OnNotify4(int i) const { mInt += i; }
223
0
    void OnNotify5(int i) volatile { mInt += i; }
224
0
    mutable int mInt;
225
0
  } foo;
226
0
227
0
  // Test member functions which might be CV qualified.
228
0
  MediaEventListener listener1 = source.Connect(queue, &foo, &Foo::OnNotify1);
229
0
  MediaEventListener listener2 = source.Connect(queue, &foo, &Foo::OnNotify2);
230
0
  MediaEventListener listener3 = source.Connect(queue, &foo, &Foo::OnNotify3);
231
0
  MediaEventListener listener4 = source.Connect(queue, &foo, &Foo::OnNotify4);
232
0
  MediaEventListener listener5 = source.Connect(queue, &foo, &Foo::OnNotify5);
233
0
234
0
  source.Notify(1);
235
0
236
0
  queue->BeginShutdown();
237
0
  queue->AwaitShutdownAndIdle();
238
0
239
0
  EXPECT_EQ(foo.mInt, 5);
240
0
241
0
  listener1.Disconnect();
242
0
  listener2.Disconnect();
243
0
  listener3.Disconnect();
244
0
  listener4.Disconnect();
245
0
  listener5.Disconnect();
246
0
}
247
248
struct SomeEvent {
249
0
  explicit SomeEvent(int& aCount) : mCount(aCount) {}
250
  // Increment mCount when copy constructor is called to know how many times
251
  // the event data is copied.
252
0
  SomeEvent(const SomeEvent& aOther) : mCount(aOther.mCount) {
253
0
    ++mCount;
254
0
  }
255
0
  SomeEvent(SomeEvent&& aOther) : mCount(aOther.mCount) { }
256
  int& mCount;
257
};
258
259
/*
260
 * Test we don't have unnecessary copies of the event data.
261
 */
262
TEST(MediaEventSource, CopyEvent1)
263
0
{
264
0
  RefPtr<TaskQueue> queue = new TaskQueue(
265
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
266
0
267
0
  MediaEventProducer<SomeEvent> source;
268
0
  int i = 0;
269
0
270
0
  auto func = [] (SomeEvent&& aEvent) {};
271
0
  struct Foo {
272
0
    void OnNotify(SomeEvent&& aEvent) {}
273
0
  } foo;
274
0
275
0
  MediaEventListener listener1 = source.Connect(queue, func);
276
0
  MediaEventListener listener2 = source.Connect(queue, &foo, &Foo::OnNotify);
277
0
278
0
  // We expect i to be 2 since SomeEvent should be copied only once when
279
0
  // passing to each listener.
280
0
  source.Notify(SomeEvent(i));
281
0
282
0
  queue->BeginShutdown();
283
0
  queue->AwaitShutdownAndIdle();
284
0
  EXPECT_EQ(i, 2);
285
0
  listener1.Disconnect();
286
0
  listener2.Disconnect();
287
0
}
288
289
TEST(MediaEventSource, CopyEvent2)
290
0
{
291
0
  RefPtr<TaskQueue> queue = new TaskQueue(
292
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
293
0
294
0
  MediaEventProducer<SomeEvent> source;
295
0
  int i = 0;
296
0
297
0
  auto func = [] () {};
298
0
  struct Foo {
299
0
    void OnNotify() {}
300
0
  } foo;
301
0
302
0
  MediaEventListener listener1 = source.Connect(queue, func);
303
0
  MediaEventListener listener2 = source.Connect(queue, &foo, &Foo::OnNotify);
304
0
305
0
  // SomeEvent won't be copied at all since the listeners take no arguments.
306
0
  source.Notify(SomeEvent(i));
307
0
308
0
  queue->BeginShutdown();
309
0
  queue->AwaitShutdownAndIdle();
310
0
  EXPECT_EQ(i, 0);
311
0
  listener1.Disconnect();
312
0
  listener2.Disconnect();
313
0
}
314
315
/*
316
 * Test move-only types.
317
 */
318
TEST(MediaEventSource, MoveOnly)
319
0
{
320
0
  RefPtr<TaskQueue> queue = new TaskQueue(
321
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
322
0
323
0
  MediaEventProducerExc<UniquePtr<int>> source;
324
0
325
0
  auto func = [] (UniquePtr<int>&& aEvent) {
326
0
    EXPECT_EQ(*aEvent, 20);
327
0
  };
328
0
  MediaEventListener listener = source.Connect(queue, func);
329
0
330
0
  // It is OK to pass an rvalue which is move-only.
331
0
  source.Notify(UniquePtr<int>(new int(20)));
332
0
  // It is an error to pass an lvalue which is move-only.
333
0
  // UniquePtr<int> event(new int(30));
334
0
  // source.Notify(event);
335
0
336
0
  queue->BeginShutdown();
337
0
  queue->AwaitShutdownAndIdle();
338
0
  listener.Disconnect();
339
0
}
340
341
struct RefCounter
342
{
343
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCounter)
344
0
  explicit RefCounter(int aVal) : mVal(aVal) { }
345
  int mVal;
346
private:
347
0
  ~RefCounter() { }
348
};
349
350
/*
351
 * Test we should copy instead of move in NonExclusive mode
352
 * for each listener must get a copy.
353
 */
354
TEST(MediaEventSource, NoMove)
355
0
{
356
0
  RefPtr<TaskQueue> queue = new TaskQueue(
357
0
    GetMediaThreadPool(MediaThreadType::PLAYBACK));
358
0
359
0
  MediaEventProducer<RefPtr<RefCounter>> source;
360
0
361
0
  auto func1 = [] (RefPtr<RefCounter>&& aEvent) {
362
0
    EXPECT_EQ(aEvent->mVal, 20);
363
0
  };
364
0
  auto func2 = [] (RefPtr<RefCounter>&& aEvent) {
365
0
    EXPECT_EQ(aEvent->mVal, 20);
366
0
  };
367
0
  MediaEventListener listener1 = source.Connect(queue, func1);
368
0
  MediaEventListener listener2 = source.Connect(queue, func2);
369
0
370
0
  // We should copy this rvalue instead of move it in NonExclusive mode.
371
0
  RefPtr<RefCounter> val = new RefCounter(20);
372
0
  source.Notify(std::move(val));
373
0
374
0
  queue->BeginShutdown();
375
0
  queue->AwaitShutdownAndIdle();
376
0
  listener1.Disconnect();
377
0
  listener2.Disconnect();
378
0
}
379
380
/*
381
 * Rvalue lambda should be moved instead of copied.
382
 */
383
TEST(MediaEventSource, MoveLambda)
384
0
{
385
0
  RefPtr<TaskQueue> queue;
386
0
  MediaEventProducer<void> source;
387
0
388
0
  int counter = 0;
389
0
  SomeEvent someEvent(counter);
390
0
391
0
  auto func = [someEvent] () { };
392
0
  // someEvent is copied when captured by the lambda.
393
0
  EXPECT_EQ(someEvent.mCount, 1);
394
0
395
0
  // someEvent should be copied for we pass |func| as an lvalue.
396
0
  MediaEventListener listener1 = source.Connect(queue, func);
397
0
  EXPECT_EQ(someEvent.mCount, 2);
398
0
399
0
  // someEvent should be moved for we pass |func| as an rvalue.
400
0
  MediaEventListener listener2 = source.Connect(queue, std::move(func));
401
0
  EXPECT_EQ(someEvent.mCount, 2);
402
0
403
0
  listener1.Disconnect();
404
0
  listener2.Disconnect();
405
0
}