// Copyright 2026 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/base/api.h"
#include "iree/testing/gtest.h"
#include "iree/testing/status_matchers.h"

namespace {

using ::iree::Status;
using ::iree::StatusCode;
using ::iree::testing::status::IsOk;
using ::iree::testing::status::StatusIs;

//===----------------------------------------------------------------------===//
// Checked arithmetic tests - iree_host_size_t
//===----------------------------------------------------------------------===//

TEST(CheckedArithmetic, AddNoOverflow) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_add(100, 200, &result));
  EXPECT_EQ(result, 300);
}

TEST(CheckedArithmetic, AddOverflowMax) {
  iree_host_size_t result;
  EXPECT_FALSE(iree_host_size_checked_add(IREE_HOST_SIZE_MAX, 1, &result));
}

TEST(CheckedArithmetic, AddOverflowLarge) {
  iree_host_size_t result;
  EXPECT_FALSE(iree_host_size_checked_add(IREE_HOST_SIZE_MAX - 10,
                                          IREE_HOST_SIZE_MAX - 10, &result));
}

TEST(CheckedArithmetic, AddZero) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_add(0, 0, &result));
  EXPECT_EQ(result, 0);
}

TEST(CheckedArithmetic, AddMaxPlusZero) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_add(IREE_HOST_SIZE_MAX, 0, &result));
  EXPECT_EQ(result, IREE_HOST_SIZE_MAX);
}

TEST(CheckedArithmetic, MulNoOverflow) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_mul(100, 200, &result));
  EXPECT_EQ(result, 20000);
}

TEST(CheckedArithmetic, MulOverflowMaxTimesTwo) {
  iree_host_size_t result;
  EXPECT_FALSE(iree_host_size_checked_mul(IREE_HOST_SIZE_MAX, 2, &result));
}

TEST(CheckedArithmetic, MulOverflowLarge) {
  iree_host_size_t result;
  EXPECT_FALSE(iree_host_size_checked_mul(IREE_HOST_SIZE_MAX / 2 + 1,
                                          IREE_HOST_SIZE_MAX / 2 + 1, &result));
}

TEST(CheckedArithmetic, MulZeroFirst) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_mul(0, IREE_HOST_SIZE_MAX, &result));
  EXPECT_EQ(result, 0);
}

TEST(CheckedArithmetic, MulZeroSecond) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_mul(IREE_HOST_SIZE_MAX, 0, &result));
  EXPECT_EQ(result, 0);
}

TEST(CheckedArithmetic, MulOneFirst) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_mul(1, IREE_HOST_SIZE_MAX, &result));
  EXPECT_EQ(result, IREE_HOST_SIZE_MAX);
}

TEST(CheckedArithmetic, MulOneSecond) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_mul(IREE_HOST_SIZE_MAX, 1, &result));
  EXPECT_EQ(result, IREE_HOST_SIZE_MAX);
}

TEST(CheckedArithmetic, MulAddNoOverflow) {
  iree_host_size_t result;
  // 100 + 10 * 20 = 300
  EXPECT_TRUE(iree_host_size_checked_mul_add(100, 10, 20, &result));
  EXPECT_EQ(result, 300);
}

TEST(CheckedArithmetic, MulAddMulOverflow) {
  iree_host_size_t result;
  // 0 + MAX * 2 overflows in multiplication
  EXPECT_FALSE(
      iree_host_size_checked_mul_add(0, IREE_HOST_SIZE_MAX, 2, &result));
}

TEST(CheckedArithmetic, MulAddAddOverflow) {
  iree_host_size_t result;
  // MAX + 1 * 1 overflows in addition
  EXPECT_FALSE(
      iree_host_size_checked_mul_add(IREE_HOST_SIZE_MAX, 1, 1, &result));
}

TEST(CheckedArithmetic, MulAddZeroCount) {
  iree_host_size_t result;
  // 100 + 0 * 1000 = 100
  EXPECT_TRUE(iree_host_size_checked_mul_add(100, 0, 1000, &result));
  EXPECT_EQ(result, 100);
}

TEST(CheckedArithmetic, AlignNoOverflow) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_align(100, 16, &result));
  EXPECT_EQ(result, 112);
}

