1919
2020#pragma once
2121
22+ #include < chrono>
2223#include < format>
2324#include < memory>
2425#include < string>
2829
2930#include " iceberg/arrow/arrow_fs_file_io_internal.h"
3031#include " iceberg/catalog/memory/in_memory_catalog.h"
32+ #include " iceberg/constants.h"
33+ #include " iceberg/partition_spec.h"
34+ #include " iceberg/schema.h"
35+ #include " iceberg/sort_order.h"
3136#include " iceberg/table.h"
3237#include " iceberg/table_identifier.h"
3338#include " iceberg/table_metadata.h"
3439#include " iceberg/test/matchers.h"
3540#include " iceberg/test/test_resource.h"
41+ #include " iceberg/type.h"
3642#include " iceberg/util/uuid.h"
3743
3844namespace iceberg {
@@ -43,6 +49,7 @@ class UpdateTestBase : public ::testing::Test {
4349 void SetUp () override {
4450 InitializeFileIO ();
4551 RegisterTableFromResource (" TableMetadataV2Valid.json" );
52+ RegisterEmptyTable ();
4653 }
4754
4855 // / \brief Initialize file IO and create necessary directories.
@@ -56,6 +63,7 @@ class UpdateTestBase : public ::testing::Test {
5663 static_cast <arrow::ArrowFileSystemFileIO&>(*file_io_).fs ());
5764 ASSERT_TRUE (arrow_fs != nullptr );
5865 ASSERT_TRUE (arrow_fs->CreateDir (table_location_ + " /metadata" ).ok ());
66+ ASSERT_TRUE (arrow_fs->CreateDir (empty_table_location_ + " /metadata" ).ok ());
5967 }
6068
6169 // / \brief Register a table from a metadata resource file.
@@ -78,11 +86,60 @@ class UpdateTestBase : public ::testing::Test {
7886 catalog_->RegisterTable (table_ident_, metadata_location));
7987 }
8088
89+ // / \brief Register an empty table with no snapshots.
90+ // /
91+ // / Creates a minimal table metadata with no snapshots (current_snapshot_id = -1).
92+ // / This is useful for testing operations on empty tables.
93+ void RegisterEmptyTable () {
94+ // Drop existing table if it exists
95+ std::ignore = catalog_->DropTable (empty_table_ident_, /* purge=*/ false );
96+
97+ // Create minimal schema with a single field
98+ auto field = SchemaField::MakeRequired (1 , " id" , int64 ());
99+ auto schema = std::make_shared<Schema>(std::vector<SchemaField>{field}, 0 );
100+
101+ // Create empty table metadata
102+ auto metadata = std::make_unique<TableMetadata>();
103+ metadata->format_version = 2 ;
104+ metadata->table_uuid = Uuid::GenerateV7 ().ToString ();
105+ metadata->location = empty_table_location_;
106+ metadata->last_sequence_number = 0 ;
107+ metadata->last_updated_ms = TimePointMs{std::chrono::milliseconds (1000 )};
108+ metadata->last_column_id = 1 ;
109+ metadata->current_schema_id = 0 ;
110+ metadata->schemas .push_back (schema);
111+ metadata->partition_specs .push_back (PartitionSpec::Unpartitioned ());
112+ metadata->default_spec_id = PartitionSpec::kInitialSpecId ;
113+ metadata->last_partition_id = 0 ;
114+ metadata->current_snapshot_id = kInvalidSnapshotId ;
115+ metadata->sort_orders .push_back (SortOrder::Unsorted ());
116+ metadata->default_sort_order_id = SortOrder::kUnsortedOrderId ;
117+ metadata->next_row_id = TableMetadata::kInitialRowId ;
118+
119+ // Write table metadata to the table location.
120+ auto metadata_location =
121+ std::format (" {}/metadata/00001-{}.metadata.json" , empty_table_location_,
122+ Uuid::GenerateV7 ().ToString ());
123+ ASSERT_THAT (TableMetadataUtil::Write (*file_io_, metadata_location, *metadata),
124+ IsOk ());
125+
126+ // Register the table in the catalog.
127+ ICEBERG_UNWRAP_OR_FAIL (
128+ auto registered_table,
129+ catalog_->RegisterTable (empty_table_ident_, metadata_location));
130+
131+ // Reload the table to ensure it's in a clean state without any transaction state.
132+ ICEBERG_UNWRAP_OR_FAIL (empty_table_, catalog_->LoadTable (empty_table_ident_));
133+ }
134+
81135 const TableIdentifier table_ident_{.name = " test_table" };
82136 const std::string table_location_{" /warehouse/test_table" };
137+ const TableIdentifier empty_table_ident_{.name = " empty_table" };
138+ const std::string empty_table_location_{" /warehouse/empty_table" };
83139 std::shared_ptr<FileIO> file_io_;
84140 std::shared_ptr<InMemoryCatalog> catalog_;
85141 std::shared_ptr<Table> table_;
142+ std::shared_ptr<Table> empty_table_;
86143};
87144
88145} // namespace iceberg
0 commit comments