1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "RollingNumber.h"
8 
9 #include "mozilla/Assertions.h"
10 
11 #include <cstdint>
12 #include <gtest/gtest.h>
13 #include <type_traits>
14 
15 using RN8 = mozilla::RollingNumber<uint8_t>;
16 
TEST(RollingNumber,Value)17 TEST(RollingNumber, Value)
18 {
19   // Value type should reflect template argument.
20   static_assert(std::is_same_v<RN8::ValueType, uint8_t>);
21 
22   // Default init to 0.
23   const RN8 n;
24   // Access through Value().
25   EXPECT_EQ(0, n.Value());
26 
27   // Conversion constructor.
28   RN8 n42{42};
29   EXPECT_EQ(42, n42.Value());
30 
31   // Copy Constructor.
32   RN8 n42Copied{n42};
33   EXPECT_EQ(42, n42Copied.Value());
34 
35   // Assignment construction.
36   RN8 n42Assigned = n42;
37   EXPECT_EQ(42, n42Assigned.Value());
38 
39   // Assignment.
40   n42 = n;
41   EXPECT_EQ(0, n42.Value());
42 }
43 
TEST(RollingNumber,Operations)44 TEST(RollingNumber, Operations)
45 {
46   RN8 n;
47   EXPECT_EQ(0, n.Value());
48 
49   RN8 nPreInc = ++n;
50   EXPECT_EQ(1, n.Value());
51   EXPECT_EQ(1, nPreInc.Value());
52 
53   RN8 nPostInc = n++;
54   EXPECT_EQ(2, n.Value());
55   EXPECT_EQ(1, nPostInc.Value());
56 
57   RN8 nPreDec = --n;
58   EXPECT_EQ(1, n.Value());
59   EXPECT_EQ(1, nPreDec.Value());
60 
61   RN8 nPostDec = n--;
62   EXPECT_EQ(0, n.Value());
63   EXPECT_EQ(1, nPostDec.Value());
64 
65   RN8 nPlus = n + 10;
66   EXPECT_EQ(0, n.Value());
67   EXPECT_EQ(10, nPlus.Value());
68 
69   n += 20;
70   EXPECT_EQ(20, n.Value());
71 
72   RN8 nMinus = n - 2;
73   EXPECT_EQ(20, n.Value());
74   EXPECT_EQ(18, nMinus.Value());
75 
76   n -= 5;
77   EXPECT_EQ(15, n.Value());
78 
79   uint8_t diff = nMinus - n;
80   EXPECT_EQ(3, diff);
81 
82   // Overflows.
83   n = RN8(0);
84   EXPECT_EQ(0, n.Value());
85   n--;
86   EXPECT_EQ(255, n.Value());
87   n++;
88   EXPECT_EQ(0, n.Value());
89   n -= 10;
90   EXPECT_EQ(246, n.Value());
91   n += 20;
92   EXPECT_EQ(10, n.Value());
93 }
94 
TEST(RollingNumber,Comparisons)95 TEST(RollingNumber, Comparisons)
96 {
97   uint8_t i = 0;
98   do {
99     RN8 n{i};
100     EXPECT_EQ(i, n.Value());
101     EXPECT_TRUE(n == n);
102     EXPECT_FALSE(n != n);
103     EXPECT_FALSE(n < n);
104     EXPECT_TRUE(n <= n);
105     EXPECT_FALSE(n > n);
106     EXPECT_TRUE(n >= n);
107 
108     RN8 same = n;
109     EXPECT_TRUE(n == same);
110     EXPECT_FALSE(n != same);
111     EXPECT_FALSE(n < same);
112     EXPECT_TRUE(n <= same);
113     EXPECT_FALSE(n > same);
114     EXPECT_TRUE(n >= same);
115 
116 #ifdef DEBUG
117     // In debug builds, we are only allowed a quarter of the type range.
118     const uint8_t maxDiff = 255 / 4;
119 #else
120     // In non-debug builds, we can go half-way up or down the type range, and
121     // still conserve the expected ordering.
122     const uint8_t maxDiff = 255 / 2;
123 #endif
124     for (uint8_t add = 1; add <= maxDiff; ++add) {
125       RN8 bigger = n + add;
126       EXPECT_FALSE(n == bigger);
127       EXPECT_TRUE(n != bigger);
128       EXPECT_TRUE(n < bigger);
129       EXPECT_TRUE(n <= bigger);
130       EXPECT_FALSE(n > bigger);
131       EXPECT_FALSE(n >= bigger);
132     }
133 
134     for (uint8_t sub = 1; sub <= maxDiff; ++sub) {
135       RN8 smaller = n - sub;
136       EXPECT_FALSE(n == smaller);
137       EXPECT_TRUE(n != smaller);
138       EXPECT_FALSE(n < smaller);
139       EXPECT_FALSE(n <= smaller);
140       EXPECT_TRUE(n > smaller);
141       EXPECT_TRUE(n >= smaller);
142     }
143 
144     ++i;
145   } while (i != 0);
146 }
147