1/*
2 *  Copyright (c) 2011 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
11#include "webrtc/system_wrappers/interface/data_log.h"
12
13#include <map>
14#include <string>
15
16#include "testing/gtest/include/gtest/gtest.h"
17#include "webrtc/system_wrappers/interface/data_log_c.h"
18#include "webrtc/system_wrappers/source/data_log_c_helpers_unittest.h"
19
20using ::webrtc::DataLog;
21
22// A class for storing the values expected from a log table column when
23// verifying a log table file.
24struct ExpectedValues {
25 public:
26  ExpectedValues()
27    : values(),
28      multi_value_length(1) {
29  }
30
31  ExpectedValues(std::vector<std::string> expected_values,
32                 int expected_multi_value_length)
33    : values(expected_values),
34      multi_value_length(expected_multi_value_length) {
35  }
36
37  std::vector<std::string> values;
38  int multi_value_length;
39};
40
41typedef std::map<std::string, ExpectedValues> ExpectedValuesMap;
42
43// A static class used for parsing and verifying data log files.
44class DataLogParser {
45 public:
46  // Verifies that the log table stored in the file "log_file" corresponds to
47  // the cells and columns specified in "columns".
48  static int VerifyTable(FILE* log_file, const ExpectedValuesMap& columns) {
49    int row = 0;
50    char line_buffer[kMaxLineLength];
51    char* ret = fgets(line_buffer, kMaxLineLength, log_file);
52    EXPECT_FALSE(ret == NULL);
53    if (ret == NULL)
54      return -1;
55
56    std::string line(line_buffer, kMaxLineLength);
57    VerifyHeader(line, columns);
58    while (fgets(line_buffer, kMaxLineLength, log_file) != NULL) {
59      line = std::string(line_buffer, kMaxLineLength);
60      size_t line_position = 0;
61
62      for (ExpectedValuesMap::const_iterator it = columns.begin();
63           it != columns.end(); ++it) {
64        std::string str = ParseElement(line, &line_position,
65                                       it->second.multi_value_length);
66        EXPECT_EQ(str, it->second.values[row]);
67        if (str != it->second.values[row])
68          return -1;
69      }
70      ++row;
71    }
72    return 0;
73  }
74
75  // Verifies the table header stored in "line" to correspond with the header
76  // specified in "columns".
77  static int VerifyHeader(const std::string& line,
78                          const ExpectedValuesMap& columns) {
79    size_t line_position = 0;
80    for (ExpectedValuesMap::const_iterator it = columns.begin();
81         it != columns.end(); ++it) {
82      std::string str = ParseElement(line, &line_position,
83                                     it->second.multi_value_length);
84      EXPECT_EQ(str, it->first);
85      if (str != it->first)
86        return -1;
87    }
88    return 0;
89  }
90
91  // Parses out and returns one element from the string "line", which contains
92  // one line read from a log table file. An element can either be a column
93  // header or a cell of a row.
94  static std::string ParseElement(const std::string& line,
95                                  size_t* line_position,
96                                  int multi_value_length) {
97    std::string parsed_cell;
98    parsed_cell = "";
99    for (int i = 0; i < multi_value_length; ++i) {
100      size_t next_separator = line.find(',', *line_position);
101      EXPECT_NE(next_separator, std::string::npos);
102      if (next_separator == std::string::npos)
103        break;
104      parsed_cell += line.substr(*line_position,
105                                 next_separator - *line_position + 1);
106      *line_position = next_separator + 1;
107    }
108    return parsed_cell;
109  }
110
111  // This constant defines the maximum line length the DataLogParser can
112  // parse.
113  enum { kMaxLineLength = 100 };
114};
115
116TEST(TestDataLog, CreateReturnTest) {
117  for (int i = 0; i < 10; ++i)
118    ASSERT_EQ(DataLog::CreateLog(), 0);
119  ASSERT_EQ(DataLog::AddTable(DataLog::Combine("a proper table", 1)), 0);
120  for (int i = 0; i < 10; ++i)
121    DataLog::ReturnLog();
122  ASSERT_LT(DataLog::AddTable(DataLog::Combine("table failure", 1)), 0);
123}
124
125TEST(TestDataLog, VerifyCombineMethod) {
126  EXPECT_EQ(std::string("a proper table_1"),
127            DataLog::Combine("a proper table", 1));
128}
129
130TEST(TestDataLog, VerifySingleTable) {
131  DataLog::CreateLog();
132  DataLog::AddTable(DataLog::Combine("table", 1));
133  DataLog::AddColumn(DataLog::Combine("table", 1), "arrival", 1);
134  DataLog::AddColumn(DataLog::Combine("table", 1), "timestamp", 1);
135  DataLog::AddColumn(DataLog::Combine("table", 1), "size", 5);
136  uint32_t sizes[5] = {1400, 1500, 1600, 1700, 1800};
137  for (int i = 0; i < 10; ++i) {
138    DataLog::InsertCell(DataLog::Combine("table", 1), "arrival",
139                        static_cast<double>(i));
140    DataLog::InsertCell(DataLog::Combine("table", 1), "timestamp",
141                        static_cast<int64_t>(4354 + i));
142    DataLog::InsertCell(DataLog::Combine("table", 1), "size", sizes, 5);
143    DataLog::NextRow(DataLog::Combine("table", 1));
144  }
145  DataLog::ReturnLog();
146  // Verify file
147  FILE* table = fopen("table_1.txt", "r");
148  ASSERT_FALSE(table == NULL);
149  // Read the column names and verify with the expected columns.
150  // Note that the columns are written to file in alphabetical order.
151  // Data expected from parsing the file
152  const int kNumberOfRows = 10;
153  std::string string_arrival[kNumberOfRows] = {
154    "0,", "1,", "2,", "3,", "4,",
155    "5,", "6,", "7,", "8,", "9,"
156  };
157  std::string string_timestamp[kNumberOfRows] = {
158    "4354,", "4355,", "4356,", "4357,",
159    "4358,", "4359,", "4360,", "4361,",
160    "4362,", "4363,"
161  };
162  std::string string_sizes = "1400,1500,1600,1700,1800,";
163  ExpectedValuesMap expected;
164  expected["arrival,"] = ExpectedValues(
165                           std::vector<std::string>(string_arrival,
166                                                    string_arrival +
167                                                    kNumberOfRows),
168                           1);
169  expected["size[5],,,,,"] = ExpectedValues(
170                               std::vector<std::string>(10, string_sizes), 5);
171  expected["timestamp,"] = ExpectedValues(
172                             std::vector<std::string>(string_timestamp,
173                                                      string_timestamp +
174                                                      kNumberOfRows),
175                             1);
176  ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
177  fclose(table);
178}
179
180TEST(TestDataLog, VerifyMultipleTables) {
181  DataLog::CreateLog();
182  DataLog::AddTable(DataLog::Combine("table", 2));
183  DataLog::AddTable(DataLog::Combine("table", 3));
184  DataLog::AddColumn(DataLog::Combine("table", 2), "arrival", 1);
185  DataLog::AddColumn(DataLog::Combine("table", 2), "timestamp", 1);
186  DataLog::AddColumn(DataLog::Combine("table", 2), "size", 1);
187  DataLog::AddTable(DataLog::Combine("table", 4));
188  DataLog::AddColumn(DataLog::Combine("table", 3), "timestamp", 1);
189  DataLog::AddColumn(DataLog::Combine("table", 3), "arrival", 1);
190  DataLog::AddColumn(DataLog::Combine("table", 4), "size", 1);
191  for (int32_t i = 0; i < 10; ++i) {
192    DataLog::InsertCell(DataLog::Combine("table", 2), "arrival",
193                        static_cast<int32_t>(i));
194    DataLog::InsertCell(DataLog::Combine("table", 2), "timestamp",
195                        static_cast<int32_t>(4354 + i));
196    DataLog::InsertCell(DataLog::Combine("table", 2), "size",
197                        static_cast<int32_t>(1200 + 10 * i));
198    DataLog::InsertCell(DataLog::Combine("table", 3), "timestamp",
199                        static_cast<int32_t>(4354 + i));
200    DataLog::InsertCell(DataLog::Combine("table", 3), "arrival",
201                        static_cast<int32_t>(i));
202    DataLog::InsertCell(DataLog::Combine("table", 4), "size",
203                        static_cast<int32_t>(1200 + 10 * i));
204    DataLog::NextRow(DataLog::Combine("table", 4));
205    DataLog::NextRow(DataLog::Combine("table", 2));
206    DataLog::NextRow(DataLog::Combine("table", 3));
207  }
208  DataLog::ReturnLog();
209
210  // Data expected from parsing the file
211  const int kNumberOfRows = 10;
212  std::string string_arrival[kNumberOfRows] = {
213    "0,", "1,", "2,", "3,", "4,",
214    "5,", "6,", "7,", "8,", "9,"
215  };
216  std::string string_timestamp[kNumberOfRows] = {
217    "4354,", "4355,", "4356,", "4357,",
218    "4358,", "4359,", "4360,", "4361,",
219    "4362,", "4363,"
220  };
221  std::string string_size[kNumberOfRows] = {
222    "1200,", "1210,", "1220,", "1230,",
223    "1240,", "1250,", "1260,", "1270,",
224    "1280,", "1290,"
225  };
226
227  // Verify table 2
228  {
229    FILE* table = fopen("table_2.txt", "r");
230    ASSERT_FALSE(table == NULL);
231    ExpectedValuesMap expected;
232    expected["arrival,"] = ExpectedValues(
233                             std::vector<std::string>(string_arrival,
234                                                      string_arrival +
235                                                      kNumberOfRows),
236                             1);
237    expected["size,"] = ExpectedValues(
238                          std::vector<std::string>(string_size,
239                                                   string_size + kNumberOfRows),
240                          1);
241    expected["timestamp,"] = ExpectedValues(
242                               std::vector<std::string>(string_timestamp,
243                                                        string_timestamp +
244                                                        kNumberOfRows),
245                               1);
246    ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
247    fclose(table);
248  }
249
250  // Verify table 3
251  {
252    FILE* table = fopen("table_3.txt", "r");
253    ASSERT_FALSE(table == NULL);
254    ExpectedValuesMap expected;
255    expected["arrival,"] = ExpectedValues(
256                             std::vector<std::string>(string_arrival,
257                                                      string_arrival +
258                                                      kNumberOfRows),
259                             1);
260    expected["timestamp,"] = ExpectedValues(
261                               std::vector<std::string>(string_timestamp,
262                                                        string_timestamp +
263                                                        kNumberOfRows),
264                               1);
265    ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
266    fclose(table);
267  }
268
269  // Verify table 4
270  {
271    FILE* table = fopen("table_4.txt", "r");
272    ASSERT_FALSE(table == NULL);
273    ExpectedValuesMap expected;
274    expected["size,"] = ExpectedValues(
275                          std::vector<std::string>(string_size,
276                                                   string_size +
277                                                   kNumberOfRows),
278                          1);
279    ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
280    fclose(table);
281  }
282}
283
284TEST(TestDataLogCWrapper, VerifyCWrapper) {
285  // Simply call all C wrapper log functions through the C helper unittests.
286  // Main purpose is to make sure that the linkage is correct.
287
288  EXPECT_EQ(0, WebRtcDataLogCHelper_TestCreateLog());
289  EXPECT_EQ(0, WebRtcDataLogCHelper_TestCombine());
290  EXPECT_EQ(0, WebRtcDataLogCHelper_TestAddTable());
291  EXPECT_EQ(0, WebRtcDataLogCHelper_TestAddColumn());
292  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_int());
293  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_int());
294  EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
295  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_float());
296  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_float());
297  EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
298  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_double());
299  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_double());
300  EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
301  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_int32());
302  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_int32());
303  EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
304  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_uint32());
305  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_uint32());
306  EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
307  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_int64());
308  EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_int64());
309  EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
310  EXPECT_EQ(0, WebRtcDataLogCHelper_TestReturnLog());
311}
312