Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / api / audio_modem / audio_modem_api_unittest.cc
blobf2cd614d2ad55b07d09d2425cd19036250b062c2
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <map>
6 #include <string>
7 #include <vector>
9 #include "base/callback.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/api/audio_modem/audio_modem_api.h"
14 #include "chrome/browser/extensions/extension_api_unittest.h"
15 #include "chrome/browser/extensions/extension_function_test_utils.h"
16 #include "chrome/browser/extensions/test_extension_system.h"
17 #include "components/audio_modem/public/modem.h"
18 #include "components/audio_modem/test/stub_modem.h"
19 #include "components/audio_modem/test/stub_whispernet_client.h"
20 #include "extensions/browser/api_test_utils.h"
21 #include "extensions/browser/event_router.h"
22 #include "extensions/browser/event_router_factory.h"
24 using audio_modem::AUDIBLE;
25 using audio_modem::AudioToken;
26 using audio_modem::INAUDIBLE;
27 using audio_modem::StubModem;
28 using audio_modem::StubWhispernetClient;
30 using base::BinaryValue;
31 using base::DictionaryValue;
32 using base::ListValue;
33 using base::StringValue;
34 using base::Value;
36 using content::BrowserContext;
38 namespace ext_test_utils = extension_function_test_utils;
40 namespace extensions {
42 namespace {
44 // The TestingFactoryFunction uses a BrowserContext as its context pointer.
45 // But each BrowserContext is still associated with a unit test.
46 // So we store the StubModem created in each test.
47 std::map<BrowserContext*, StubModem*> g_modems;
49 // Create a test AudioModemAPI and store the modem it uses.
50 scoped_ptr<KeyedService> ApiFactoryFunction(BrowserContext* context) {
51 StubModem* modem = new StubModem;
52 g_modems[context] = modem;
53 return make_scoped_ptr(new AudioModemAPI(
54 context,
55 make_scoped_ptr<audio_modem::WhispernetClient>(new StubWhispernetClient),
56 make_scoped_ptr<audio_modem::Modem>(modem)));
59 DictionaryValue* CreateParams(const std::string& audio_band) {
60 DictionaryValue* params = new DictionaryValue;
61 params->SetInteger("timeoutMillis", 60000);
62 params->SetString("band", audio_band);
63 params->SetInteger("encoding.tokenLength", 4);
64 return params;
67 BinaryValue* CreateToken(const std::string& token) {
68 return BinaryValue::CreateWithCopiedBuffer(token.c_str(), token.size());
71 scoped_ptr<ListValue> CreateList(Value* single_elt) {
72 scoped_ptr<ListValue> list(new ListValue);
73 list->Append(single_elt);
74 return list.Pass();
77 scoped_ptr<ListValue> CreateList(Value* elt1, Value* elt2) {
78 scoped_ptr<ListValue> list(new ListValue);
79 list->Append(elt1);
80 list->Append(elt2);
81 return list.Pass();
84 DictionaryValue* CreateReceivedToken(const std::string& token,
85 const std::string& audio_band) {
86 DictionaryValue* out = new DictionaryValue;
87 out->Set("token", CreateToken(token));
88 out->SetString("band", audio_band);
89 return out;
92 bool ReceivedSingleToken(const Event* event,
93 const DictionaryValue* expected_token) {
94 ListValue* received_tokens;
95 event->event_args->GetList(0, &received_tokens);
96 if (received_tokens->GetSize() != 1)
97 return false;
99 DictionaryValue* received_token;
100 received_tokens->GetDictionary(0, &received_token);
101 return received_token->Equals(expected_token);
104 // TODO(ckehoe): Put this in //extensions/test.
105 // Then replace the other EventRouter mocks.
106 class StubEventRouter : public EventRouter {
107 public:
108 // Callback to receive events. First argument is
109 // the extension id to receive the event.
110 using EventCallback = base::Callback<void(const std::string&,
111 scoped_ptr<Event>)>;
113 explicit StubEventRouter(BrowserContext* context)
114 : EventRouter(context, nullptr) {}
116 void DispatchEventToExtension(const std::string& extension_id,
117 scoped_ptr<Event> event) override {
118 event_callback_.Run(extension_id, event.Pass());
121 void SetEventCallBack(EventCallback event_callback) {
122 event_callback_ = event_callback;
125 void ClearEventCallback() {
126 event_callback_.Reset();
129 private:
130 EventCallback event_callback_;
133 // StubEventRouter factory function
134 scoped_ptr<KeyedService> StubEventRouterFactoryFunction(
135 content::BrowserContext* context) {
136 return make_scoped_ptr(new StubEventRouter(context));
139 } // namespace
141 class AudioModemApiUnittest : public ExtensionApiUnittest {
142 public:
143 AudioModemApiUnittest() {}
144 ~AudioModemApiUnittest() override {
145 for (const auto& events : events_by_extension_id_) {
146 for (const Event* event : events.second)
147 delete event;
151 protected:
152 template<typename Function>
153 const std::string RunFunction(scoped_ptr<ListValue> args,
154 const Extension* extension) {
155 scoped_refptr<UIThreadExtensionFunction> function(new Function);
156 function->set_extension(extension);
157 function->set_browser_context(profile());
158 function->set_has_callback(true);
159 ext_test_utils::RunFunction(
160 function.get(), args.Pass(), browser(), ext_test_utils::NONE);
162 std::string result_status;
163 CHECK(function->GetResultList()->GetString(0, &result_status));
164 return result_status;
167 template<typename Function>
168 const std::string RunFunction(scoped_ptr<ListValue> args) {
169 return RunFunction<Function>(args.Pass(), GetExtension(std::string()));
172 StubModem* GetModem() const {
173 return g_modems[profile()];
176 const Extension* GetExtension(const std::string& name) {
177 if (!extensions_by_name_[name].get()) {
178 scoped_ptr<DictionaryValue> extension_definition(new DictionaryValue);
179 extension_definition->SetString("name", name);
180 extension_definition->SetString("version", "1.0");
181 extensions_by_name_[name] = api_test_utils::CreateExtension(
182 Manifest::INTERNAL, extension_definition.get(), name);
183 DVLOG(2) << "Created extension " << extensions_by_name_[name]->id();
185 return extensions_by_name_[name].get();
188 const std::vector<const Event*>&
189 GetEventsForExtension(const std::string& name) {
190 const Extension* extension = extensions_by_name_[name].get();
191 DCHECK(extension);
192 return events_by_extension_id_[extension->id()];
195 const std::vector<const Event*>& GetEvents() {
196 return GetEventsForExtension(std::string());
199 private:
200 void SetUp() override {
201 ExtensionApiUnittest::SetUp();
202 AudioModemAPI::GetFactoryInstance()->SetTestingFactory(
203 profile(), &ApiFactoryFunction);
205 StubEventRouter* stub_event_router = static_cast<StubEventRouter*>(
206 extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
207 profile(), &StubEventRouterFactoryFunction));
208 stub_event_router->SetEventCallBack(base::Bind(
209 &AudioModemApiUnittest::CaptureEvent, base::Unretained(this)));
212 void CaptureEvent(const std::string& extension_id,
213 scoped_ptr<Event> event) {
214 // Since scoped_ptr (and ScopedVector) do not work inside STL containers,
215 // we must manage this memory manually. It is cleaned up by the destructor.
216 events_by_extension_id_[extension_id].push_back(event.release());
219 std::map<std::string, scoped_refptr<Extension>> extensions_by_name_;
221 // We own all of these pointers.
222 // Do not remove them from the map without calling delete.
223 std::map<std::string, std::vector<const Event*>> events_by_extension_id_;
226 TEST_F(AudioModemApiUnittest, TransmitBasic) {
227 // Start transmitting inaudibly.
228 EXPECT_EQ("success", RunFunction<AudioModemTransmitFunction>(
229 CreateList(CreateParams("inaudible"), CreateToken("1234"))));
230 EXPECT_TRUE(GetModem()->IsPlaying(INAUDIBLE));
232 // Can't cancel audible transmit - we haven't started it yet.
233 EXPECT_EQ("invalidRequest", RunFunction<AudioModemStopTransmitFunction>(
234 CreateList(new StringValue("audible"))));
236 // Start transmitting audibly.
237 EXPECT_EQ("success", RunFunction<AudioModemTransmitFunction>(
238 CreateList(CreateParams("audible"), CreateToken("ABCD"))));
239 EXPECT_TRUE(GetModem()->IsPlaying(AUDIBLE));
241 // Stop audible transmit. We're still transmitting inaudibly.
242 EXPECT_EQ("success", RunFunction<AudioModemStopTransmitFunction>(
243 CreateList(new StringValue("audible"))));
244 EXPECT_FALSE(GetModem()->IsPlaying(AUDIBLE));
245 EXPECT_TRUE(GetModem()->IsPlaying(INAUDIBLE));
247 // Stop inaudible transmit.
248 EXPECT_EQ("success", RunFunction<AudioModemStopTransmitFunction>(
249 CreateList(new StringValue("inaudible"))));
250 EXPECT_FALSE(GetModem()->IsPlaying(INAUDIBLE));
253 TEST_F(AudioModemApiUnittest, ReceiveBasic) {
254 // Start listening for audible tokens.
255 EXPECT_EQ("success", RunFunction<AudioModemReceiveFunction>(
256 CreateList(CreateParams("audible"))));
257 EXPECT_TRUE(GetModem()->IsRecording(AUDIBLE));
259 // Can't cancel inaudible receive - we haven't started it yet.
260 EXPECT_EQ("invalidRequest", RunFunction<AudioModemStopReceiveFunction>(
261 CreateList(new StringValue("inaudible"))));
263 // Send some audible tokens.
264 std::vector<AudioToken> tokens;
265 tokens.push_back(AudioToken("1234", true));
266 tokens.push_back(AudioToken("ABCD", true));
267 tokens.push_back(AudioToken("abcd", false));
268 GetModem()->DeliverTokens(tokens);
270 // Check the tokens received.
271 EXPECT_EQ(1u, GetEvents().size());
272 scoped_ptr<ListValue> expected_tokens(new ListValue);
273 expected_tokens->Append(CreateReceivedToken("1234", "audible"));
274 expected_tokens->Append(CreateReceivedToken("ABCD", "audible"));
275 ListValue* received_tokens;
276 GetEvents()[0]->event_args->GetList(0, &received_tokens);
277 EXPECT_TRUE(received_tokens->Equals(expected_tokens.get()));
279 // Start listening for inaudible tokens.
280 EXPECT_EQ("success", RunFunction<AudioModemReceiveFunction>(
281 CreateList(CreateParams("inaudible"))));
282 EXPECT_TRUE(GetModem()->IsRecording(INAUDIBLE));
284 // Send some more tokens.
285 tokens.push_back(AudioToken("5678", false));
286 GetModem()->DeliverTokens(tokens);
288 // Check the tokens received.
289 EXPECT_EQ(2u, GetEvents().size());
290 expected_tokens->Append(CreateReceivedToken("abcd", "inaudible"));
291 expected_tokens->Append(CreateReceivedToken("5678", "inaudible"));
292 GetEvents()[1]->event_args->GetList(0, &received_tokens);
293 EXPECT_TRUE(received_tokens->Equals(expected_tokens.get()));
295 // Stop audible receive. We're still receiving inaudible.
296 EXPECT_EQ("success", RunFunction<AudioModemStopReceiveFunction>(
297 CreateList(new StringValue("audible"))));
298 EXPECT_FALSE(GetModem()->IsRecording(AUDIBLE));
299 EXPECT_TRUE(GetModem()->IsRecording(INAUDIBLE));
301 // Stop inaudible receive.
302 EXPECT_EQ("success", RunFunction<AudioModemStopReceiveFunction>(
303 CreateList(new StringValue("inaudible"))));
304 EXPECT_FALSE(GetModem()->IsRecording(INAUDIBLE));
307 TEST_F(AudioModemApiUnittest, TransmitMultiple) {
308 // Start transmit.
309 EXPECT_EQ("success", RunFunction<AudioModemTransmitFunction>(
310 CreateList(CreateParams("audible"), CreateToken("1234")),
311 GetExtension("ext1")));
312 EXPECT_TRUE(GetModem()->IsPlaying(AUDIBLE));
314 // Another extension can't interfere with the first one.
315 EXPECT_EQ("inUse", RunFunction<AudioModemTransmitFunction>(
316 CreateList(CreateParams("audible"), CreateToken("ABCD")),
317 GetExtension("ext2")));
318 EXPECT_EQ("invalidRequest", RunFunction<AudioModemStopTransmitFunction>(
319 CreateList(new StringValue("audible")), GetExtension("ext2")));
320 EXPECT_TRUE(GetModem()->IsPlaying(AUDIBLE));
322 // The other extension can use the other audio band, however.
323 EXPECT_EQ("success", RunFunction<AudioModemTransmitFunction>(
324 CreateList(CreateParams("inaudible"), CreateToken("ABCD")),
325 GetExtension("ext2")));
326 EXPECT_TRUE(GetModem()->IsPlaying(INAUDIBLE));
328 // The first extension can change its token.
329 // But the other band is still in use.
330 EXPECT_EQ("success", RunFunction<AudioModemTransmitFunction>(
331 CreateList(CreateParams("audible"), CreateToken("abcd")),
332 GetExtension("ext1")));
333 EXPECT_EQ("inUse", RunFunction<AudioModemTransmitFunction>(
334 CreateList(CreateParams("inaudible"), CreateToken("1234")),
335 GetExtension("ext1")));
337 // Stop transmission.
338 EXPECT_EQ("success", RunFunction<AudioModemStopTransmitFunction>(
339 CreateList(new StringValue("audible")), GetExtension("ext1")));
340 EXPECT_FALSE(GetModem()->IsPlaying(AUDIBLE));
341 EXPECT_EQ("success", RunFunction<AudioModemStopTransmitFunction>(
342 CreateList(new StringValue("inaudible")), GetExtension("ext2")));
343 EXPECT_FALSE(GetModem()->IsPlaying(INAUDIBLE));
346 TEST_F(AudioModemApiUnittest, ReceiveMultiple) {
347 // Start receive. Multiple extensions can receive on the same band.
348 EXPECT_EQ("success", RunFunction<AudioModemReceiveFunction>(
349 CreateList(CreateParams("inaudible")), GetExtension("ext1")));
350 EXPECT_TRUE(GetModem()->IsRecording(INAUDIBLE));
351 EXPECT_EQ("success", RunFunction<AudioModemReceiveFunction>(
352 CreateList(CreateParams("inaudible")), GetExtension("ext2")));
354 // Receive a token.
355 GetModem()->DeliverTokens(std::vector<AudioToken>(
356 1, AudioToken("abcd", false)));
357 EXPECT_EQ(1u, GetEventsForExtension("ext1").size());
358 EXPECT_EQ(1u, GetEventsForExtension("ext2").size());
360 // Check the token received.
361 scoped_ptr<DictionaryValue> expected_token(
362 CreateReceivedToken("abcd", "inaudible"));
363 EXPECT_TRUE(ReceivedSingleToken(
364 GetEventsForExtension("ext1")[0], expected_token.get()));
365 EXPECT_TRUE(ReceivedSingleToken(
366 GetEventsForExtension("ext2")[0], expected_token.get()));
368 // If one extension stops, the modem is still receiving for the other.
369 EXPECT_EQ("success", RunFunction<AudioModemStopReceiveFunction>(
370 CreateList(new StringValue("inaudible")), GetExtension("ext1")));
371 EXPECT_TRUE(GetModem()->IsRecording(INAUDIBLE));
373 // Receive another token. Should only go to ext2.
374 GetModem()->DeliverTokens(std::vector<AudioToken>(
375 1, AudioToken("1234", false)));
376 EXPECT_EQ(1u, GetEventsForExtension("ext1").size());
377 EXPECT_EQ(2u, GetEventsForExtension("ext2").size());
378 expected_token.reset(CreateReceivedToken("1234", "inaudible"));
379 EXPECT_TRUE(ReceivedSingleToken(
380 GetEventsForExtension("ext2")[1], expected_token.get()));
382 EXPECT_EQ("success", RunFunction<AudioModemStopReceiveFunction>(
383 CreateList(new StringValue("inaudible")), GetExtension("ext2")));
384 EXPECT_FALSE(GetModem()->IsRecording(INAUDIBLE));
387 } // namespace extensions