blob: b0003847cb91547ba6bced055a50f0b13720eabb [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#ifndef RTC_BASE_TESTUTILS_H_
12#define RTC_BASE_TESTUTILS_H_
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020014// Utilities for testing rtc infrastructure in unittests
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000015
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020016#include <algorithm>
17#include <map>
18#include <memory>
19#include <vector>
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/asyncsocket.h"
21#include "rtc_base/checks.h"
22#include "rtc_base/gunit.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "rtc_base/stream.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/stringutils.h"
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020025
26namespace webrtc {
27namespace testing {
28
29using namespace rtc;
30
31///////////////////////////////////////////////////////////////////////////////
32// StreamSink - Monitor asynchronously signalled events from StreamInterface
33// or AsyncSocket (which should probably be a StreamInterface.
34///////////////////////////////////////////////////////////////////////////////
35
36// Note: Any event that is an error is treaded as SSE_ERROR instead of that
37// event.
38
39enum StreamSinkEvent {
40 SSE_OPEN = SE_OPEN,
41 SSE_READ = SE_READ,
42 SSE_WRITE = SE_WRITE,
43 SSE_CLOSE = SE_CLOSE,
44 SSE_ERROR = 16
45};
46
47class StreamSink : public sigslot::has_slots<> {
48 public:
Steve Anton9de3aac2017-10-24 10:08:26 -070049 StreamSink();
50 ~StreamSink() override;
51
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020052 void Monitor(StreamInterface* stream) {
53 stream->SignalEvent.connect(this, &StreamSink::OnEvent);
54 events_.erase(stream);
55 }
56 void Unmonitor(StreamInterface* stream) {
57 stream->SignalEvent.disconnect(this);
58 // In case you forgot to unmonitor a previous object with this address
59 events_.erase(stream);
60 }
61 bool Check(StreamInterface* stream, StreamSinkEvent event, bool reset = true) {
62 return DoCheck(stream, event, reset);
63 }
64 int Events(StreamInterface* stream, bool reset = true) {
65 return DoEvents(stream, reset);
66 }
67
68 void Monitor(AsyncSocket* socket) {
69 socket->SignalConnectEvent.connect(this, &StreamSink::OnConnectEvent);
70 socket->SignalReadEvent.connect(this, &StreamSink::OnReadEvent);
71 socket->SignalWriteEvent.connect(this, &StreamSink::OnWriteEvent);
72 socket->SignalCloseEvent.connect(this, &StreamSink::OnCloseEvent);
73 // In case you forgot to unmonitor a previous object with this address
74 events_.erase(socket);
75 }
76 void Unmonitor(AsyncSocket* socket) {
77 socket->SignalConnectEvent.disconnect(this);
78 socket->SignalReadEvent.disconnect(this);
79 socket->SignalWriteEvent.disconnect(this);
80 socket->SignalCloseEvent.disconnect(this);
81 events_.erase(socket);
82 }
83 bool Check(AsyncSocket* socket, StreamSinkEvent event, bool reset = true) {
84 return DoCheck(socket, event, reset);
85 }
86 int Events(AsyncSocket* socket, bool reset = true) {
87 return DoEvents(socket, reset);
88 }
89
90 private:
91 typedef std::map<void*,int> EventMap;
92
93 void OnEvent(StreamInterface* stream, int events, int error) {
94 if (error) {
95 events = SSE_ERROR;
96 }
97 AddEvents(stream, events);
98 }
99 void OnConnectEvent(AsyncSocket* socket) {
100 AddEvents(socket, SSE_OPEN);
101 }
102 void OnReadEvent(AsyncSocket* socket) {
103 AddEvents(socket, SSE_READ);
104 }
105 void OnWriteEvent(AsyncSocket* socket) {
106 AddEvents(socket, SSE_WRITE);
107 }
108 void OnCloseEvent(AsyncSocket* socket, int error) {
109 AddEvents(socket, (0 == error) ? SSE_CLOSE : SSE_ERROR);
110 }
111
112 void AddEvents(void* obj, int events) {
113 EventMap::iterator it = events_.find(obj);
114 if (events_.end() == it) {
115 events_.insert(EventMap::value_type(obj, events));
116 } else {
117 it->second |= events;
118 }
119 }
120 bool DoCheck(void* obj, StreamSinkEvent event, bool reset) {
121 EventMap::iterator it = events_.find(obj);
122 if ((events_.end() == it) || (0 == (it->second & event))) {
123 return false;
124 }
125 if (reset) {
126 it->second &= ~event;
127 }
128 return true;
129 }
130 int DoEvents(void* obj, bool reset) {
131 EventMap::iterator it = events_.find(obj);
132 if (events_.end() == it)
133 return 0;
134 int events = it->second;
135 if (reset) {
136 it->second = 0;
137 }
138 return events;
139 }
140
141 EventMap events_;
142};
143
144///////////////////////////////////////////////////////////////////////////////
145// StreamSource - Implements stream interface and simulates asynchronous
146// events on the stream, without a network. Also buffers written data.
147///////////////////////////////////////////////////////////////////////////////
148
149class StreamSource : public StreamInterface {
150public:
Steve Anton9de3aac2017-10-24 10:08:26 -0700151 StreamSource();
152 ~StreamSource() override;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200153
Steve Anton9de3aac2017-10-24 10:08:26 -0700154 void Clear() {
155 readable_data_.clear();
156 written_data_.clear();
157 state_ = SS_CLOSED;
158 read_block_ = 0;
159 write_block_ = SIZE_UNKNOWN;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200160 }
161 void QueueString(const char* data) {
162 QueueData(data, strlen(data));
163 }
Niels Möller00f934a2017-12-14 13:30:46 +0100164#if defined(__GNUC__)
165 // Note: Implicit |this| argument counts as the first argument.
166 __attribute__((__format__(__printf__, 2, 3)))
167#endif
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200168 void QueueStringF(const char* format, ...) {
169 va_list args;
170 va_start(args, format);
171 char buffer[1024];
172 size_t len = vsprintfn(buffer, sizeof(buffer), format, args);
173 RTC_CHECK(len < sizeof(buffer) - 1);
174 va_end(args);
175 QueueData(buffer, len);
176 }
177 void QueueData(const char* data, size_t len) {
178 readable_data_.insert(readable_data_.end(), data, data + len);
179 if ((SS_OPEN == state_) && (readable_data_.size() == len)) {
180 SignalEvent(this, SE_READ, 0);
181 }
182 }
183 std::string ReadData() {
184 std::string data;
185 // avoid accessing written_data_[0] if it is undefined
186 if (written_data_.size() > 0) {
187 data.insert(0, &written_data_[0], written_data_.size());
188 }
189 written_data_.clear();
190 return data;
191 }
192 void SetState(StreamState state) {
193 int events = 0;
194 if ((SS_OPENING == state_) && (SS_OPEN == state)) {
195 events |= SE_OPEN;
196 if (!readable_data_.empty()) {
197 events |= SE_READ;
198 }
199 } else if ((SS_CLOSED != state_) && (SS_CLOSED == state)) {
200 events |= SE_CLOSE;
201 }
202 state_ = state;
203 if (events) {
204 SignalEvent(this, events, 0);
205 }
206 }
207 // Will cause Read to block when there are pos bytes in the read queue.
208 void SetReadBlock(size_t pos) { read_block_ = pos; }
209 // Will cause Write to block when there are pos bytes in the write queue.
210 void SetWriteBlock(size_t pos) { write_block_ = pos; }
211
Steve Anton9de3aac2017-10-24 10:08:26 -0700212 StreamState GetState() const override;
213 StreamResult Read(void* buffer,
214 size_t buffer_len,
215 size_t* read,
216 int* error) override;
217 StreamResult Write(const void* data,
218 size_t data_len,
219 size_t* written,
220 int* error) override;
221 void Close() override;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200222
Steve Anton9de3aac2017-10-24 10:08:26 -0700223 private:
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200224 typedef std::vector<char> Buffer;
225 Buffer readable_data_, written_data_;
226 StreamState state_;
227 size_t read_block_, write_block_;
228};
229
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200230} // namespace testing
231} // namespace webrtc
232
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200233#endif // RTC_BASE_TESTUTILS_H_