TEST(CheckedArithmetic, AlignAlreadyAligned) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_align(128, 16, &result));
  EXPECT_EQ(result, 128);
}

TEST(CheckedArithmetic, AlignZero) {
  iree_host_size_t result;
  EXPECT_TRUE(iree_host_size_checked_align(0, 16, &result));
  EXPECT_EQ(result, 0);
}

TEST(CheckedArithmetic, AlignOverflow) {
  iree_host_size_t result;
  // MAX - 5 + 15 (alignment-1) would overflow.
  EXPECT_FALSE(
      iree_host_size_checked_align(IREE_HOST_SIZE_MAX - 5, 16, &result));
}

TEST(CheckedArithmetic, AlignNearMaxNoOverflow) {
  iree_host_size_t result;
  // Value that is already aligned at MAX boundary should work.
  iree_host_size_t max_aligned = IREE_HOST_SIZE_MAX & ~(iree_host_size_t)15;
  EXPECT_TRUE(iree_host_size_checked_align(max_aligned, 16, &result));
  EXPECT_EQ(result, max_aligned);
}

//===----------------------------------------------------------------------===//
// Checked arithmetic tests - iree_device_size_t
//===----------------------------------------------------------------------===//

TEST(CheckedArithmeticDevice, AddNoOverflow) {
  iree_device_size_t result;
  EXPECT_TRUE(iree_device_size_checked_add(100, 200, &result));
  EXPECT_EQ(result, 300);
}

TEST(CheckedArithmeticDevice, AddOverflow) {
  iree_device_size_t result;
  EXPECT_FALSE(iree_device_size_checked_add(IREE_DEVICE_SIZE_MAX, 1, &result));
}

TEST(CheckedArithmeticDevice, MulNoOverflow) {
  iree_device_size_t result;
  EXPECT_TRUE(iree_device_size_checked_mul(100, 200, &result));
  EXPECT_EQ(result, 20000);
}

TEST(CheckedArithmeticDevice, MulOverflow) {
  iree_device_size_t result;
  EXPECT_FALSE(iree_device_size_checked_mul(IREE_DEVICE_SIZE_MAX, 2, &result));
}

TEST(CheckedArithmeticDevice, MulAddNoOverflow) {
  iree_device_size_t result;
  EXPECT_TRUE(iree_device_size_checked_mul_add(100, 10, 20, &result));
  EXPECT_EQ(result, 300);
}

//===----------------------------------------------------------------------===//
// Array allocation tests
//===----------------------------------------------------------------------===//

TEST(AllocatorArray, MallocArrayBasic) {
  void* ptr = nullptr;
  IREE_EXPECT_OK(
      iree_allocator_malloc_array(iree_allocator_system(), 10, 8, &ptr));
  ASSERT_NE(ptr, nullptr);
  // Verify memory is zeroed.
  for (int i = 0; i < 80; ++i) {
    EXPECT_EQ(static_cast<uint8_t*>(ptr)[i], 0);
  }
  iree_allocator_free(iree_allocator_system(), ptr);
}

TEST(AllocatorArray, MallocArrayOverflow) {
  void* ptr = nullptr;
  EXPECT_THAT(Status(iree_allocator_malloc_array(iree_allocator_system(),
                                                 IREE_HOST_SIZE_MAX, 2, &ptr)),
              StatusIs(StatusCode::kOutOfRange));
}

TEST(AllocatorArray, MallocArrayZeroCount) {
  void* ptr = nullptr;
  // Zero count results in zero bytes, which IREE's allocator rejects.
  EXPECT_THAT(
      Status(iree_allocator_malloc_array(iree_allocator_system(), 0, 8, &ptr)),
      StatusIs(StatusCode::kInvalidArgument));
}

TEST(AllocatorArray, MallocArrayUninitializedBasic) {
  void* ptr = nullptr;
  IREE_EXPECT_OK(iree_allocator_malloc_array_uninitialized(
      iree_allocator_system(), 10, 8, &ptr));
  ASSERT_NE(ptr, nullptr);
  iree_allocator_free(iree_allocator_system(), ptr);
}

