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