1// Copyright (c) 2011 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.
4
5#include <string>
6
7#include "base/memory/scoped_ptr.h"
8#include "base/stl_util.h"
9#include "base/strings/string_number_conversions.h"
10#include "remoting/proto/event.pb.h"
11#include "remoting/proto/internal.pb.h"
12#include "remoting/protocol/message_decoder.h"
13#include "remoting/protocol/message_serialization.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace remoting {
17namespace protocol {
18
19static const unsigned int kTestKey = 142;
20
21static void AppendMessage(const EventMessage& msg,
22                          std::string* buffer) {
23  // Contains one encoded message.
24  scoped_refptr<net::IOBufferWithSize> encoded_msg;
25  encoded_msg = SerializeAndFrameMessage(msg);
26  buffer->append(encoded_msg->data(), encoded_msg->size());
27}
28
29// Construct and prepare data in the |output_stream|.
30static void PrepareData(uint8** buffer, int* size) {
31  // Contains all encoded messages.
32  std::string encoded_data;
33
34  // Then append 10 update sequences to the data.
35  for (int i = 0; i < 10; ++i) {
36    EventMessage msg;
37    msg.set_sequence_number(i);
38    msg.mutable_key_event()->set_usb_keycode(kTestKey + i);
39    msg.mutable_key_event()->set_pressed((i % 2) != 0);
40    AppendMessage(msg, &encoded_data);
41  }
42
43  *size = encoded_data.length();
44  *buffer = new uint8[*size];
45  memcpy(*buffer, encoded_data.c_str(), *size);
46}
47
48void SimulateReadSequence(const int read_sequence[], int sequence_size) {
49  // Prepare encoded data for testing.
50  int size;
51  uint8* test_data;
52  PrepareData(&test_data, &size);
53  scoped_ptr<uint8[]> memory_deleter(test_data);
54
55  // Then simulate using MessageDecoder to decode variable
56  // size of encoded data.
57  // The first thing to do is to generate a variable size of data. This is done
58  // by iterating the following array for read sizes.
59  MessageDecoder decoder;
60
61  // Then feed the protocol decoder using the above generated data and the
62  // read pattern.
63  std::list<EventMessage*> message_list;
64  for (int pos = 0; pos < size;) {
65    SCOPED_TRACE("Input position: " + base::IntToString(pos));
66
67    // First generate the amount to feed the decoder.
68    int read = std::min(size - pos, read_sequence[pos % sequence_size]);
69
70    // And then prepare an IOBuffer for feeding it.
71    scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(read));
72    memcpy(buffer->data(), test_data + pos, read);
73    decoder.AddData(buffer, read);
74    while (true) {
75      scoped_ptr<CompoundBuffer> message(decoder.GetNextMessage());
76      if (!message.get())
77        break;
78
79      EventMessage* event = new EventMessage();
80      CompoundBufferInputStream stream(message.get());
81      ASSERT_TRUE(event->ParseFromZeroCopyStream(&stream));
82      message_list.push_back(event);
83    }
84    pos += read;
85  }
86
87  // Then verify the decoded messages.
88  EXPECT_EQ(10u, message_list.size());
89
90  unsigned int index = 0;
91  for (std::list<EventMessage*>::iterator it =
92           message_list.begin();
93       it != message_list.end(); ++it) {
94    SCOPED_TRACE("Message " + base::IntToString(index));
95
96    EventMessage* message = *it;
97    // Partial update stream.
98    EXPECT_TRUE(message->has_key_event());
99
100    // TODO(sergeyu): Don't use index here. Instead store the expected values
101    // in an array.
102    EXPECT_EQ(kTestKey + index, message->key_event().usb_keycode());
103    EXPECT_EQ((index % 2) != 0, message->key_event().pressed());
104    ++index;
105  }
106  STLDeleteElements(&message_list);
107}
108
109TEST(MessageDecoderTest, SmallReads) {
110  const int kReads[] = {1, 2, 3, 1};
111  SimulateReadSequence(kReads, arraysize(kReads));
112}
113
114TEST(MessageDecoderTest, LargeReads) {
115  const int kReads[] = {50, 50, 5};
116  SimulateReadSequence(kReads, arraysize(kReads));
117}
118
119TEST(MessageDecoderTest, EmptyReads) {
120  const int kReads[] = {4, 0, 50, 0};
121  SimulateReadSequence(kReads, arraysize(kReads));
122}
123
124}  // namespace protocol
125}  // namespace remoting
126