TEST(AllocatorArray, MallocArrayUninitializedOverflow) {
  void* ptr = nullptr;
  EXPECT_THAT(Status(iree_allocator_malloc_array_uninitialized(
                  iree_allocator_system(), IREE_HOST_SIZE_MAX, 2, &ptr)),
              StatusIs(StatusCode::kOutOfRange));
}

TEST(AllocatorArray, ReallocArrayBasic) {
  void* ptr = nullptr;
  IREE_EXPECT_OK(
      iree_allocator_malloc_array(iree_allocator_system(), 10, 8, &ptr));
  ASSERT_NE(ptr, nullptr);
  IREE_EXPECT_OK(
      iree_allocator_realloc_array(iree_allocator_system(), 20, 8, &ptr));
  ASSERT_NE(ptr, nullptr);
  iree_allocator_free(iree_allocator_system(), ptr);
}

TEST(AllocatorArray, ReallocArrayOverflow) {
  void* ptr = nullptr;
  IREE_EXPECT_OK(
      iree_allocator_malloc_array(iree_allocator_system(), 10, 8, &ptr));
  ASSERT_NE(ptr, nullptr);
  void* original_ptr = ptr;
  EXPECT_THAT(Status(iree_allocator_realloc_array(iree_allocator_system(),
                                                  IREE_HOST_SIZE_MAX, 2, &ptr)),
              StatusIs(StatusCode::kOutOfRange));
  // Original pointer should be unchanged on failure.
  EXPECT_EQ(ptr, original_ptr);
  iree_allocator_free(iree_allocator_system(), ptr);
}

//===----------------------------------------------------------------------===//
// Struct+trailing allocation tests
//===----------------------------------------------------------------------===//

TEST(AllocatorStruct, MallocWithTrailingBasic) {
  void* ptr = nullptr;
  IREE_EXPECT_OK(iree_allocator_malloc_with_trailing(iree_allocator_system(),
                                                     64, 128, &ptr));
  ASSERT_NE(ptr, nullptr);
  iree_allocator_free(iree_allocator_system(), ptr);
}

TEST(AllocatorStruct, MallocWithTrailingOverflow) {
  void* ptr = nullptr;
  // Use values that sum to overflow (each > MAX/2).
  EXPECT_THAT(Status(iree_allocator_malloc_with_trailing(
                  iree_allocator_system(), IREE_HOST_SIZE_MAX / 2 + 100,
                  IREE_HOST_SIZE_MAX / 2 + 100, &ptr)),
              StatusIs(StatusCode::kOutOfRange));
}

TEST(AllocatorStruct, MallocStructArrayBasic) {
  void* ptr = nullptr;
  IREE_EXPECT_OK(iree_allocator_malloc_struct_array(iree_allocator_system(), 64,
                                                    10, 8, &ptr));
  ASSERT_NE(ptr, nullptr);
  iree_allocator_free(iree_allocator_system(), ptr);
}

TEST(AllocatorStruct, MallocStructArrayOverflow) {
  void* ptr = nullptr;
  EXPECT_THAT(Status(iree_allocator_malloc_struct_array(
                  iree_allocator_system(), 64, IREE_HOST_SIZE_MAX, 2, &ptr)),
              StatusIs(StatusCode::kOutOfRange));
}

//===----------------------------------------------------------------------===//
// iree_allocator_grow_array tests
//===----------------------------------------------------------------------===//

TEST(GrowArray, BasicGrowth) {
  uint64_t* ptr = nullptr;
  iree_host_size_t capacity = 0;
  // Initial allocation from 0 capacity with minimum of 8.
  IREE_EXPECT_OK(iree_allocator_grow_array(
      iree_allocator_system(), 8, sizeof(uint64_t), &capacity, (void**)&ptr));
  EXPECT_EQ(capacity, 8u);
  EXPECT_NE(ptr, nullptr);

  // Write to verify allocation is valid.
  for (iree_host_size_t i = 0; i < capacity; ++i) {
    ptr[i] = i * 100;
  }

  // Grow from 8 to 16 (doubled).
  IREE_EXPECT_OK(iree_allocator_grow_array(
      iree_allocator_system(), 8, sizeof(uint64_t), &capacity, (void**)&ptr));
  EXPECT_EQ(capacity, 16u);

  // Verify old data preserved (realloc semantics).
  for (iree_host_size_t i = 0; i < 8; ++i) {
    EXPECT_EQ(ptr[i], i * 100);
  }

  iree_allocator_free(iree_allocator_system(), ptr);
}

