text: /**
   * @file unit-SubarrayPartitioner-dense.cc
   *
   * @section LICENSE
   *
   * The MIT License
   *
   * @copyright Copyright (c) 2017-2019 TileDB, Inc.
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   * THE SOFTWARE.
   *
   * @section DESCRIPTION
   *
   * Tests the `SubarrayPartitioner` class for dense arrays.
   */
  
  #include "test/src/helpers.h"
  #include "tiledb/sm/c_api/tiledb_struct_def.h"
  #include "tiledb/sm/subarray/subarray_partitioner.h"
  
  #ifdef _WIN32
  #include "tiledb/sm/filesystem/win.h"
  #else
  #include "tiledb/sm/filesystem/posix.h"
  #endif
  
  #include <catch.hpp>
  #include <iostream>
  
  using namespace tiledb::sm;
  
  /* ********************************* */
  /*         STRUCT DEFINITION         */
  /* ********************************* */
  
  struct SubarrayPartitionerDenseFx {
    tiledb_ctx_t* ctx_;
    tiledb_vfs_t* vfs_;
    bool s3_supported_, hdfs_supported_;
    std::string temp_dir_;
    const std::string s3_bucket_name_ =
        "s3://" + random_bucket_name("tiledb") + "/";
    std::string array_name_;
    const char* ARRAY_NAME = "subarray_partitioner_dense";
    tiledb_array_t* array_ = nullptr;
  
    SubarrayPartitionerDenseFx();
    ~SubarrayPartitionerDenseFx();
  
    /**
     * Helper function that creates a default 1D array, with the
     * input tile and cell order.
     */
    void create_default_1d_array(
        tiledb_layout_t tile_order, tiledb_layout_t cell_order);
  
    /**
     * Helper function that creates a default 2D array, with the
     * input tile and cell order.
     */
    void create_default_2d_array(
        tiledb_layout_t tile_order, tiledb_layout_t cell_order);
  
    /** Helper function that writes to the default 1D array. */
    void write_default_1d_array();
  
    /** Helper function that writes to the default 2D array. */
    void write_default_2d_array();
  
    /**
     * Helper function to test the subarray partitioner for the given arguments.
     */
    template <class T>
    void test_subarray_partitioner(
        Layout subarray_layout,
        const SubarrayRanges<T>& ranges,
        const std::vector<SubarrayRanges<T>>& partitions,
        const std::string& attr,  // Attribute to set the budget for
        uint64_t budget,
        bool unsplittable = false);
  
    /**
     * Helper function to test the subarray partitioner for the given arguments.
     * This is different from the above in that it tests the memory
     * budget.
     */
    template <class T>
    void test_subarray_partitioner(
        Layout subarray_layout,
        const SubarrayRanges<T>& ranges,
        const std::vector<SubarrayRanges<T>>& partitions,
        uint64_t budget,
        uint64_t budget_var,
        bool unsplittable = false);
  };
  
  SubarrayPartitionerDenseFx::SubarrayPartitionerDenseFx() {
    ctx_ = nullptr;
    vfs_ = nullptr;
    hdfs_supported_ = false;
    s3_supported_ = false;
  
    get_supported_fs(&s3_supported_, &hdfs_supported_);
    create_ctx_and_vfs(s3_supported_, &ctx_, &vfs_);
    create_s3_bucket(s3_bucket_name_, s3_supported_, ctx_, vfs_);
  
  // Create temporary directory based on the supported filesystem
  #ifdef _WIN32
    temp_dir_ = tiledb::sm::Win::current_dir() + "\\tiledb_test\\";
  #else
    temp_dir_ = "file://" + tiledb::sm::Posix::current_dir() + "/tiledb_test/";
  #endif
    if (s3_supported_)
      temp_dir_ = s3_bucket_name_ + "tiledb/test/";
    // Disabling this for now, as this test takes a long time on HDFS
    // if (hdfs_supported_)
    //  temp_dir_ = "hdfs:///tiledb_test/";
  
    create_dir(temp_dir_, ctx_, vfs_);
  
    array_name_ = temp_dir_ + ARRAY_NAME;
    int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array_);
    CHECK(rc == TILEDB_OK);
  }
  
  SubarrayPartitionerDenseFx::~SubarrayPartitionerDenseFx() {
    tiledb_array_free(&array_);
    remove_dir(temp_dir_, ctx_, vfs_);
    tiledb_ctx_free(&ctx_);
    tiledb_vfs_free(&vfs_);
  }
  
  void SubarrayPartitionerDenseFx::create_default_1d_array(
      tiledb_layout_t tile_order, tiledb_layout_t cell_order) {
    uint64_t domain[] = {1, 10};
    uint64_t tile_extent = 2;
    create_array(
        ctx_,
        array_name_,
        TILEDB_DENSE,
        {"d"},
        {TILEDB_UINT64},
        {domain},
        {&tile_extent},
        {"a", "b"},
        {TILEDB_INT32, TILEDB_INT32},
        {1, TILEDB_VAR_NUM},
        {::Compressor(TILEDB_FILTER_LZ4, -1),
         ::Compressor(TILEDB_FILTER_LZ4, -1)},
        tile_order,
        cell_order,
        2);
  }
  
  void SubarrayPartitionerDenseFx::create_default_2d_array(
      tiledb_layout_t tile_order, tiledb_layout_t cell_order) {
    uint64_t domain[] = {1, 4};
    uint64_t tile_extent = 2;
    create_array(
        ctx_,
        array_name_,
        TILEDB_DENSE,
        {"d1", "d2"},
        {TILEDB_UINT64, TILEDB_UINT64},
        {domain, domain},
        {&tile_extent, &tile_extent},
        {"a", "b"},
        {TILEDB_INT32, TILEDB_INT32},
        {1, TILEDB_VAR_NUM},
        {::Compressor(TILEDB_FILTER_LZ4, -1),
         ::Compressor(TILEDB_FILTER_LZ4, -1)},
        tile_order,
        cell_order,
        2);
  }
  
  void SubarrayPartitionerDenseFx::write_default_1d_array() {
    AttrBuffers attr_buffers;
    std::vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    uint64_t a_size = a.size() * sizeof(int);
    std::vector<uint64_t> b_off = {0,
                                   sizeof(int),
                                   3 * sizeof(int),
                                   6 * sizeof(int),
                                   9 * sizeof(int),
                                   11 * sizeof(int),
                                   15 * sizeof(int),
                                   16 * sizeof(int),
                                   17 * sizeof(int),
                                   18 * sizeof(int)};
    uint64_t b_off_size = b_off.size() * sizeof(uint64_t);
    std::vector<int> b_val = {
        1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 6, 7, 8, 9, 10};
    uint64_t b_val_size = b_val.size() * sizeof(int);
    attr_buffers["a"] = AttrBuffer({&a[0], a_size, nullptr, 0});
    attr_buffers["b"] =
        AttrBuffer({&b_off[0], b_off_size, &b_val[0], b_val_size});
    write_array(ctx_, array_name_, TILEDB_GLOBAL_ORDER, attr_buffers);
  }
  
  void SubarrayPartitionerDenseFx::write_default_2d_array() {
    AttrBuffers attr_buffers;
    std::vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
    uint64_t a_size = a.size() * sizeof(int);
    std::vector<uint64_t> b_off = {0,
                                   sizeof(int),
                                   3 * sizeof(int),
                                   6 * sizeof(int),
                                   9 * sizeof(int),
                                   11 * sizeof(int),
                                   15 * sizeof(int),
                                   17 * sizeof(int),
                                   20 * sizeof(int),
                                   21 * sizeof(int),
                                   23 * sizeof(int),
                                   24 * sizeof(int),
                                   25 * sizeof(int),
                                   27 * sizeof(int),
                                   28 * sizeof(int),
                                   29 * sizeof(int)};
    uint64_t b_off_size = b_off.size() * sizeof(uint64_t);
    std::vector<int> b_val = {1,  2,  2,  3,  3,  3,  4,  4,  4, 5, 5,
                              6,  6,  6,  6,  7,  7,  8,  8,  8, 9, 10,
                              10, 11, 12, 13, 13, 14, 15, 16, 16};
    uint64_t b_val_size = b_val.size() * sizeof(int);
    attr_buffers["a"] = AttrBuffer({&a[0], a_size, nullptr, 0});
    attr_buffers["b"] =
        AttrBuffer({&b_off[0], b_off_size, &b_val[0], b_val_size});
    write_array(ctx_, array_name_, TILEDB_GLOBAL_ORDER, attr_buffers);
  }
  
  template <class T>
  void SubarrayPartitionerDenseFx::test_subarray_partitioner(
      Layout subarray_layout,
      const SubarrayRanges<T>& ranges,
      const std::vector<SubarrayRanges<T>>& partitions,
      const std::string& attr,
      uint64_t budget,
      bool unsplittable) {
    Subarray subarray;
    create_subarray(array_->array_, ranges, subarray_layout, &subarray);
  
    SubarrayPartitioner subarray_partitioner(subarray);
    auto st = subarray_partitioner.set_result_budget(attr.c_str(), budget);
    CHECK(st.ok());
  
    check_partitions(subarray_partitioner, partitions, unsplittable);
  }
  
  template <class T>
  void SubarrayPartitionerDenseFx::test_subarray_partitioner(
      Layout subarray_layout,
      const SubarrayRanges<T>& ranges,
      const std::vector<SubarrayRanges<T>>& partitions,
      uint64_t budget,
      uint64_t budget_var,
      bool unsplittable) {
    Subarray subarray;
    create_subarray(array_->array_, ranges, subarray_layout, &subarray);
  
    SubarrayPartitioner subarray_partitioner(subarray);
  
    // Note: this is necessary, otherwise the subarray partitioner does
    // not check if the memory budget is exceeded for attributes whose
    // result budget is not set.
    auto st = subarray_partitioner.set_result_budget(TILEDB_COORDS, 1000000);
    CHECK(st.ok());
    st = subarray_partitioner.set_result_budget("a", 1000000);
    CHECK(st.ok());
    st = subarray_partitioner.set_result_budget("b", 1000000, 1000000);
    CHECK(st.ok());
  
    st = subarray_partitioner.set_memory_budget(budget, budget_var);
    CHECK(st.ok());
  
    check_partitions(subarray_partitioner, partitions, unsplittable);
  }
  
  /* ********************************* */
  /*                TESTS              */
  /* ********************************* */
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, single-range, empty array",
      "[SubarrayPartitioner][dense][1D][1R][empty_array]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {};
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{1, 10}}};
    uint64_t budget = 1000 * sizeof(uint64_t);
    std::string attr = TILEDB_COORDS;
    bool unsplittable = false;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: global
    subarray_layout = Layout::GLOBAL_ORDER;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, single-range, whole subarray fits",
      "[SubarrayPartitioner][dense][1D][1R][whole_subarray_fits]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {};
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{1, 10}}};
    uint64_t budget = 1000 * sizeof(uint64_t);
    std::string attr = TILEDB_COORDS;
    bool unsplittable = false;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: global
    subarray_layout = Layout::GLOBAL_ORDER;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, single-range, split once",
      "[SubarrayPartitioner][dense][1D][1R][split_once]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{2, 5}};
    std::vector<SubarrayRanges<uint64_t>> partitions;
    uint64_t budget = 3 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = false;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: global
    subarray_layout = Layout::GLOBAL_ORDER;
    partitions = {{{2, 2}}, {{3, 5}}};
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    partitions = {{{2, 3}}, {{4, 5}}};
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, single-range, unsplittable at once",
      "[SubarrayPartitioner][dense][1D][1R][unsplittable_at_once]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{4, 4}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{4, 4}}};
    uint64_t budget = 1;
    std::string attr = "a";
    bool unsplittable = true;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: global
    subarray_layout = Layout::GLOBAL_ORDER;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, single-range, split multiple",
      "[SubarrayPartitioner][dense][1D][1R][split_multiple]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{1, 6}};
    std::vector<SubarrayRanges<uint64_t>> partitions;
    uint64_t budget = 2 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = false;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: global
    subarray_layout = Layout::GLOBAL_ORDER;
    partitions = {{{1, 2}}, {{3, 4}}, {{5, 6}}};
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: row
    partitions = {{{1, 2}}, {{3, 3}}, {{4, 5}}, {{6, 6}}};
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, single-range, unsplittable after "
      "multiple",
      "[SubarrayPartitioner][dense][1D][1R][unsplittable_after_multiple]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{1, 6}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{1, 1}}};
    uint64_t budget = 1;
    std::string attr = "a";
    bool unsplittable = true;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: global
    subarray_layout = Layout::GLOBAL_ORDER;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, single-range, unsplittable but ok after "
      "budget reset",
      "[SubarrayPartitioner][dense][1D][1R][unsplittable_but_then_ok]") {
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    Subarray subarray;
    SubarrayRanges<uint64_t> ranges = {{2, 6}};
    Layout subarray_layout = Layout::GLOBAL_ORDER;
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{2, 2}}};
    std::vector<SubarrayRanges<uint64_t>> partitions_after = {{{3, 6}}};
  
    create_subarray(array_->array_, ranges, subarray_layout, &subarray);
  
    SubarrayPartitioner subarray_partitioner(subarray);
    auto st = subarray_partitioner.set_result_budget("a", 100 * sizeof(int));
    CHECK(st.ok());
    st = subarray_partitioner.set_result_budget("b", 1, 1);
    CHECK(st.ok());
  
    check_partitions(subarray_partitioner, partitions, true);
  
    st = subarray_partitioner.set_result_budget("b", 100, 100);
    CHECK(st.ok());
  
    check_partitions(subarray_partitioner, partitions_after, false);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, multi-range, whole subarray fits",
      "[SubarrayPartitioner][dense][1D][MR][whole_subarray_fits]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{2, 3, 5, 8, 9, 10}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{2, 3, 5, 8, 9, 10}}};
    uint64_t budget = 1000000;
    std::string attr = "a";
    bool unsplittable = false;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, multi-range, split once",
      "[SubarrayPartitioner][dense][1D][MR][split_once]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{2, 3, 5, 8, 9, 10}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{2, 3, 5, 8}},
                                                        {{9, 10}}};
    uint64_t budget = 7 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = false;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, multi-range, split multiple",
      "[SubarrayPartitioner][dense][1D][MR][split_multiple]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{2, 3, 5, 8, 9, 10}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {
        {{2, 3}}, {{5, 8}}, {{9, 10}}};
    uint64_t budget = 4 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = false;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, multi-range, split multiple finer",
      "[SubarrayPartitioner][dense][1D][MR][split_multiple_finer]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{2, 3, 5, 8, 9, 10}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {
        {{2, 3}}, {{5, 6}}, {{7, 8}}, {{9, 10}}};
    uint64_t budget = 2 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = false;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, multi-range, unsplittable",
      "[SubarrayPartitioner][dense][1D][MR][unsplittable]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{2, 3, 5, 8, 9, 10}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{2, 2}}};
    uint64_t budget = 0;
    std::string attr = "a";
    bool unsplittable = true;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 1D, single-range, memory budget",
      "[SubarrayPartitioner][dense][1D][1R][memory_budget]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {};
    std::vector<SubarrayRanges<uint64_t>> partitions = {};
    uint64_t budget = 16;
    uint64_t budget_var = 100000;
    bool unsplittable = false;
  
    create_default_1d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
    write_default_1d_array();
    open_array(ctx_, array_, TILEDB_READ);
  
    // subarray: global
    subarray_layout = Layout::GLOBAL_ORDER;
    partitions = {
        {{1, 2}},
        {{3, 4}},
        {{5, 6}},
        {{7, 8}},
        {{9, 10}},
    };
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, budget, budget_var, unsplittable);
  
    // subarray: row
    subarray_layout = Layout::ROW_MAJOR;
    partitions = {
        {{1, 2}},
        {{3, 3}},
        {{4, 4}},
        {{5, 5}},
        {{6, 6}},
        {{7, 7}},
        {{8, 8}},
        {{9, 10}},
    };
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, budget, budget_var, unsplittable);
  
    // subarray: col
    subarray_layout = Layout::COL_MAJOR;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, budget, budget_var, unsplittable);
  
    // subarray: unordered
    subarray_layout = Layout::UNORDERED;
    test_subarray_partitioner(
        subarray_layout, ranges, partitions, budget, budget_var, unsplittable);
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 2D, single-range, whole subarray fits",
      "[SubarrayPartitioner][dense][2D][1R][whole_subarray_fits]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{1, 4}, {1, 4}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{1, 4}, {1, 4}}};
    uint64_t budget = 1000 * sizeof(uint64_t);
    std::string attr = TILEDB_COORDS;
    bool unsplittable = false;
  
    SECTION("# tile: row, cell: row") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: row, cell: col") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: row") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: col") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 2D, single-range, unsplittable",
      "[SubarrayPartitioner][dense][2D][1R][unsplittable]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{2, 4}, {2, 4}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{2, 2}, {2, 2}}};
    uint64_t budget = 0 * sizeof(uint64_t);
    std::string attr = TILEDB_COORDS;
    bool unsplittable = true;
  
    SECTION("# tile: row, cell: row") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: row, cell: col") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: row") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: col") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 2D, single-range, split multiple",
      "[SubarrayPartitioner][dense][2D][1R][split_multiple]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{2, 4}, {2, 4}};
    std::vector<SubarrayRanges<uint64_t>> partitions;
    ;
    uint64_t budget = 2 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = false;
  
    SECTION("# tile: row, cell: row") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      partitions = {
          {{2, 2}, {2, 2}},
          {{2, 2}, {3, 4}},
          {{3, 4}, {2, 2}},
          {{3, 3}, {3, 4}},
          {{4, 4}, {3, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{2, 2}, {2, 3}},
          {{2, 2}, {4, 4}},
          {{3, 3}, {2, 3}},
          {{3, 3}, {4, 4}},
          {{4, 4}, {2, 3}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{2, 3}, {2, 2}},
          {{4, 4}, {2, 2}},
          {{2, 3}, {3, 3}},
          {{4, 4}, {3, 3}},
          {{2, 3}, {4, 4}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{2, 2}, {2, 3}},
          {{2, 2}, {4, 4}},
          {{3, 3}, {2, 3}},
          {{3, 3}, {4, 4}},
          {{4, 4}, {2, 3}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: row, cell: col") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      partitions = {
          {{2, 2}, {2, 2}},
          {{2, 2}, {3, 4}},
          {{3, 4}, {2, 2}},
          {{3, 4}, {3, 3}},
          {{3, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{2, 2}, {2, 3}},
          {{2, 2}, {4, 4}},
          {{3, 3}, {2, 3}},
          {{3, 3}, {4, 4}},
          {{4, 4}, {2, 3}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{2, 3}, {2, 2}},
          {{4, 4}, {2, 2}},
          {{2, 3}, {3, 3}},
          {{4, 4}, {3, 3}},
          {{2, 3}, {4, 4}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{2, 3}, {2, 2}},
          {{4, 4}, {2, 2}},
          {{2, 3}, {3, 3}},
          {{4, 4}, {3, 3}},
          {{2, 3}, {4, 4}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: row") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      partitions = {
          {{2, 2}, {2, 2}},
          {{3, 4}, {2, 2}},
          {{2, 2}, {3, 4}},
          {{3, 3}, {3, 4}},
          {{4, 4}, {3, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{2, 2}, {2, 3}},
          {{2, 2}, {4, 4}},
          {{3, 3}, {2, 3}},
          {{3, 3}, {4, 4}},
          {{4, 4}, {2, 3}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{2, 3}, {2, 2}},
          {{4, 4}, {2, 2}},
          {{2, 3}, {3, 3}},
          {{4, 4}, {3, 3}},
          {{2, 3}, {4, 4}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{2, 2}, {2, 3}},
          {{2, 2}, {4, 4}},
          {{3, 3}, {2, 3}},
          {{3, 3}, {4, 4}},
          {{4, 4}, {2, 3}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: col") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: global
      subarray_layout = Layout::GLOBAL_ORDER;
      partitions = {
          {{2, 2}, {2, 2}},
          {{3, 4}, {2, 2}},
          {{2, 2}, {3, 4}},
          {{3, 4}, {3, 3}},
          {{3, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{2, 2}, {2, 3}},
          {{2, 2}, {4, 4}},
          {{3, 3}, {2, 3}},
          {{3, 3}, {4, 4}},
          {{4, 4}, {2, 3}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{2, 3}, {2, 2}},
          {{4, 4}, {2, 2}},
          {{2, 3}, {3, 3}},
          {{4, 4}, {3, 3}},
          {{2, 3}, {4, 4}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{2, 3}, {2, 2}},
          {{4, 4}, {2, 2}},
          {{2, 3}, {3, 3}},
          {{4, 4}, {3, 3}},
          {{2, 3}, {4, 4}},
          {{4, 4}, {4, 4}},
      };
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 2D, multi-range, whole_subarray_fits",
      "[SubarrayPartitioner][dense][2D][MR][whole_subarray_fits]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {
        {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}}};
    uint64_t budget = 100 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = false;
  
    SECTION("# tile: row, cell: row") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: row, cell: col") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: row") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: col") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 2D, multi-range, split once",
      "[SubarrayPartitioner][dense][2D][MR][split_once]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges;
    std::vector<SubarrayRanges<uint64_t>> partitions;
    uint64_t budget = 0;
    std::string attr = "a";
    bool unsplittable = false;
  
    SECTION("# tile: row, cell: row") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 9 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 3, 4, 4}, {2, 3}},
          {{1, 2, 3, 3, 4, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 9 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 9 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: row, cell: col") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 9 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 3, 4, 4}, {2, 3}},
          {{1, 2, 3, 3, 4, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 9 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2, 3, 3, 4, 4}, {2, 3}},
          {{1, 2, 3, 3, 4, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 9 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: row") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 9 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 4}, {1, 2, 3, 3}},
          {{1, 2, 3, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 4}, {1, 2, 3, 3, 4, 4}};
      budget = 12 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 9 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: col") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 9 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 4}, {1, 2, 3, 3}},
          {{1, 2, 3, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 4}, {1, 2, 3, 3, 4, 4}};
      budget = 12 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2, 3, 4}, {1, 2, 3, 3}},
          {{1, 2, 3, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 4}, {1, 2, 3, 3, 4, 4}};
      budget = 12 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 2D, multi-range, calibrate",
      "[SubarrayPartitioner][dense][2D][MR][calibrate]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
    std::vector<SubarrayRanges<uint64_t>> partitions = {
        {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}}};
    uint64_t budget = 100 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = false;
  
    SECTION("# tile: row, cell: row") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 11 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 3, 4, 4}, {2, 3}},
          {{1, 2, 3, 3, 4, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 11 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 11 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: row, cell: col") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 11 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 3, 4, 4}, {2, 3}},
          {{1, 2, 3, 3, 4, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 11 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2, 3, 3, 4, 4}, {2, 3}},
          {{1, 2, 3, 3, 4, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 11 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: row") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 11 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 4}, {1, 2}},
          {{1, 2, 3, 4}, {3, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 4}, {1, 2, 3, 3, 4, 4}};
      budget = 10 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 11 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: col") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 11 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 4}, {1, 2}},
          {{1, 2, 3, 4}, {3, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 4}, {1, 2, 3, 3, 4, 4}};
      budget = 10 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2, 3, 4}, {1, 2}},
          {{1, 2, 3, 4}, {3, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 4}, {1, 2, 3, 3, 4, 4}};
      budget = 10 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 2D, multi-range, split multiple finer",
      "[SubarrayPartitioner][dense][2D][MR][split_multiple_finer]") {
    Layout subarray_layout;
    SubarrayRanges<uint64_t> ranges;
    std::vector<SubarrayRanges<uint64_t>> partitions;
    uint64_t budget = 100 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = false;
  
    SECTION("# tile: row, cell: row") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 1}, {2, 3, 4, 4}},
          {{2, 2}, {2, 3, 4, 4}},
          {{3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 3 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 2}},
          {{4, 4}, {2, 2}},
          {{1, 2, 3, 3}, {3, 3}},
          {{4, 4}, {3, 3}},
          {{1, 2, 3, 3}, {4, 4}},
          {{4, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 3 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 1}, {2, 3}},
          {{2, 2}, {2, 3}},
          {{1, 2}, {4, 4}},
          {{3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 3 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: row, cell: col") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 1}, {2, 3, 4, 4}},
          {{2, 2}, {2, 3, 4, 4}},
          {{3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 3 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 3}, {2, 2}},
          {{4, 4}, {2, 2}},
          {{1, 2, 3, 3}, {3, 3}},
          {{4, 4}, {3, 3}},
          {{1, 2, 3, 3}, {4, 4}},
          {{4, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 3 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2}, {2, 2}},
          {{1, 2}, {3, 3}},
          {{3, 3}, {2, 3}},
          {{4, 4}, {2, 3}},
          {{1, 2, 3, 3}, {4, 4}},
          {{4, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 3 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: row") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 1}, {2, 3, 4, 4}},
          {{2, 2}, {2, 3, 4, 4}},
          {{3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 3 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 4}, {1, 1}},
          {{1, 2, 3, 4}, {2, 2}},
          {{1, 2, 3, 4}, {3, 3}},
          {{1, 2, 3, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 4}, {1, 2, 3, 3, 4, 4}};
      budget = 4 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 1}, {2, 3}},
          {{2, 2}, {2, 3}},
          {{1, 2}, {4, 4}},
          {{3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 3 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: col") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      partitions = {
          {{1, 1}, {2, 3, 4, 4}},
          {{2, 2}, {2, 3, 4, 4}},
          {{3, 3}, {2, 3, 4, 4}},
          {{4, 4}, {2, 3, 4, 4}},
      };
      ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
      budget = 3 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      partitions = {
          {{1, 2, 3, 4}, {1, 1}},
          {{1, 2, 3, 4}, {2, 2}},
          {{1, 2, 3, 4}, {3, 3}},
          {{1, 2, 3, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 4}, {1, 2, 3, 3, 4, 4}};
      budget = 4 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      partitions = {
          {{1, 2}, {1, 2}},
          {{3, 4}, {1, 2}},
          {{1, 2, 3, 4}, {3, 3}},
          {{1, 2, 3, 4}, {4, 4}},
      };
      ranges = {{1, 2, 3, 4}, {1, 2, 3, 3, 4, 4}};
      budget = 4 * sizeof(int);
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    close_array(ctx_, array_);
  }
  
  TEST_CASE_METHOD(
      SubarrayPartitionerDenseFx,
      "SubarrayPartitioner (Dense): 2D, multi-range, unsplittable",
      "[SubarrayPartitioner][dense][2D][MR][unsplittable]") {
    Layout subarray_layout;
    std::vector<SubarrayRanges<uint64_t>> partitions = {{{1, 1}, {2, 2}}};
    SubarrayRanges<uint64_t> ranges = {{1, 2, 3, 3, 4, 4}, {2, 3, 4, 4}};
    uint64_t budget = 0 * sizeof(int);
    std::string attr = "a";
    bool unsplittable = true;
  
    SECTION("# tile: row, cell: row") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: row, cell: col") {
      create_default_2d_array(TILEDB_ROW_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: row") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_ROW_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    SECTION("# tile: col, cell: col") {
      create_default_2d_array(TILEDB_COL_MAJOR, TILEDB_COL_MAJOR);
      write_default_2d_array();
      open_array(ctx_, array_, TILEDB_READ);
  
      // subarray: row
      subarray_layout = Layout::ROW_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: col
      subarray_layout = Layout::COL_MAJOR;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
  
      // subarray: unordered
      subarray_layout = Layout::UNORDERED;
      test_subarray_partitioner(
          subarray_layout, ranges, partitions, attr, budget, unsplittable);
    }
  
    close_array(ctx_, array_);
  }
  