[Session restore] Rename group name Enabled to Restore.
[chromium-blink-merge.git] / content / browser / speech / google_streaming_remote_engine_unittest.cc
blobc3d7ce5c4e1be68ae49b3a3c6150b8b486a5a15b
1 // Copyright (c) 2012 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 <queue>
7 #include "base/big_endian.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/sys_byteorder.h"
13 #include "content/browser/speech/audio_buffer.h"
14 #include "content/browser/speech/google_streaming_remote_engine.h"
15 #include "content/browser/speech/proto/google_streaming_api.pb.h"
16 #include "content/public/common/speech_recognition_error.h"
17 #include "content/public/common/speech_recognition_result.h"
18 #include "net/url_request/test_url_fetcher_factory.h"
19 #include "net/url_request/url_request_context_getter.h"
20 #include "net/url_request/url_request_status.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using base::HostToNet32;
24 using base::checked_cast;
25 using net::URLRequestStatus;
26 using net::TestURLFetcher;
27 using net::TestURLFetcherFactory;
29 namespace content {
31 // Frame types for framed POST data.
32 static const uint32_t kFrameTypePreamble = 0;
33 static const uint32_t kFrameTypeRecognitionAudio = 1;
35 // Note: the terms upstream and downstream are from the point-of-view of the
36 // client (engine_under_test_).
38 class GoogleStreamingRemoteEngineTest : public SpeechRecognitionEngineDelegate,
39 public testing::Test {
40 public:
41 GoogleStreamingRemoteEngineTest()
42 : last_number_of_upstream_chunks_seen_(0U),
43 error_(SPEECH_RECOGNITION_ERROR_NONE) { }
45 // Creates a speech recognition request and invokes its URL fetcher delegate
46 // with the given test data.
47 void CreateAndTestRequest(bool success, const std::string& http_response);
49 // SpeechRecognitionRequestDelegate methods.
50 void OnSpeechRecognitionEngineResults(
51 const SpeechRecognitionResults& results) override {
52 results_.push(results);
54 void OnSpeechRecognitionEngineError(
55 const SpeechRecognitionError& error) override {
56 error_ = error.code;
59 // testing::Test methods.
60 void SetUp() override;
61 void TearDown() override;
63 protected:
64 enum DownstreamError {
65 DOWNSTREAM_ERROR_NONE,
66 DOWNSTREAM_ERROR_HTTP500,
67 DOWNSTREAM_ERROR_NETWORK,
68 DOWNSTREAM_ERROR_WEBSERVICE_NO_MATCH
70 static bool ResultsAreEqual(const SpeechRecognitionResults& a,
71 const SpeechRecognitionResults& b);
72 static std::string SerializeProtobufResponse(
73 const proto::SpeechRecognitionEvent& msg);
75 TestURLFetcher* GetUpstreamFetcher();
76 TestURLFetcher* GetDownstreamFetcher();
77 void StartMockRecognition();
78 void EndMockRecognition();
79 void InjectDummyAudioChunk();
80 size_t UpstreamChunksUploadedFromLastCall();
81 std::string LastUpstreamChunkUploaded();
82 void ProvideMockProtoResultDownstream(
83 const proto::SpeechRecognitionEvent& result);
84 void ProvideMockResultDownstream(const SpeechRecognitionResult& result);
85 void ExpectResultsReceived(const SpeechRecognitionResults& result);
86 void ExpectFramedChunk(const std::string& chunk, uint32_t type);
87 void CloseMockDownstream(DownstreamError error);
89 scoped_ptr<GoogleStreamingRemoteEngine> engine_under_test_;
90 TestURLFetcherFactory url_fetcher_factory_;
91 size_t last_number_of_upstream_chunks_seen_;
92 base::MessageLoop message_loop_;
93 std::string response_buffer_;
94 SpeechRecognitionErrorCode error_;
95 std::queue<SpeechRecognitionResults> results_;
98 TEST_F(GoogleStreamingRemoteEngineTest, SingleDefinitiveResult) {
99 StartMockRecognition();
100 ASSERT_TRUE(GetUpstreamFetcher());
101 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall());
103 // Inject some dummy audio chunks and check a corresponding chunked upload
104 // is performed every time on the server.
105 for (int i = 0; i < 3; ++i) {
106 InjectDummyAudioChunk();
107 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
110 // Ensure that a final (empty) audio chunk is uploaded on chunks end.
111 engine_under_test_->AudioChunksEnded();
112 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
113 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
115 // Simulate a protobuf message streamed from the server containing a single
116 // result with two hypotheses.
117 SpeechRecognitionResults results;
118 results.push_back(SpeechRecognitionResult());
119 SpeechRecognitionResult& result = results.back();
120 result.is_provisional = false;
121 result.hypotheses.push_back(
122 SpeechRecognitionHypothesis(base::UTF8ToUTF16("hypothesis 1"), 0.1F));
123 result.hypotheses.push_back(
124 SpeechRecognitionHypothesis(base::UTF8ToUTF16("hypothesis 2"), 0.2F));
126 ProvideMockResultDownstream(result);
127 ExpectResultsReceived(results);
128 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
130 // Ensure everything is closed cleanly after the downstream is closed.
131 CloseMockDownstream(DOWNSTREAM_ERROR_NONE);
132 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
133 EndMockRecognition();
134 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_);
135 ASSERT_EQ(0U, results_.size());
138 TEST_F(GoogleStreamingRemoteEngineTest, SeveralStreamingResults) {
139 StartMockRecognition();
140 ASSERT_TRUE(GetUpstreamFetcher());
141 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall());
143 for (int i = 0; i < 4; ++i) {
144 InjectDummyAudioChunk();
145 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
147 SpeechRecognitionResults results;
148 results.push_back(SpeechRecognitionResult());
149 SpeechRecognitionResult& result = results.back();
150 result.is_provisional = (i % 2 == 0); // Alternate result types.
151 float confidence = result.is_provisional ? 0.0F : (i * 0.1F);
152 result.hypotheses.push_back(SpeechRecognitionHypothesis(
153 base::UTF8ToUTF16("hypothesis"), confidence));
155 ProvideMockResultDownstream(result);
156 ExpectResultsReceived(results);
157 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
160 // Ensure that a final (empty) audio chunk is uploaded on chunks end.
161 engine_under_test_->AudioChunksEnded();
162 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
163 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
165 // Simulate a final definitive result.
166 SpeechRecognitionResults results;
167 results.push_back(SpeechRecognitionResult());
168 SpeechRecognitionResult& result = results.back();
169 result.is_provisional = false;
170 result.hypotheses.push_back(
171 SpeechRecognitionHypothesis(base::UTF8ToUTF16("The final result"), 1.0F));
172 ProvideMockResultDownstream(result);
173 ExpectResultsReceived(results);
174 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
176 // Ensure everything is closed cleanly after the downstream is closed.
177 CloseMockDownstream(DOWNSTREAM_ERROR_NONE);
178 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
179 EndMockRecognition();
180 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_);
181 ASSERT_EQ(0U, results_.size());
184 TEST_F(GoogleStreamingRemoteEngineTest, NoFinalResultAfterAudioChunksEnded) {
185 StartMockRecognition();
186 ASSERT_TRUE(GetUpstreamFetcher());
187 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall());
189 // Simulate one pushed audio chunk.
190 InjectDummyAudioChunk();
191 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
193 // Simulate the corresponding definitive result.
194 SpeechRecognitionResults results;
195 results.push_back(SpeechRecognitionResult());
196 SpeechRecognitionResult& result = results.back();
197 result.hypotheses.push_back(
198 SpeechRecognitionHypothesis(base::UTF8ToUTF16("hypothesis"), 1.0F));
199 ProvideMockResultDownstream(result);
200 ExpectResultsReceived(results);
201 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
203 // Simulate a silent downstream closure after |AudioChunksEnded|.
204 engine_under_test_->AudioChunksEnded();
205 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
206 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
207 CloseMockDownstream(DOWNSTREAM_ERROR_NONE);
209 // Expect an empty result, aimed at notifying recognition ended with no
210 // actual results nor errors.
211 SpeechRecognitionResults empty_results;
212 ExpectResultsReceived(empty_results);
214 // Ensure everything is closed cleanly after the downstream is closed.
215 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
216 EndMockRecognition();
217 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_);
218 ASSERT_EQ(0U, results_.size());
221 TEST_F(GoogleStreamingRemoteEngineTest, NoMatchError) {
222 StartMockRecognition();
223 ASSERT_TRUE(GetUpstreamFetcher());
224 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall());
226 for (int i = 0; i < 3; ++i)
227 InjectDummyAudioChunk();
228 engine_under_test_->AudioChunksEnded();
229 ASSERT_EQ(4U, UpstreamChunksUploadedFromLastCall());
230 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
232 // Simulate only a provisional result.
233 SpeechRecognitionResults results;
234 results.push_back(SpeechRecognitionResult());
235 SpeechRecognitionResult& result = results.back();
236 result.is_provisional = true;
237 result.hypotheses.push_back(
238 SpeechRecognitionHypothesis(base::UTF8ToUTF16("The final result"), 0.0F));
239 ProvideMockResultDownstream(result);
240 ExpectResultsReceived(results);
241 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
243 CloseMockDownstream(DOWNSTREAM_ERROR_WEBSERVICE_NO_MATCH);
245 // Expect an empty result.
246 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
247 EndMockRecognition();
248 SpeechRecognitionResults empty_result;
249 ExpectResultsReceived(empty_result);
252 TEST_F(GoogleStreamingRemoteEngineTest, HTTPError) {
253 StartMockRecognition();
254 ASSERT_TRUE(GetUpstreamFetcher());
255 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall());
257 InjectDummyAudioChunk();
258 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
260 // Close the downstream with a HTTP 500 error.
261 CloseMockDownstream(DOWNSTREAM_ERROR_HTTP500);
263 // Expect a SPEECH_RECOGNITION_ERROR_NETWORK error to be raised.
264 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
265 EndMockRecognition();
266 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NETWORK, error_);
267 ASSERT_EQ(0U, results_.size());
270 TEST_F(GoogleStreamingRemoteEngineTest, NetworkError) {
271 StartMockRecognition();
272 ASSERT_TRUE(GetUpstreamFetcher());
273 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall());
275 InjectDummyAudioChunk();
276 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
278 // Close the downstream fetcher simulating a network failure.
279 CloseMockDownstream(DOWNSTREAM_ERROR_NETWORK);
281 // Expect a SPEECH_RECOGNITION_ERROR_NETWORK error to be raised.
282 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
283 EndMockRecognition();
284 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NETWORK, error_);
285 ASSERT_EQ(0U, results_.size());
288 TEST_F(GoogleStreamingRemoteEngineTest, Stability) {
289 StartMockRecognition();
290 ASSERT_TRUE(GetUpstreamFetcher());
291 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall());
293 // Upload a dummy audio chunk.
294 InjectDummyAudioChunk();
295 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
296 engine_under_test_->AudioChunksEnded();
298 // Simulate a protobuf message with an intermediate result without confidence,
299 // but with stability.
300 proto::SpeechRecognitionEvent proto_event;
301 proto_event.set_status(proto::SpeechRecognitionEvent::STATUS_SUCCESS);
302 proto::SpeechRecognitionResult* proto_result = proto_event.add_result();
303 proto_result->set_stability(0.5);
304 proto::SpeechRecognitionAlternative *proto_alternative =
305 proto_result->add_alternative();
306 proto_alternative->set_transcript("foo");
307 ProvideMockProtoResultDownstream(proto_event);
309 // Set up expectations.
310 SpeechRecognitionResults results;
311 results.push_back(SpeechRecognitionResult());
312 SpeechRecognitionResult& result = results.back();
313 result.is_provisional = true;
314 result.hypotheses.push_back(
315 SpeechRecognitionHypothesis(base::UTF8ToUTF16("foo"), 0.5));
317 // Check that the protobuf generated the expected result.
318 ExpectResultsReceived(results);
320 // Since it was a provisional result, recognition is still pending.
321 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
323 // Shut down.
324 CloseMockDownstream(DOWNSTREAM_ERROR_NONE);
325 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
326 EndMockRecognition();
328 // Since there was no final result, we get an empty "no match" result.
329 SpeechRecognitionResults empty_result;
330 ExpectResultsReceived(empty_result);
331 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_);
332 ASSERT_EQ(0U, results_.size());
335 TEST_F(GoogleStreamingRemoteEngineTest, SendPreamble) {
336 const size_t kPreambleLength = 100;
337 scoped_refptr<SpeechRecognitionSessionPreamble> preamble =
338 new SpeechRecognitionSessionPreamble();
339 preamble->sample_rate = 16000;
340 preamble->sample_depth = 2;
341 preamble->sample_data.assign(kPreambleLength, 0);
342 SpeechRecognitionEngine::Config config;
343 config.auth_token = "foo";
344 config.auth_scope = "bar";
345 config.preamble = preamble;
346 engine_under_test_->SetConfig(config);
348 StartMockRecognition();
349 ASSERT_TRUE(GetUpstreamFetcher());
350 // First chunk uploaded should be the preamble.
351 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
352 std::string chunk = LastUpstreamChunkUploaded();
353 ExpectFramedChunk(chunk, kFrameTypePreamble);
355 for (int i = 0; i < 3; ++i) {
356 InjectDummyAudioChunk();
357 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall());
358 chunk = LastUpstreamChunkUploaded();
359 ExpectFramedChunk(chunk, kFrameTypeRecognitionAudio);
361 engine_under_test_->AudioChunksEnded();
362 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
364 // Simulate a protobuf message streamed from the server containing a single
365 // result with one hypotheses.
366 SpeechRecognitionResults results;
367 results.push_back(SpeechRecognitionResult());
368 SpeechRecognitionResult& result = results.back();
369 result.is_provisional = false;
370 result.hypotheses.push_back(
371 SpeechRecognitionHypothesis(base::UTF8ToUTF16("hypothesis 1"), 0.1F));
373 ProvideMockResultDownstream(result);
374 ExpectResultsReceived(results);
375 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
377 // Ensure everything is closed cleanly after the downstream is closed.
378 CloseMockDownstream(DOWNSTREAM_ERROR_NONE);
379 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
380 EndMockRecognition();
381 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_);
382 ASSERT_EQ(0U, results_.size());
385 void GoogleStreamingRemoteEngineTest::SetUp() {
386 engine_under_test_.reset(
387 new GoogleStreamingRemoteEngine(NULL /*URLRequestContextGetter*/));
388 engine_under_test_->set_delegate(this);
391 void GoogleStreamingRemoteEngineTest::TearDown() {
392 engine_under_test_.reset();
395 TestURLFetcher* GoogleStreamingRemoteEngineTest::GetUpstreamFetcher() {
396 return url_fetcher_factory_.GetFetcherByID(
397 GoogleStreamingRemoteEngine::kUpstreamUrlFetcherIdForTesting);
400 TestURLFetcher* GoogleStreamingRemoteEngineTest::GetDownstreamFetcher() {
401 return url_fetcher_factory_.GetFetcherByID(
402 GoogleStreamingRemoteEngine::kDownstreamUrlFetcherIdForTesting);
405 // Starts recognition on the engine, ensuring that both stream fetchers are
406 // created.
407 void GoogleStreamingRemoteEngineTest::StartMockRecognition() {
408 DCHECK(engine_under_test_.get());
410 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
412 engine_under_test_->StartRecognition();
413 ASSERT_TRUE(engine_under_test_->IsRecognitionPending());
415 TestURLFetcher* upstream_fetcher = GetUpstreamFetcher();
416 ASSERT_TRUE(upstream_fetcher);
417 upstream_fetcher->set_url(upstream_fetcher->GetOriginalURL());
419 TestURLFetcher* downstream_fetcher = GetDownstreamFetcher();
420 ASSERT_TRUE(downstream_fetcher);
421 downstream_fetcher->set_url(downstream_fetcher->GetOriginalURL());
424 void GoogleStreamingRemoteEngineTest::EndMockRecognition() {
425 DCHECK(engine_under_test_.get());
426 engine_under_test_->EndRecognition();
427 ASSERT_FALSE(engine_under_test_->IsRecognitionPending());
429 // TODO(primiano): In order to be very pedantic we should check that both the
430 // upstream and downstream URL fetchers have been disposed at this time.
431 // Unfortunately it seems that there is no direct way to detect (in tests)
432 // if a url_fetcher has been freed or not, since they are not automatically
433 // de-registered from the TestURLFetcherFactory on destruction.
436 void GoogleStreamingRemoteEngineTest::InjectDummyAudioChunk() {
437 unsigned char dummy_audio_buffer_data[2] = {'\0', '\0'};
438 scoped_refptr<AudioChunk> dummy_audio_chunk(
439 new AudioChunk(&dummy_audio_buffer_data[0],
440 sizeof(dummy_audio_buffer_data),
441 2 /* bytes per sample */));
442 DCHECK(engine_under_test_.get());
443 engine_under_test_->TakeAudioChunk(*dummy_audio_chunk.get());
446 size_t GoogleStreamingRemoteEngineTest::UpstreamChunksUploadedFromLastCall() {
447 TestURLFetcher* upstream_fetcher = GetUpstreamFetcher();
448 DCHECK(upstream_fetcher);
449 const size_t number_of_chunks = upstream_fetcher->upload_chunks().size();
450 DCHECK_GE(number_of_chunks, last_number_of_upstream_chunks_seen_);
451 const size_t new_chunks = number_of_chunks -
452 last_number_of_upstream_chunks_seen_;
453 last_number_of_upstream_chunks_seen_ = number_of_chunks;
454 return new_chunks;
457 std::string GoogleStreamingRemoteEngineTest::LastUpstreamChunkUploaded() {
458 TestURLFetcher* upstream_fetcher = GetUpstreamFetcher();
459 DCHECK(upstream_fetcher);
460 DCHECK(!upstream_fetcher->upload_chunks().empty());
461 return upstream_fetcher->upload_chunks().back();
464 void GoogleStreamingRemoteEngineTest::ProvideMockProtoResultDownstream(
465 const proto::SpeechRecognitionEvent& result) {
466 TestURLFetcher* downstream_fetcher = GetDownstreamFetcher();
468 ASSERT_TRUE(downstream_fetcher);
469 downstream_fetcher->set_status(URLRequestStatus(/* default=SUCCESS */));
470 downstream_fetcher->set_response_code(200);
472 std::string response_string = SerializeProtobufResponse(result);
473 response_buffer_.append(response_string);
474 downstream_fetcher->SetResponseString(response_buffer_);
475 downstream_fetcher->delegate()->OnURLFetchDownloadProgress(
476 downstream_fetcher,
477 response_buffer_.size(),
478 -1 /* total response length not used */);
481 void GoogleStreamingRemoteEngineTest::ProvideMockResultDownstream(
482 const SpeechRecognitionResult& result) {
483 proto::SpeechRecognitionEvent proto_event;
484 proto_event.set_status(proto::SpeechRecognitionEvent::STATUS_SUCCESS);
485 proto::SpeechRecognitionResult* proto_result = proto_event.add_result();
486 proto_result->set_final(!result.is_provisional);
487 for (size_t i = 0; i < result.hypotheses.size(); ++i) {
488 proto::SpeechRecognitionAlternative* proto_alternative =
489 proto_result->add_alternative();
490 const SpeechRecognitionHypothesis& hypothesis = result.hypotheses[i];
491 proto_alternative->set_confidence(hypothesis.confidence);
492 proto_alternative->set_transcript(base::UTF16ToUTF8(hypothesis.utterance));
494 ProvideMockProtoResultDownstream(proto_event);
497 void GoogleStreamingRemoteEngineTest::CloseMockDownstream(
498 DownstreamError error) {
499 TestURLFetcher* downstream_fetcher = GetDownstreamFetcher();
500 ASSERT_TRUE(downstream_fetcher);
502 const URLRequestStatus::Status fetcher_status =
503 (error == DOWNSTREAM_ERROR_NETWORK) ? URLRequestStatus::FAILED :
504 URLRequestStatus::SUCCESS;
505 downstream_fetcher->set_status(URLRequestStatus(fetcher_status, 0));
506 downstream_fetcher->set_response_code(
507 (error == DOWNSTREAM_ERROR_HTTP500) ? 500 : 200);
509 if (error == DOWNSTREAM_ERROR_WEBSERVICE_NO_MATCH) {
510 // Send empty response.
511 proto::SpeechRecognitionEvent response;
512 response_buffer_.append(SerializeProtobufResponse(response));
514 downstream_fetcher->SetResponseString(response_buffer_);
515 downstream_fetcher->delegate()->OnURLFetchComplete(downstream_fetcher);
518 void GoogleStreamingRemoteEngineTest::ExpectResultsReceived(
519 const SpeechRecognitionResults& results) {
520 ASSERT_GE(1U, results_.size());
521 ASSERT_TRUE(ResultsAreEqual(results, results_.front()));
522 results_.pop();
525 bool GoogleStreamingRemoteEngineTest::ResultsAreEqual(
526 const SpeechRecognitionResults& a, const SpeechRecognitionResults& b) {
527 if (a.size() != b.size())
528 return false;
530 SpeechRecognitionResults::const_iterator it_a = a.begin();
531 SpeechRecognitionResults::const_iterator it_b = b.begin();
532 for (; it_a != a.end() && it_b != b.end(); ++it_a, ++it_b) {
533 if (it_a->is_provisional != it_b->is_provisional ||
534 it_a->hypotheses.size() != it_b->hypotheses.size()) {
535 return false;
537 for (size_t i = 0; i < it_a->hypotheses.size(); ++i) {
538 const SpeechRecognitionHypothesis& hyp_a = it_a->hypotheses[i];
539 const SpeechRecognitionHypothesis& hyp_b = it_b->hypotheses[i];
540 if (hyp_a.utterance != hyp_b.utterance ||
541 hyp_a.confidence != hyp_b.confidence) {
542 return false;
547 return true;
550 void GoogleStreamingRemoteEngineTest::ExpectFramedChunk(
551 const std::string& chunk, uint32_t type) {
552 uint32_t value;
553 base::ReadBigEndian(&chunk[0], &value);
554 EXPECT_EQ(chunk.size() - 8, value);
555 base::ReadBigEndian(&chunk[4], &value);
556 EXPECT_EQ(type, value);
559 std::string GoogleStreamingRemoteEngineTest::SerializeProtobufResponse(
560 const proto::SpeechRecognitionEvent& msg) {
561 std::string msg_string;
562 msg.SerializeToString(&msg_string);
564 // Prepend 4 byte prefix length indication to the protobuf message as
565 // envisaged by the google streaming recognition webservice protocol.
566 uint32 prefix = HostToNet32(checked_cast<uint32>(msg_string.size()));
567 msg_string.insert(0, reinterpret_cast<char*>(&prefix), sizeof(prefix));
569 return msg_string;
572 } // namespace content