TEST(GrowArray, MinimumCapacityWins) {
  uint64_t* ptr = nullptr;
  iree_host_size_t capacity = 4;
  // Pre-allocate with capacity 4.
  IREE_EXPECT_OK(iree_allocator_malloc_array(iree_allocator_system(), capacity,
                                             sizeof(uint64_t), (void**)&ptr));
  // Grow: max(32, 4*2=8) = 32.
  IREE_EXPECT_OK(iree_allocator_grow_array(
      iree_allocator_system(), 32, sizeof(uint64_t), &capacity, (void**)&ptr));
  EXPECT_EQ(capacity, 32u);
  iree_allocator_free(iree_allocator_system(), ptr);
}

TEST(GrowArray, DoubleWins) {
  uint64_t* ptr = nullptr;
  iree_host_size_t capacity = 100;
  // Pre-allocate with capacity 100.
  IREE_EXPECT_OK(iree_allocator_malloc_array(iree_allocator_system(), capacity,
                                             sizeof(uint64_t), (void**)&ptr));
  // Grow: max(8, 100*2=200) = 200.
  IREE_EXPECT_OK(iree_allocator_grow_array(
      iree_allocator_system(), 8, sizeof(uint64_t), &capacity, (void**)&ptr));
  EXPECT_EQ(capacity, 200u);
  iree_allocator_free(iree_allocator_system(), ptr);
}

TEST(GrowArray, OverflowOnDouble) {
  void* ptr = nullptr;
  iree_host_size_t capacity = IREE_HOST_SIZE_MAX;
  EXPECT_THAT(
      Status(iree_allocator_grow_array(iree_allocator_system(), 8,
                                       sizeof(uint64_t), &capacity, &ptr)),
      StatusIs(StatusCode::kOutOfRange));
}

//===----------------------------------------------------------------------===//
// IREE_STRUCT_LAYOUT tests
//===----------------------------------------------------------------------===//

struct TestHeader {
  void* vtable;
  uint64_t flags;
};

struct TestElement {
  uint64_t data[4];
};

TEST(StructLayout, BasicTwoFields) {
  iree_host_size_t total = 0;
  iree_host_size_t field1_offset = 0;
  iree_host_size_t field2_offset = 0;
  IREE_EXPECT_OK(
      IREE_STRUCT_LAYOUT(sizeof(TestHeader), &total,
                         IREE_STRUCT_FIELD(10, TestElement, &field1_offset),
                         IREE_STRUCT_FIELD(5, uint64_t, &field2_offset)));

  EXPECT_EQ(field1_offset, sizeof(TestHeader));
  EXPECT_EQ(field2_offset, sizeof(TestHeader) + 10 * sizeof(TestElement));
  EXPECT_EQ(total, sizeof(TestHeader) + 10 * sizeof(TestElement) +
                       5 * sizeof(uint64_t));
}

TEST(StructLayout, AlignedFields) {
  iree_host_size_t total = 0;
  iree_host_size_t header_offset = 0;
  iree_host_size_t data_offset = 0;
  IREE_EXPECT_OK(IREE_STRUCT_LAYOUT(
      0, &total, IREE_STRUCT_FIELD_ALIGNED(1, TestHeader, 16, &header_offset),
      IREE_STRUCT_FIELD_ALIGNED(100, uint8_t, 64, &data_offset)));

  EXPECT_EQ(header_offset, 0u);
  // TestHeader is 16 bytes, data should be at offset 64 (aligned).
  EXPECT_EQ(data_offset, 64u);
  EXPECT_EQ(total, 64u + 100u);
}

TEST(StructLayout, NullOffsetPointer) {
  iree_host_size_t total = 0;
  IREE_EXPECT_OK(IREE_STRUCT_LAYOUT(sizeof(TestHeader), &total,
                                    IREE_STRUCT_FIELD(10, TestElement, NULL),
                                    IREE_STRUCT_FIELD(5, uint64_t, NULL)));
  EXPECT_EQ(total, sizeof(TestHeader) + 10 * sizeof(TestElement) +
                       5 * sizeof(uint64_t));
}

