1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2015 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18// See https://msdn.microsoft.com/en-us/library/4hwaceh6.aspx
19#define _USE_MATH_DEFINES
20
21// Include the histogram header first to ensure that it is standalone
22#include <platform/histogram.h>
23
24#include <cmath>
25#include <algorithm>
26#include <functional>
27#include <sstream>
28#include <thread>
29
30#include "config.h"
31#include <gtest/gtest.h>
32
33class PopulatedSamples {
34public:
35    PopulatedSamples(std::ostream& stream)
36        : s(stream) { }
37
38    void operator()(const Histogram<int>::value_type& b) {
39        if (b->count() > 0) {
40            s << *b << "; ";
41        }
42    }
43
44    std::ostream& s;
45};
46
47TEST(HistoTest, Basic) {
48    GrowingWidthGenerator<int> gen(0, 10, M_E);
49    Histogram<int> histo(gen, 10);
50    histo.add(3, 1);
51    histo.add(-3, 15);
52    histo.add(84477242, 11);
53
54    // Verify the stream stuff works.
55    std::stringstream s;
56    s << histo;
57    std::string expected("{Histogram: [-2147483648, 0) = 15, [0, 10) = 1, "
58                         "[10, 37) = 0, [37, 110) = 0, [110, 310) = 0, "
59                         "[310, 855) = 0, [855, 2339) = 0, [2339, 6373) = 0, "
60                         "[6373, 17339) = 0, [17339, 47148) = 0, "
61                         "[47148, 128178) = 0, [128178, 2147483647) = 11}");
62    EXPECT_EQ(expected, s.str());
63
64    std::stringstream s2;
65    PopulatedSamples ps(s2);
66    std::for_each(histo.begin(), histo.end(), ps);
67    expected = "[-2147483648, 0) = 15; [0, 10) = 1; [128178, 2147483647) = 11; ";
68    EXPECT_EQ(expected, s2.str());
69    EXPECT_EQ(27u, histo.total());
70
71    // I haven't set a 4, but there should be something in that bin.
72    EXPECT_EQ(1u, histo.getBin(4)->count());
73
74    histo.reset();
75    EXPECT_EQ(0u, histo.total());
76}
77
78TEST(HistoTest, FixedInput) {
79    std::vector<int> figinput;
80    figinput.push_back(1);
81    figinput.push_back(10);
82    figinput.push_back(100);
83    figinput.push_back(1000);
84    figinput.push_back(10000);
85    FixedInputGenerator<int> fig(figinput);
86    Histogram<int> histo(fig, 4);
87
88    std::string expected("{Histogram: [-2147483648, 1) = 0, "
89                         "[1, 10) = 0, [10, 100) = 0, [100, 1000) = 0, "
90                         "[1000, 10000) = 0, [10000, 2147483647) = 0}");
91    std::stringstream s;
92    s << histo;
93    EXPECT_EQ(expected, s.str());
94}
95
96TEST(HistoTest, Exponential) {
97    ExponentialGenerator<int> gen(0, 10.0);
98    Histogram<int> histo(gen, 5);
99    std::string expected("{Histogram: [-2147483648, 1) = 0, [1, 10) = 0, "
100                         "[10, 100) = 0, [100, 1000) = 0, [1000, 10000) = 0, "
101                         "[10000, 100000) = 0, [100000, 2147483647) = 0}");
102    std::stringstream s;
103    s << histo;
104    EXPECT_EQ(expected, s.str());
105}
106
107TEST(HistoTest, CompleteRange) {
108    GrowingWidthGenerator<uint16_t> gen(0, 10, M_E);
109    Histogram<uint16_t> histo(gen, 10);
110    uint16_t i(0);
111    do {
112        histo.add(i);
113        ++i;
114    } while (i != 0);
115}
116
117
118TEST(BlockTimerTest, Basic) {
119    MicrosecondHistogram histo;
120    ASSERT_EQ(0u, histo.total());
121    {
122        BlockTimer timer(&histo);
123    }
124    EXPECT_EQ(1u, histo.total());
125}
126
127// TODO: This doesn't fully test the threshold functionality as it doesn't
128// check that the threshold is actually logged.
129TEST(BlockTimerTest, ThresholdTest) {
130    MicrosecondHistogram histo;
131    ASSERT_EQ(0u, histo.total());
132    {
133        GenericBlockTimer<MicrosecondHistogram, 1> timer(&histo, "thresholdTest");
134        std::this_thread::sleep_for(std::chrono::milliseconds(2));
135    }
136    EXPECT_EQ(1u, histo.total());
137}
138
139TEST(MoveTest, Basic){
140    Histogram<int> histo;
141    std::stringstream s;
142    s << histo;
143    std::string oldExpected = s.str();
144    s.str(std::string());
145    Histogram<int> newHist(std::move(histo));
146    s << newHist;
147    ASSERT_EQ(oldExpected, s.str());
148    s.str(std::string());
149    s << histo;
150    ASSERT_NE(s.str(), oldExpected);
151}
152