910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/byte_count.h"

#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
#include "base/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace base {

TEST(ByteCount, ConstructionDefault) {
  constexpr ByteCount bytes;
  EXPECT_EQ(0, bytes.InBytes());
  EXPECT_EQ(0, bytes.InKiB());
  EXPECT_EQ(0, bytes.InMiB());
  EXPECT_EQ(0, bytes.InGiB());
  EXPECT_EQ(0, bytes.InBytesUnsigned());
}

TEST(ByteCount, ConstructionByteCount) {
  constexpr ByteCount bytes(1024 * 1024 * 1024);
  EXPECT_EQ(1024 * 1024 * 1024, bytes.InBytes());
  EXPECT_EQ(1024 * 1024, bytes.InKiB());
  EXPECT_EQ(1024, bytes.InMiB());
  EXPECT_EQ(1, bytes.InGiB());
  EXPECT_EQ(1024u * 1024 * 1024, bytes.InBytesUnsigned());
}

TEST(ByteCount, ConstructionUnsigned) {
  auto bytes = ByteCount::FromUnsigned(5u);
  EXPECT_EQ(5, bytes.InBytes());
}

TEST(ByteCountDeathTest, ConstructionUnsignedInvalid) {
  BASE_EXPECT_DEATH(
      ByteCount::FromUnsigned(std::numeric_limits<uint64_t>::max()), "");
}

TEST(ByteCount, ConstructionChecked) {
  auto bytes = ByteCount::FromChecked(CheckedNumeric<uint64_t>(5));
  EXPECT_EQ(5, bytes.InBytes());
}

TEST(ByteCountDeathTest, ConstructionCheckedInvalid) {
  BASE_EXPECT_DEATH(
      ByteCount::FromChecked(
          CheckedNumeric<int64_t>(std::numeric_limits<int64_t>::max()) + 1),
      "");
}

TEST(ByteCount, ConstructionOtherUnitIntegral) {
  // 32-bit numbers that will overflow if multiplied as
  // CheckedNumeric<uint32_t>, but not if multiplied as CheckedNumeric<int64_t>.
  // This verifies that the implementations of the KiB, MiB and GiB templates
  // avoid a subtle conversion order bug.
  constexpr int64_t kLargeKiB32 =
      std::numeric_limits<uint32_t>::max() / 1024 + 1;
  constexpr int64_t kLargeMiB32 =
      std::numeric_limits<uint32_t>::max() / 1024 / 1024 + 1;
  constexpr int64_t kLargeGiB32 =
      std::numeric_limits<uint32_t>::max() / 1024 / 1024 / 1024 + 1;

  static_assert(kLargeKiB32 * 1024 > std::numeric_limits<uint32_t>::max());
  static_assert(kLargeMiB32 * 1024 * 1024 >
                std::numeric_limits<uint32_t>::max());
  static_assert(kLargeGiB32 * 1024 * 1024 * 1024 >
                std::numeric_limits<uint32_t>::max());

  auto kib5 = KiB(5);
  EXPECT_EQ(5 * 1024, kib5.InBytes());
  EXPECT_EQ(kLargeKiB32 * 1024,
            KiB(checked_cast<uint32_t>(kLargeKiB32)).InBytes());

  auto mib5 = MiB(5);
  EXPECT_EQ(5 * 1024 * 1024, mib5.InBytes());
  EXPECT_EQ(kLargeMiB32 * 1024 * 1024,
            MiB(checked_cast<uint32_t>(kLargeMiB32)).InBytes());

  auto gib5 = GiB(5);
  EXPECT_EQ(5ll * 1024 * 1024 * 1024, gib5.InBytes());
  EXPECT_EQ(kLargeGiB32 * 1024 * 1024 * 1024,
            GiB(checked_cast<uint32_t>(kLargeGiB32)).InBytes());
}