TEST(StructLayout, ZeroCountField) {
  iree_host_size_t total = 0;
  iree_host_size_t offset = 0;
  IREE_EXPECT_OK(IREE_STRUCT_LAYOUT(
      sizeof(TestHeader), &total, IREE_STRUCT_FIELD(0, TestElement, &offset)));
  EXPECT_EQ(offset, sizeof(TestHeader));
  EXPECT_EQ(total, sizeof(TestHeader));
}

TEST(StructLayout, OverflowOnMultiply) {
  iree_host_size_t total = 0;
  IREE_EXPECT_STATUS_IS(
      IREE_STATUS_OUT_OF_RANGE,
      IREE_STRUCT_LAYOUT(0, &total,
                         IREE_STRUCT_FIELD(SIZE_MAX, TestElement, NULL)));
}

TEST(StructLayout, OverflowOnAdd) {
  iree_host_size_t total = 0;
  IREE_EXPECT_STATUS_IS(
      IREE_STATUS_OUT_OF_RANGE,
      IREE_STRUCT_LAYOUT(SIZE_MAX - 10, &total,
                         IREE_STRUCT_FIELD(100, uint8_t, NULL)));
}

TEST(StructLayout, SingleField) {
  iree_host_size_t total = 0;
  iree_host_size_t offset = 0;
  IREE_EXPECT_OK(IREE_STRUCT_LAYOUT(
      sizeof(TestHeader), &total, IREE_STRUCT_FIELD(64, TestElement, &offset)));
  EXPECT_EQ(offset, sizeof(TestHeader));
  EXPECT_EQ(total, sizeof(TestHeader) + 64 * sizeof(TestElement));
}

TEST(StructLayout, ThreeFields) {
  iree_host_size_t total = 0;
  iree_host_size_t offset1 = 0, offset2 = 0, offset3 = 0;
  IREE_EXPECT_OK(IREE_STRUCT_LAYOUT(sizeof(TestHeader), &total,
                                    IREE_STRUCT_FIELD(10, uint8_t, &offset1),
                                    IREE_STRUCT_FIELD(20, uint16_t, &offset2),
                                    IREE_STRUCT_FIELD(30, uint32_t, &offset3)));
  EXPECT_EQ(offset1, sizeof(TestHeader));
  EXPECT_EQ(offset2, sizeof(TestHeader) + 10);
  EXPECT_EQ(offset3, sizeof(TestHeader) + 10 + 40);
  EXPECT_EQ(total, sizeof(TestHeader) + 10 + 40 + 120);
}

//===----------------------------------------------------------------------===//
// iree_allocator_malloc_aligned tests
//===----------------------------------------------------------------------===//

TEST(AllocatorAligned, MallocBasic) {
  void* ptr = nullptr;
  IREE_EXPECT_OK(
      iree_allocator_malloc_aligned(iree_allocator_system(), 128, 64, 0, &ptr));
  ASSERT_NE(ptr, nullptr);
  // Verify alignment.
  EXPECT_EQ(reinterpret_cast<uintptr_t>(ptr) % 64, 0u);
  // Verify memory is zeroed.
  for (int i = 0; i < 128; ++i) {
    EXPECT_EQ(static_cast<uint8_t*>(ptr)[i], 0);
  }
  iree_allocator_free_aligned(iree_allocator_system(), ptr);
}

TEST(AllocatorAligned, MallocLargeAlignment) {
  void* ptr = nullptr;
  // Test with 4096-byte (page) alignment.
  IREE_EXPECT_OK(iree_allocator_malloc_aligned(iree_allocator_system(), 256,
                                               4096, 0, &ptr));
  ASSERT_NE(ptr, nullptr);
  EXPECT_EQ(reinterpret_cast<uintptr_t>(ptr) % 4096, 0u);
  iree_allocator_free_aligned(iree_allocator_system(), ptr);
}

