blob: e7e8a32ed1423f7b487907f36fe66eb091763d6f [file] [log] [blame]
François Doray714df63e2025-07-04 19:07:201// Copyright 2025 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/byte_count.h"
6
Joe Masona946ad22025-07-21 17:02:027#include "base/numerics/checked_math.h"
Joe Masonbb7bec02025-07-23 00:59:348#include "base/numerics/safe_conversions.h"
François Doray714df63e2025-07-04 19:07:209#include "base/test/gtest_util.h"
10#include "testing/gmock/include/gmock/gmock.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace base {
14
15TEST(ByteCount, ConstructionDefault) {
16 constexpr ByteCount bytes;
17 EXPECT_EQ(0, bytes.InBytes());
18 EXPECT_EQ(0, bytes.InKiB());
19 EXPECT_EQ(0, bytes.InMiB());
20 EXPECT_EQ(0, bytes.InGiB());
21 EXPECT_EQ(0, bytes.InBytesUnsigned());
22}
23
24TEST(ByteCount, ConstructionByteCount) {
25 constexpr ByteCount bytes(1024 * 1024 * 1024);
26 EXPECT_EQ(1024 * 1024 * 1024, bytes.InBytes());
27 EXPECT_EQ(1024 * 1024, bytes.InKiB());
28 EXPECT_EQ(1024, bytes.InMiB());
29 EXPECT_EQ(1, bytes.InGiB());
30 EXPECT_EQ(1024u * 1024 * 1024, bytes.InBytesUnsigned());
31}
32
33TEST(ByteCount, ConstructionUnsigned) {
34 auto bytes = ByteCount::FromUnsigned(5u);
35 EXPECT_EQ(5, bytes.InBytes());
36}
37
Joe Masona946ad22025-07-21 17:02:0238TEST(ByteCountDeathTest, ConstructionUnsignedInvalid) {
François Doray714df63e2025-07-04 19:07:2039 BASE_EXPECT_DEATH(
Joe Masona946ad22025-07-21 17:02:0240 ByteCount::FromUnsigned(std::numeric_limits<uint64_t>::max()), "");
41}
42
43TEST(ByteCount, ConstructionChecked) {
44 auto bytes = ByteCount::FromChecked(CheckedNumeric<uint64_t>(5));
45 EXPECT_EQ(5, bytes.InBytes());
46}
47
48TEST(ByteCountDeathTest, ConstructionCheckedInvalid) {
49 BASE_EXPECT_DEATH(
50 ByteCount::FromChecked(
51 CheckedNumeric<int64_t>(std::numeric_limits<int64_t>::max()) + 1),
52 "");
François Doray714df63e2025-07-04 19:07:2053}
54
Joe Masonbb7bec02025-07-23 00:59:3455TEST(ByteCount, ConstructionOtherUnitIntegral) {
56 // 32-bit numbers that will overflow if multiplied as
57 // CheckedNumeric<uint32_t>, but not if multiplied as CheckedNumeric<int64_t>.
58 // This verifies that the implementations of the KiB, MiB and GiB templates
59 // avoid a subtle conversion order bug.
60 constexpr int64_t kLargeKiB32 =
61 std::numeric_limits<uint32_t>::max() / 1024 + 1;
62 constexpr int64_t kLargeMiB32 =
63 std::numeric_limits<uint32_t>::max() / 1024 / 1024 + 1;
64 constexpr int64_t kLargeGiB32 =
65 std::numeric_limits<uint32_t>::max() / 1024 / 1024 / 1024 + 1;
66
67 static_assert(kLargeKiB32 * 1024 > std::numeric_limits<uint32_t>::max());
68 static_assert(kLargeMiB32 * 1024 * 1024 >
69 std::numeric_limits<uint32_t>::max());
70 static_assert(kLargeGiB32 * 1024 * 1024 * 1024 >
71 std::numeric_limits<uint32_t>::max());
72
François Doray714df63e2025-07-04 19:07:2073 auto kib5 = KiB(5);
74 EXPECT_EQ(5 * 1024, kib5.InBytes());
Joe Masonbb7bec02025-07-23 00:59:3475 EXPECT_EQ(kLargeKiB32 * 1024,
76 KiB(checked_cast<uint32_t>(kLargeKiB32)).InBytes());
François Doray714df63e2025-07-04 19:07:2077
78 auto mib5 = MiB(5);
79 EXPECT_EQ(5 * 1024 * 1024, mib5.InBytes());
Joe Masonbb7bec02025-07-23 00:59:3480 EXPECT_EQ(kLargeMiB32 * 1024 * 1024,
81 MiB(checked_cast<uint32_t>(kLargeMiB32)).InBytes());
François Doray714df63e2025-07-04 19:07:2082
83 auto gib5 = GiB(5);
84 EXPECT_EQ(5ll * 1024 * 1024 * 1024, gib5.InBytes());
Joe Masonbb7bec02025-07-23 00:59:3485 EXPECT_EQ(kLargeGiB32 * 1024 * 1024 * 1024,
86 GiB(checked_cast<uint32_t>(kLargeGiB32)).InBytes());
87}
88
89TEST(ByteCount, ConstructionOtherUnitFloat) {
90 auto kib = KiB(5.5);
91 EXPECT_EQ(5632, kib.InBytes());
92 EXPECT_EQ(5632.0, kib.InBytesF());
93
94 auto mib = MiB(2.3);
95 // Round down from 2411724.8
96 EXPECT_EQ(2411724, mib.InBytes());
97 EXPECT_EQ(2411724.0, mib.InBytesF());
98
99 auto gib = GiB(12.81);
100 // Round down from 13754632765.4
101 EXPECT_EQ(13754632765, gib.InBytes());
102 EXPECT_EQ(13754632765.0, gib.InBytesF());
103
104 auto negative_kib = KiB(-4.2);
105 // Round up from -4300.8
106 EXPECT_EQ(-4300, negative_kib.InBytes());
107 EXPECT_EQ(-4300.0, negative_kib.InBytesF());
108
109 auto negative_mib = MiB(-9.89);
110 // Round up from -10370416.64
111 EXPECT_EQ(-10370416, negative_mib.InBytes());
112 EXPECT_EQ(-10370416.0, negative_mib.InBytesF());
113
114 auto negative_gib = GiB(-5.17);
115 // Round up from -5551245230.08
116 EXPECT_EQ(-5551245230, negative_gib.InBytes());
117 EXPECT_EQ(-5551245230.0, negative_gib.InBytesF());
François Doray714df63e2025-07-04 19:07:20118}
119
Joe Masona946ad22025-07-21 17:02:02120TEST(ByteCountDeathTest, ConstructionOtherUnitInvalid) {
121 BASE_EXPECT_DEATH(KiB(std::numeric_limits<int64_t>::max()), "");
François Doray714df63e2025-07-04 19:07:20122
Joe Masona946ad22025-07-21 17:02:02123 BASE_EXPECT_DEATH(MiB(std::numeric_limits<int64_t>::max()), "");
François Doray714df63e2025-07-04 19:07:20124
Joe Masona946ad22025-07-21 17:02:02125 BASE_EXPECT_DEATH(GiB(std::numeric_limits<int64_t>::max()), "");
François Doray714df63e2025-07-04 19:07:20126}
127
Avi Drissman0bebd542025-08-14 16:31:00128TEST(ByteCount, IsPositive) {
129 EXPECT_FALSE(ByteCount(-2).is_positive());
130 EXPECT_FALSE(ByteCount(0).is_positive());
131 EXPECT_TRUE(ByteCount(2).is_positive());
132}
133
François Doray714df63e2025-07-04 19:07:20134TEST(ByteCount, IsZero) {
François Doray714df63e2025-07-04 19:07:20135 EXPECT_FALSE(ByteCount(-2).is_zero());
Avi Drissman0bebd542025-08-14 16:31:00136 EXPECT_TRUE(ByteCount(0).is_zero());
François Doray714df63e2025-07-04 19:07:20137 EXPECT_FALSE(ByteCount(2).is_zero());
138}
139
Avi Drissman0bebd542025-08-14 16:31:00140TEST(ByteCount, IsNegative) {
141 EXPECT_TRUE(ByteCount(-2).is_negative());
142 EXPECT_FALSE(ByteCount(0).is_negative());
143 EXPECT_FALSE(ByteCount(2).is_negative());
144}
145
François Doray714df63e2025-07-04 19:07:20146TEST(ByteCount, InFloating) {
147 constexpr ByteCount bytes(3435973836);
Joe Masonbb7bec02025-07-23 00:59:34148 EXPECT_THAT(bytes.InBytesF(), testing::DoubleEq(3435973836.0));
François Doray714df63e2025-07-04 19:07:20149 EXPECT_THAT(bytes.InKiBF(), testing::DoubleEq(3355443.19921875));
150 EXPECT_THAT(bytes.InMiBF(), testing::DoubleEq(3276.7999992370605));
151 EXPECT_THAT(bytes.InGiBF(), testing::DoubleEq(3.1999999992549419));
Avi Drissmanb7bb7f02025-08-12 17:23:02152 constexpr ByteCount morebytes(3435973836343597383);
153 EXPECT_THAT(morebytes.InTiBF(), testing::DoubleEq(3124999.9995849044));
154 EXPECT_THAT(morebytes.InPiBF(), testing::DoubleEq(3051.7578120946332));
155 EXPECT_THAT(morebytes.InEiBF(), testing::DoubleEq(2.9802322383736652));
François Doray714df63e2025-07-04 19:07:20156}
157
Joe Masona946ad22025-07-21 17:02:02158TEST(ByteCountDeathTest, InUnsignedInvalid) {
François Doray714df63e2025-07-04 19:07:20159 ByteCount bytes(-2);
Joe Masona946ad22025-07-21 17:02:02160 BASE_EXPECT_DEATH(bytes.InBytesUnsigned(), "");
François Doray714df63e2025-07-04 19:07:20161}
162
Avi Drissmanb7bb7f02025-08-12 17:23:02163TEST(ByteCount, UnarySigns) {
164 ByteCount bytes(42);
165 EXPECT_EQ(bytes, +bytes);
166
167 ByteCount negative_bytes(-42);
168 EXPECT_EQ(-bytes, negative_bytes);
169}
170
François Doray714df63e2025-07-04 19:07:20171TEST(ByteCount, Arithmetic) {
172 ByteCount bytes(42);
173
174 ByteCount add = bytes + ByteCount(10);
175 EXPECT_EQ(52, add.InBytes());
176
177 ByteCount sub = bytes - ByteCount(10);
178 EXPECT_EQ(32, sub.InBytes());
179
180 ByteCount mul = bytes * 10;
181 EXPECT_EQ(420, mul.InBytes());
182
Avi Drissmanb7bb7f02025-08-12 17:23:02183 ByteCount mul2 = 10 * bytes;
184 EXPECT_EQ(420, mul2.InBytes());
185
François Doray714df63e2025-07-04 19:07:20186 ByteCount div = bytes / 2;
187 EXPECT_EQ(21, div.InBytes());
188}
189
Thiabaud Engelbrecht84089c32025-07-23 19:16:53190TEST(ByteCount, ArithmeticCompound) {
191 ByteCount bytes(42);
192
193 bytes += ByteCount(10);
194 EXPECT_EQ(52, bytes.InBytes());
195
196 bytes -= ByteCount(10);
197 EXPECT_EQ(42, bytes.InBytes());
198
199 bytes *= 10;
200 EXPECT_EQ(420, bytes.InBytes());
201
202 bytes /= 2;
203 EXPECT_EQ(210, bytes.InBytes());
204}
205
Joe Masona946ad22025-07-21 17:02:02206TEST(ByteCountDeathTest, ArithmeticInvalid) {
François Doray714df63e2025-07-04 19:07:20207 ByteCount max_bytes(std::numeric_limits<int64_t>::max());
208
209 BASE_EXPECT_DEATH({ max_bytes + max_bytes; }, "");
210
211 BASE_EXPECT_DEATH({ ByteCount() - max_bytes - max_bytes; }, "");
212
213 BASE_EXPECT_DEATH({ max_bytes * 2; }, "");
214
215 BASE_EXPECT_DEATH({ max_bytes / 0; }, "");
216}
217
218TEST(ByteCount, Comparison) {
219 ByteCount a(1);
220 ByteCount b(2);
221 ByteCount c(2);
222
223 EXPECT_TRUE(a < b);
224 EXPECT_FALSE(b < a);
225 EXPECT_FALSE(b < c);
226
227 EXPECT_TRUE(a <= b);
228 EXPECT_FALSE(b <= a);
229 EXPECT_TRUE(b <= c);
230
231 EXPECT_FALSE(a > b);
232 EXPECT_TRUE(b > a);
233 EXPECT_FALSE(b > c);
234
235 EXPECT_FALSE(a >= b);
236 EXPECT_TRUE(b >= a);
237 EXPECT_TRUE(b >= c);
238
239 EXPECT_FALSE(a == b);
240 EXPECT_TRUE(b == c);
241
242 EXPECT_TRUE(a != b);
243 EXPECT_FALSE(b != c);
244}
245
François Doray396c6712025-08-05 11:52:45246TEST(ByteCount, StreamOperator) {
Avi Drissmanb7bb7f02025-08-12 17:23:02247 struct TestValue {
248 int64_t bytes;
249 const char* expected;
250 } kTestValues[] = {
251 {-1, "-1B"},
252 {0, "0B"},
253 {1, "1B"},
254
255 {1024 - 1, "1023B"},
256 {1024, "1KiB"},
257 {1024 + 1, "1025B (1.001KiB)"},
258 {-(1024 - 1), "-1023B"},
259 {-(1024), "-1KiB"},
260 {-(1024 + 1), "-1025B (-1.001KiB)"},
261
262 {1024 * 1024 - 1, "1048575B (1023.999KiB)"},
263 {1024 * 1024, "1MiB"},
264 {1024 * 1024 + 1'000, "1049576B (1.001MiB)"},
265 {-(1024 * 1024 - 1), "-1048575B (-1023.999KiB)"},
266 {-(1024 * 1024), "-1MiB"},
267 {-(1024 * 1024 + 1'000), "-1049576B (-1.001MiB)"},
268
269 {1024LL * 1024 * 1024 - 1'000, "1073740824B (1023.999MiB)"},
270 {1024LL * 1024 * 1024, "1GiB"},
271 {1024LL * 1024 * 1024 + 1'000'000, "1074741824B (1.001GiB)"},
272
273 {1024LL * 1024 * 1024 * 1024 - 1'000'000, "1099510627776B (1023.999GiB)"},
274 {1024LL * 1024 * 1024 * 1024, "1TiB"},
275 {1024LL * 1024 * 1024 * 1024 + 1'000'000'000,
276 "1100511627776B (1.001TiB)"},
277
278 {1024LL * 1024 * 1024 * 1024 * 1024 - 1'000'000'000,
279 "1125898906842624B (1023.999TiB)"},
280 {1024LL * 1024 * 1024 * 1024 * 1024, "1PiB"},
281 {1024LL * 1024 * 1024 * 1024 * 1024 + 1'000'000'000'000,
282 "1126899906842624B (1.001PiB)"},
283
284 {1024LL * 1024 * 1024 * 1024 * 1024 * 1024 - 1'000'000'000'000,
285 "1152920504606846976B (1023.999PiB)"},
286 {1024LL * 1024 * 1024 * 1024 * 1024 * 1024, "1EiB"},
287 {1024LL * 1024 * 1024 * 1024 * 1024 * 1024 + 1'000'000'000'000'000,
288 "1153921504606846976B (1.001EiB)"},
289 {-(1024LL * 1024 * 1024 * 1024 * 1024 * 1024 - 1'000'000'000'000),
290 "-1152920504606846976B (-1023.999PiB)"},
291 {-(1024LL * 1024 * 1024 * 1024 * 1024 * 1024), "-1EiB"},
292 {-(1024LL * 1024 * 1024 * 1024 * 1024 * 1024 + 1'000'000'000'000'000),
293 "-1153921504606846976B (-1.001EiB)"},
294
295 {ByteCount::Max().InBytes(), "9223372036854775807B (8.000EiB)"},
296 {std::numeric_limits<int64_t>::min(), "-8EiB"},
297 {std::numeric_limits<int64_t>::min() + 1,
298 "-9223372036854775807B (-8.000EiB)"},
299 };
300 for (const auto& test_value : kTestValues) {
François Doray396c6712025-08-05 11:52:45301 std::stringstream ss;
Avi Drissmanb7bb7f02025-08-12 17:23:02302 ss << ByteCount(test_value.bytes);
303 EXPECT_EQ(test_value.expected, ss.str());
François Doray396c6712025-08-05 11:52:45304 }
305}
306
François Doray714df63e2025-07-04 19:07:20307} // namespace base