1// Copyright 2008 Google Inc.
2// Authors: Craig Silverstein, Lincoln Smith
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#ifndef OPEN_VCDIFF_TESTING_H_
17#define OPEN_VCDIFF_TESTING_H_
18
19#include <config.h>
20#include <assert.h>
21#include <stdint.h>  // int64_t
22#include <stdlib.h>  // rand
23#include <time.h>  // gettimeofday
24#include "gtest/gtest.h"
25
26#ifdef HAVE_SYS_TIME_H
27#include <sys/time.h>  // struct timeval
28#endif  // HAVE_SYS_TIME_H
29
30#ifdef HAVE_WINDOWS_H
31#include <windows.h>  // QueryPerformanceCounter
32#endif  // HAVE_WINDOWS_H
33
34// CHECK is used for assertions that verify the consistency of the test itself,
35// rather than correctness of the code that is being tested.
36//
37// It is better to use a preprocessor macro for CHECK
38// than an inline function, because assert() may report
39// the source file and line where the failure occurred.
40//
41// Putting parentheses around the macro arguments
42// (e.g. "assert((X) == (Y))") would be good practice
43// but would produce error messages that are inconsistent
44// with those expected in the unit tests.
45
46#define CHECK(CONDITION) assert(CONDITION)
47#define CHECK_EQ(X, Y) assert(X == Y)
48#define CHECK_NE(X, Y) assert(X != Y)
49#define CHECK_GE(X, Y) assert(X >= Y)
50#define CHECK_GT(X, Y) assert(X > Y)
51#define CHECK_LE(X, Y) assert(X <= Y)
52#define CHECK_LT(X, Y) assert(X < Y)
53
54namespace open_vcdiff {
55
56// Support for timing tests
57#if defined(HAVE_GETTIMEOFDAY)
58class CycleTimer {
59 public:
60  inline CycleTimer() {
61    Reset();
62  }
63
64  inline void Reset() {
65    start_time_.tv_sec = 0;
66    start_time_.tv_usec = 0;
67    cumulative_time_in_usec_ = 0;
68  }
69
70  inline void Start() {
71    CHECK(!IsStarted());
72    gettimeofday(&start_time_, NULL);
73  }
74
75  inline void Restart() {
76    Reset();
77    Start();
78  }
79
80  inline void Stop() {
81    struct timeval end_time;
82    gettimeofday(&end_time, NULL);
83    CHECK(IsStarted());
84    cumulative_time_in_usec_ +=
85        (1000000 * (end_time.tv_sec - start_time_.tv_sec))
86        + end_time.tv_usec - start_time_.tv_usec;
87    start_time_.tv_sec = 0;
88    start_time_.tv_usec = 0;
89  }
90
91  inline int64_t GetInUsec() {
92    return cumulative_time_in_usec_;
93  }
94
95 private:
96  inline bool IsStarted() {
97    return (start_time_.tv_usec > 0) || (start_time_.tv_sec > 0);
98  }
99
100  struct timeval start_time_;
101  int64_t cumulative_time_in_usec_;
102};
103#elif defined(HAVE_QUERYPERFORMANCECOUNTER)
104class CycleTimer {
105 public:
106  inline CycleTimer() {
107    LARGE_INTEGER frequency;
108    QueryPerformanceFrequency(&frequency);  // counts per second
109    usecs_per_count_ = 1000000.0 / static_cast<double>(frequency.QuadPart);
110    Reset();
111  }
112
113  inline void Reset() {
114    start_time_.QuadPart = 0;
115    cumulative_time_in_usec_ = 0;
116  }
117
118  inline void Start() {
119    CHECK(!IsStarted());
120    QueryPerformanceCounter(&start_time_);
121  }
122
123  inline void Restart() {
124    Reset();
125    Start();
126  }
127
128  inline void Stop() {
129    LARGE_INTEGER end_time;
130    QueryPerformanceCounter(&end_time);
131    CHECK(IsStarted());
132    double count_diff = static_cast<double>(
133        end_time.QuadPart - start_time_.QuadPart);
134    cumulative_time_in_usec_ +=
135        static_cast<int64_t>(count_diff * usecs_per_count_);
136    start_time_.QuadPart = 0;
137  }
138
139  inline int64_t GetInUsec() {
140    return cumulative_time_in_usec_;
141  }
142
143 private:
144  inline bool IsStarted() {
145    return start_time_.QuadPart > 0;
146  }
147
148  LARGE_INTEGER start_time_;
149  int64_t cumulative_time_in_usec_;
150  double usecs_per_count_;
151};
152#else
153#error CycleTimer needs an implementation that does not use gettimeofday or QueryPerformanceCounter
154#endif  // HAVE_GETTIMEOFDAY
155
156// This function returns a pseudo-random value of type IntType between 0 and
157// limit.  It uses the standard rand() function to produce the value, and makes
158// as many calls to rand() as needed to ensure that the values returned can fall
159// within the full range specified.  It is slow, so don't include calls to this
160// function when calculating the execution time of tests.
161//
162template<typename IntType>
163inline IntType PortableRandomInRange(IntType limit) {
164  uint64_t value = rand();
165  double rand_limit = RAND_MAX;  // The maximum possible value
166  while (rand_limit < limit) {
167    // value is multiplied by (RAND_MAX + 1) each iteration. This factor will be
168    // canceled out when we divide by rand_limit to get scaled_value, below.
169    value = (value * (static_cast<uint64_t>(RAND_MAX) + 1)) + rand();
170    rand_limit = (rand_limit * (RAND_MAX + 1.0)) + RAND_MAX;
171  }
172  // Translate the random 64-bit integer into a floating-point value between
173  // 0.0 (inclusive) and 1.0 (inclusive).
174  const double scaled_value = value / rand_limit;
175  return static_cast<IntType>(limit * scaled_value);
176}
177
178}  // namespace open_vcdiff
179
180#endif  // OPEN_VCDIFF_TESTING_H_
181