blob: b1702c27189eda669d8a23508db9fd500205ed72 [file]
// Copyright 2026 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/fxcrt/fx_ceil_div.h"
#include <stdint.h>
#include <limits>
#include "core/fxcrt/fx_safe_types.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace fxcrt {
static_assert(CeilDiv(0, 8) == 0);
static_assert(CeilDiv(1, 8) == 1);
static_assert(CeilDiv(8, 8) == 1);
static_assert(CeilDiv(9, 8) == 2);
TEST(CeilDiv, Exact) {
EXPECT_EQ(0, CeilDiv(0, 4));
EXPECT_EQ(1, CeilDiv(4, 4));
EXPECT_EQ(2, CeilDiv(8, 4));
EXPECT_EQ(25, CeilDiv(100, 4));
}
TEST(CeilDiv, RoundsUp) {
EXPECT_EQ(1, CeilDiv(1, 4));
EXPECT_EQ(1, CeilDiv(3, 4));
EXPECT_EQ(2, CeilDiv(5, 4));
EXPECT_EQ(2, CeilDiv(7, 4));
}
TEST(CeilDiv, DivisorOfOne) {
EXPECT_EQ(0, CeilDiv(0, 1));
EXPECT_EQ(7, CeilDiv(7, 1));
}
TEST(CeilDiv, NegativeDividend) {
// Rounding towards positive infinity, i.e. towards zero here.
EXPECT_EQ(0, CeilDiv(-1, 4));
EXPECT_EQ(0, CeilDiv(-3, 4));
EXPECT_EQ(-1, CeilDiv(-4, 4));
EXPECT_EQ(-1, CeilDiv(-7, 4));
EXPECT_EQ(-2, CeilDiv(-8, 4));
}
TEST(CeilDiv, NoOverflowNearMax) {
constexpr uint32_t kMax32 = std::numeric_limits<uint32_t>::max();
EXPECT_EQ(kMax32 / 8 + 1, CeilDiv(kMax32, 8));
EXPECT_EQ(kMax32, CeilDiv(kMax32, 1));
constexpr int32_t kMaxSigned32 = std::numeric_limits<int32_t>::max();
EXPECT_EQ(kMaxSigned32 / 8 + 1, CeilDiv(kMaxSigned32, 8));
constexpr int32_t kMinSigned32 = std::numeric_limits<int32_t>::min();
EXPECT_EQ(kMinSigned32 / 8, CeilDiv(kMinSigned32, 8));
constexpr uint64_t kMax64 = std::numeric_limits<uint64_t>::max();
EXPECT_EQ(kMax64 / 8 + 1, CeilDiv(kMax64, 8));
}
// The divisor is not deduced, so an untyped literal picks up the dividend's
// type instead of promoting the result to int.
TEST(CeilDiv, NarrowTypes) {
constexpr uint8_t kMax8 = std::numeric_limits<uint8_t>::max();
static_assert(std::is_same_v<decltype(CeilDiv(kMax8, 2)), uint8_t>);
EXPECT_EQ(128, CeilDiv(kMax8, 2));
EXPECT_EQ(3, CeilDiv(uint8_t{5}, 2));
constexpr uint16_t kMax16 = std::numeric_limits<uint16_t>::max();
EXPECT_EQ(32768, CeilDiv(kMax16, 2));
}
TEST(CeilDiv, CheckedType) {
FX_SAFE_UINT32 value = 9;
EXPECT_EQ(2u, CeilDiv(value, 8).ValueOrDie());
FX_SAFE_SIZE_T size = 16;
EXPECT_EQ(2u, CeilDiv(size, 8).ValueOrDie());
}
TEST(CeilDiv, CheckedTypePropagatesInvalid) {
FX_SAFE_UINT32 invalid = std::numeric_limits<uint32_t>::max();
invalid *= 2;
EXPECT_FALSE(CeilDiv(invalid, 8).IsValid());
}
TEST(CeilDiv, CheckedTypeNoOverflowNearMax) {
// Dividing cannot overflow, so a valid dividend stays valid no matter how
// close to the maximum it is.
constexpr uint32_t kMax32 = std::numeric_limits<uint32_t>::max();
FX_SAFE_UINT32 near_max = kMax32;
EXPECT_EQ(kMax32 / 8 + 1, CeilDiv(near_max, 8).ValueOrDie());
}
} // namespace fxcrt