TEST(AllocatorAligned, MallocWithOffset) {
  // Allocate with an offset so that a specific byte is aligned.
  void* ptr = nullptr;
  iree_host_size_t offset = 32;
  IREE_EXPECT_OK(iree_allocator_malloc_aligned(iree_allocator_system(), 256, 64,
                                               offset, &ptr));
  ASSERT_NE(ptr, nullptr);
  // The byte at 'offset' from ptr should be 64-byte aligned.
  EXPECT_EQ((reinterpret_cast<uintptr_t>(ptr) + offset) % 64, 0u);
  iree_allocator_free_aligned(iree_allocator_system(), ptr);
}

TEST(AllocatorAligned, ReallocGrow) {
  void* ptr = nullptr;
  IREE_EXPECT_OK(
      iree_allocator_malloc_aligned(iree_allocator_system(), 64, 64, 0, &ptr));
  ASSERT_NE(ptr, nullptr);

  // Write pattern to verify data preservation.
  for (int i = 0; i < 64; ++i) {
    static_cast<uint8_t*>(ptr)[i] = static_cast<uint8_t>(i);
  }

  // Grow the allocation.
  IREE_EXPECT_OK(iree_allocator_realloc_aligned(iree_allocator_system(), 256,
                                                64, 0, &ptr));
  ASSERT_NE(ptr, nullptr);
  EXPECT_EQ(reinterpret_cast<uintptr_t>(ptr) % 64, 0u);

  // Verify original data preserved.
  for (int i = 0; i < 64; ++i) {
    EXPECT_EQ(static_cast<uint8_t*>(ptr)[i], static_cast<uint8_t>(i));
  }

  iree_allocator_free_aligned(iree_allocator_system(), ptr);
}

TEST(AllocatorAligned, ReallocShrink) {
  void* ptr = nullptr;
  IREE_EXPECT_OK(
      iree_allocator_malloc_aligned(iree_allocator_system(), 256, 64, 0, &ptr));
  ASSERT_NE(ptr, nullptr);

  // Write pattern.
  for (int i = 0; i < 64; ++i) {
    static_cast<uint8_t*>(ptr)[i] = static_cast<uint8_t>(i);
  }

  // Shrink the allocation.
  IREE_EXPECT_OK(
      iree_allocator_realloc_aligned(iree_allocator_system(), 64, 64, 0, &ptr));
  ASSERT_NE(ptr, nullptr);
  EXPECT_EQ(reinterpret_cast<uintptr_t>(ptr) % 64, 0u);

  // Verify data preserved in the retained region.
  for (int i = 0; i < 64; ++i) {
    EXPECT_EQ(static_cast<uint8_t*>(ptr)[i], static_cast<uint8_t>(i));
  }

  iree_allocator_free_aligned(iree_allocator_system(), ptr);
}

TEST(AllocatorAligned, ReallocFromNull) {
  void* ptr = nullptr;
  // Realloc with NULL acts like malloc.
  IREE_EXPECT_OK(iree_allocator_realloc_aligned(iree_allocator_system(), 128,
                                                64, 0, &ptr));
  ASSERT_NE(ptr, nullptr);
  EXPECT_EQ(reinterpret_cast<uintptr_t>(ptr) % 64, 0u);
  iree_allocator_free_aligned(iree_allocator_system(), ptr);
}

TEST(AllocatorAligned, InvalidAlignment) {
  void* ptr = nullptr;
  // Non-power-of-two alignment should fail.
  EXPECT_THAT(Status(iree_allocator_malloc_aligned(iree_allocator_system(), 128,
                                                   63, 0, &ptr)),
              StatusIs(StatusCode::kInvalidArgument));
}

TEST(AllocatorAligned, ZeroSize) {
  void* ptr = nullptr;
  // Zero-size allocation should fail.
  EXPECT_THAT(Status(iree_allocator_malloc_aligned(iree_allocator_system(), 0,
                                                   64, 0, &ptr)),
              StatusIs(StatusCode::kInvalidArgument));
}

TEST(AllocatorAligned, OverflowCheck) {
  void* ptr = nullptr;
  // Request a size that would overflow when adding alignment padding.
  EXPECT_THAT(
      Status(iree_allocator_malloc_aligned(
          iree_allocator_system(), IREE_HOST_SIZE_MAX - 10, 64, 0, &ptr)),
      StatusIs(StatusCode::kOutOfRange));
}

}  // namespace