TEST(ByteCount, ConstructionOtherUnitFloat) {
  auto kib = KiB(5.5);
  EXPECT_EQ(5632, kib.InBytes());
  EXPECT_EQ(5632.0, kib.InBytesF());

  auto mib = MiB(2.3);
  // Round down from 2411724.8
  EXPECT_EQ(2411724, mib.InBytes());
  EXPECT_EQ(2411724.0, mib.InBytesF());

  auto gib = GiB(12.81);
  // Round down from 13754632765.4
  EXPECT_EQ(13754632765, gib.InBytes());
  EXPECT_EQ(13754632765.0, gib.InBytesF());

  auto negative_kib = KiB(-4.2);
  // Round up from -4300.8
  EXPECT_EQ(-4300, negative_kib.InBytes());
  EXPECT_EQ(-4300.0, negative_kib.InBytesF());

  auto negative_mib = MiB(-9.89);
  // Round up from -10370416.64
  EXPECT_EQ(-10370416, negative_mib.InBytes());
  EXPECT_EQ(-10370416.0, negative_mib.InBytesF());

  auto negative_gib = GiB(-5.17);
  // Round up from -5551245230.08
  EXPECT_EQ(-5551245230, negative_gib.InBytes());
  EXPECT_EQ(-5551245230.0, negative_gib.InBytesF());
}

TEST(ByteCountDeathTest, ConstructionOtherUnitInvalid) {
  BASE_EXPECT_DEATH(KiB(std::numeric_limits<int64_t>::max()), "");

  BASE_EXPECT_DEATH(MiB(std::numeric_limits<int64_t>::max()), "");

  BASE_EXPECT_DEATH(GiB(std::numeric_limits<int64_t>::max()), "");
}

TEST(ByteCount, IsPositive) {
  EXPECT_FALSE(ByteCount(-2).is_positive());
  EXPECT_FALSE(ByteCount(0).is_positive());
  EXPECT_TRUE(ByteCount(2).is_positive());
}

TEST(ByteCount, IsZero) {
  EXPECT_FALSE(ByteCount(-2).is_zero());
  EXPECT_TRUE(ByteCount(0).is_zero());
  EXPECT_FALSE(ByteCount(2).is_zero());
}

TEST(ByteCount, IsNegative) {
  EXPECT_TRUE(ByteCount(-2).is_negative());
  EXPECT_FALSE(ByteCount(0).is_negative());
  EXPECT_FALSE(ByteCount(2).is_negative());
}

TEST(ByteCount, InFloating) {
  constexpr ByteCount bytes(3435973836);
  EXPECT_THAT(bytes.InBytesF(), testing::DoubleEq(3435973836.0));
  EXPECT_THAT(bytes.InKiBF(), testing::DoubleEq(3355443.19921875));
  EXPECT_THAT(bytes.InMiBF(), testing::DoubleEq(3276.7999992370605));
  EXPECT_THAT(bytes.InGiBF(), testing::DoubleEq(3.1999999992549419));
  constexpr ByteCount morebytes(3435973836343597383);
  EXPECT_THAT(morebytes.InTiBF(), testing::DoubleEq(3124999.9995849044));
  EXPECT_THAT(morebytes.InPiBF(), testing::DoubleEq(3051.7578120946332));
  EXPECT_THAT(morebytes.InEiBF(), testing::DoubleEq(2.9802322383736652));
}

TEST(ByteCountDeathTest, InUnsignedInvalid) {
  ByteCount bytes(-2);
  BASE_EXPECT_DEATH(bytes.InBytesUnsigned(), "");
}

TEST(ByteCount, UnarySigns) {
  ByteCount bytes(42);
  EXPECT_EQ(bytes, +bytes);

  ByteCount negative_bytes(-42);
  EXPECT_EQ(-bytes, negative_bytes);
}

TEST(ByteCount, Arithmetic) {
  ByteCount bytes(42);

  ByteCount add = bytes + ByteCount(10);
  EXPECT_EQ(52, add.InBytes());

  ByteCount sub = bytes - ByteCount(10);
  EXPECT_EQ(32, sub.InBytes());

  ByteCount mul = bytes * 10;
  EXPECT_EQ(420, mul.InBytes());

  ByteCount mul2 = 10 * bytes;
  EXPECT_EQ(420, mul2.InBytes());

  ByteCount div = bytes / 2;
  EXPECT_EQ(21, div.InBytes());
}

TEST(ByteCount, ArithmeticCompound) {
  ByteCount bytes(42);

  bytes += ByteCount(10);
  EXPECT_EQ(52, bytes.InBytes());

  bytes -= ByteCount(10);
  EXPECT_EQ(42, bytes.InBytes());

  bytes *= 10;
  EXPECT_EQ(420, bytes.InBytes());

  bytes /= 2;
  EXPECT_EQ(210, bytes.InBytes());
}

