aboutsummaryrefslogtreecommitdiff
path: root/src/testing.h
blob: 3227fd8045b178fbd1ac9049b0ac9477bb161d94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright 2008 Google Inc.
// Authors: Craig Silverstein, Lincoln Smith
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef OPEN_VCDIFF_TESTING_H_
#define OPEN_VCDIFF_TESTING_H_

#include <config.h>
#include <assert.h>
#include <stdint.h>  // int64_t
#include <stdlib.h>  // rand
#include <time.h>  // gettimeofday
#include "gtest/gtest.h"

#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>  // struct timeval
#endif  // HAVE_SYS_TIME_H

#ifdef HAVE_WINDOWS_H
#include <windows.h>  // QueryPerformanceCounter
#endif  // HAVE_WINDOWS_H

// CHECK is used for assertions that verify the consistency of the test itself,
// rather than correctness of the code that is being tested.
//
// It is better to use a preprocessor macro for CHECK
// than an inline function, because assert() may report
// the source file and line where the failure occurred.
//
// Putting parentheses around the macro arguments
// (e.g. "assert((X) == (Y))") would be good practice
// but would produce error messages that are inconsistent
// with those expected in the unit tests.

#define CHECK(CONDITION) assert(CONDITION)
#define CHECK_EQ(X, Y) assert(X == Y)
#define CHECK_NE(X, Y) assert(X != Y)
#define CHECK_GE(X, Y) assert(X >= Y)
#define CHECK_GT(X, Y) assert(X > Y)
#define CHECK_LE(X, Y) assert(X <= Y)
#define CHECK_LT(X, Y) assert(X < Y)

namespace open_vcdiff {

// Support for timing tests
#if defined(HAVE_GETTIMEOFDAY)
class CycleTimer {
 public:
  inline CycleTimer() {
    Reset();
  }

  inline void Reset() {
    start_time_.tv_sec = 0;
    start_time_.tv_usec = 0;
    cumulative_time_in_usec_ = 0;
  }

  inline void Start() {
    CHECK(!IsStarted());
    gettimeofday(&start_time_, NULL);
  }

  inline void Restart() {
    Reset();
    Start();
  }

  inline void Stop() {
    struct timeval end_time;
    gettimeofday(&end_time, NULL);
    CHECK(IsStarted());
    cumulative_time_in_usec_ +=
        (1000000 * (end_time.tv_sec - start_time_.tv_sec))
        + end_time.tv_usec - start_time_.tv_usec;
    start_time_.tv_sec = 0;
    start_time_.tv_usec = 0;
  }

  inline int64_t GetInUsec() {
    return cumulative_time_in_usec_;
  }

 private:
  inline bool IsStarted() {
    return (start_time_.tv_usec > 0) || (start_time_.tv_sec > 0);
  }

  struct timeval start_time_;
  int64_t cumulative_time_in_usec_;
};
#elif defined(HAVE_QUERYPERFORMANCECOUNTER)
class CycleTimer {
 public:
  inline CycleTimer() {
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);  // counts per second
    usecs_per_count_ = 1000000.0 / static_cast<double>(frequency.QuadPart);
    Reset();
  }

  inline void Reset() {
    start_time_.QuadPart = 0;
    cumulative_time_in_usec_ = 0;
  }

  inline void Start() {
    CHECK(!IsStarted());
    QueryPerformanceCounter(&start_time_);
  }

  inline void Restart() {
    Reset();
    Start();
  }

  inline void Stop() {
    LARGE_INTEGER end_time;
    QueryPerformanceCounter(&end_time);
    CHECK(IsStarted());
    double count_diff = static_cast<double>(
        end_time.QuadPart - start_time_.QuadPart);
    cumulative_time_in_usec_ +=
        static_cast<int64_t>(count_diff * usecs_per_count_);
    start_time_.QuadPart = 0;
  }

  inline int64_t GetInUsec() {
    return cumulative_time_in_usec_;
  }

 private:
  inline bool IsStarted() {
    return start_time_.QuadPart > 0;
  }

  LARGE_INTEGER start_time_;
  int64_t cumulative_time_in_usec_;
  double usecs_per_count_;
};
#else
#error CycleTimer needs an implementation that does not use gettimeofday or QueryPerformanceCounter
#endif  // HAVE_GETTIMEOFDAY

// This function returns a pseudo-random value of type IntType between 0 and
// limit.  It uses the standard rand() function to produce the value, and makes
// as many calls to rand() as needed to ensure that the values returned can fall
// within the full range specified.  It is slow, so don't include calls to this
// function when calculating the execution time of tests.
//
template<typename IntType>
inline IntType PortableRandomInRange(IntType limit) {
  uint64_t value = rand();
  double rand_limit = RAND_MAX;  // The maximum possible value
  while (rand_limit < limit) {
    // value is multiplied by (RAND_MAX + 1) each iteration. This factor will be
    // canceled out when we divide by rand_limit to get scaled_value, below.
    value = (value * (static_cast<uint64_t>(RAND_MAX) + 1)) + rand();
    rand_limit = (rand_limit * (RAND_MAX + 1.0)) + RAND_MAX;
  }
  // Translate the random 64-bit integer into a floating-point value between
  // 0.0 (inclusive) and 1.0 (inclusive).
  const double scaled_value = value / rand_limit;
  return static_cast<IntType>(limit * scaled_value);
}

}  // namespace open_vcdiff

#endif  // OPEN_VCDIFF_TESTING_H_