TEST(ByteCountDeathTest, ArithmeticInvalid) {
  ByteCount max_bytes(std::numeric_limits<int64_t>::max());

  BASE_EXPECT_DEATH({ max_bytes + max_bytes; }, "");

  BASE_EXPECT_DEATH({ ByteCount() - max_bytes - max_bytes; }, "");

  BASE_EXPECT_DEATH({ max_bytes * 2; }, "");

  BASE_EXPECT_DEATH({ max_bytes / 0; }, "");
}

TEST(ByteCount, Comparison) {
  ByteCount a(1);
  ByteCount b(2);
  ByteCount c(2);

  EXPECT_TRUE(a < b);
  EXPECT_FALSE(b < a);
  EXPECT_FALSE(b < c);

  EXPECT_TRUE(a <= b);
  EXPECT_FALSE(b <= a);
  EXPECT_TRUE(b <= c);

  EXPECT_FALSE(a > b);
  EXPECT_TRUE(b > a);
  EXPECT_FALSE(b > c);

  EXPECT_FALSE(a >= b);
  EXPECT_TRUE(b >= a);
  EXPECT_TRUE(b >= c);

  EXPECT_FALSE(a == b);
  EXPECT_TRUE(b == c);

  EXPECT_TRUE(a != b);
  EXPECT_FALSE(b != c);
}

TEST(ByteCount, StreamOperator) {
  struct TestValue {
    int64_t bytes;
    const char* expected;
  } kTestValues[] = {
      {-1, "-1B"},
      {0, "0B"},
      {1, "1B"},

      {1024 - 1, "1023B"},
      {1024, "1KiB"},
      {1024 + 1, "1025B (1.001KiB)"},
      {-(1024 - 1), "-1023B"},
      {-(1024), "-1KiB"},
      {-(1024 + 1), "-1025B (-1.001KiB)"},

      {1024 * 1024 - 1, "1048575B (1023.999KiB)"},
      {1024 * 1024, "1MiB"},
      {1024 * 1024 + 1'000, "1049576B (1.001MiB)"},
      {-(1024 * 1024 - 1), "-1048575B (-1023.999KiB)"},
      {-(1024 * 1024), "-1MiB"},
      {-(1024 * 1024 + 1'000), "-1049576B (-1.001MiB)"},

      {1024LL * 1024 * 1024 - 1'000, "1073740824B (1023.999MiB)"},
      {1024LL * 1024 * 1024, "1GiB"},
      {1024LL * 1024 * 1024 + 1'000'000, "1074741824B (1.001GiB)"},

      {1024LL * 1024 * 1024 * 1024 - 1'000'000, "1099510627776B (1023.999GiB)"},
      {1024LL * 1024 * 1024 * 1024, "1TiB"},
      {1024LL * 1024 * 1024 * 1024 + 1'000'000'000,
       "1100511627776B (1.001TiB)"},

      {1024LL * 1024 * 1024 * 1024 * 1024 - 1'000'000'000,
       "1125898906842624B (1023.999TiB)"},
      {1024LL * 1024 * 1024 * 1024 * 1024, "1PiB"},
      {1024LL * 1024 * 1024 * 1024 * 1024 + 1'000'000'000'000,
       "1126899906842624B (1.001PiB)"},

      {1024LL * 1024 * 1024 * 1024 * 1024 * 1024 - 1'000'000'000'000,
       "1152920504606846976B (1023.999PiB)"},
      {1024LL * 1024 * 1024 * 1024 * 1024 * 1024, "1EiB"},
      {1024LL * 1024 * 1024 * 1024 * 1024 * 1024 + 1'000'000'000'000'000,
       "1153921504606846976B (1.001EiB)"},
      {-(1024LL * 1024 * 1024 * 1024 * 1024 * 1024 - 1'000'000'000'000),
       "-1152920504606846976B (-1023.999PiB)"},
      {-(1024LL * 1024 * 1024 * 1024 * 1024 * 1024), "-1EiB"},
      {-(1024LL * 1024 * 1024 * 1024 * 1024 * 1024 + 1'000'000'000'000'000),
       "-1153921504606846976B (-1.001EiB)"},

      {ByteCount::Max().InBytes(), "9223372036854775807B (8.000EiB)"},
      {std::numeric_limits<int64_t>::min(), "-8EiB"},
      {std::numeric_limits<int64_t>::min() + 1,
       "-9223372036854775807B (-8.000EiB)"},
  };
  for (const auto& test_value : kTestValues) {
    std::stringstream ss;
    ss << ByteCount(test_value.bytes);
    EXPECT_EQ(test_value.expected, ss.str());
  }
}

}  // namespace base