| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| #include <format> | |
| #include <map> | |
| #include <memory> | |
| #include <string> | |
| #include <unordered_map> | |
| #include <vector> | |
| #include <gmock/gmock-matchers.h> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include "iceberg/statistics_file.h" | |
| #include "iceberg/table_identifier.h" | |
| #include "iceberg/util/formatter_internal.h" | |
| namespace iceberg { | |
| // Tests for the std::format specializations | |
| TEST(FormatterTest, VectorFormat) { | |
| std::vector<int> empty; | |
| EXPECT_EQ("[]", std::format("{}", empty)); | |
| std::vector<int> nums = {1, 2, 3, 4, 5}; | |
| EXPECT_EQ("[1, 2, 3, 4, 5]", std::format("{}", nums)); | |
| std::vector<std::string> names = {"Alice", "Bob", "Charlie"}; | |
| EXPECT_EQ("[Alice, Bob, Charlie]", std::format("{}", names)); | |
| } | |
| TEST(FormatterTest, MapFormat) { | |
| std::map<std::string, int> empty; | |
| EXPECT_EQ("{}", std::format("{}", empty)); | |
| std::map<std::string, int> ages = {{"Alice", 30}, {"Bob", 25}, {"Charlie", 35}}; | |
| EXPECT_EQ("{Alice: 30, Bob: 25, Charlie: 35}", std::format("{}", ages)); | |
| } | |
| TEST(FormatterTest, UnorderedMapFormat) { | |
| std::unordered_map<std::string, double> empty; | |
| EXPECT_EQ("{}", std::format("{}", empty)); | |
| std::unordered_map<std::string, double> scores = { | |
| {"Alice", 95.5}, {"Bob", 87.0}, {"Charlie", 92.3}}; | |
| std::string str = std::format("{}", scores); | |
| EXPECT_THAT(str, ::testing::HasSubstr("Alice: 95.5")); | |
| EXPECT_THAT(str, ::testing::HasSubstr("Bob: 87")); | |
| EXPECT_THAT(str, ::testing::HasSubstr("Charlie: 92.3")); | |
| } | |
| TEST(FormatterTest, NestedContainersFormat) { | |
| std::vector<std::map<std::string, int>> nested = {{{"a", 1}, {"b", 2}}, | |
| {{"c", 3}, {"d", 4}}}; | |
| EXPECT_EQ("[{a: 1, b: 2}, {c: 3, d: 4}]", std::format("{}", nested)); | |
| std::map<std::string, std::vector<int>> nested_map = { | |
| {"primes", {2, 3, 5, 7, 11}}, {"fibonacci", {1, 1, 2, 3, 5, 8, 13}}}; | |
| std::string result = std::format("{}", nested_map); | |
| EXPECT_THAT(result, ::testing::HasSubstr("primes")); | |
| EXPECT_THAT(result, ::testing::HasSubstr("fibonacci")); | |
| EXPECT_THAT(result, ::testing::HasSubstr("[2, 3, 5, 7, 11]")); | |
| EXPECT_THAT(result, ::testing::HasSubstr("[1, 1, 2, 3, 5, 8, 13]")); | |
| } | |
| TEST(FormatterTest, EdgeCasesFormat) { | |
| std::vector<int> single_vec = {42}; | |
| EXPECT_EQ("[42]", std::format("{}", single_vec)); | |
| std::map<std::string, int> single_map = {{"key", 42}}; | |
| EXPECT_EQ("{key: 42}", std::format("{}", single_map)); | |
| std::vector<std::vector<int>> nested_empty = {{}, {1, 2}, {}}; | |
| EXPECT_EQ("[[], [1, 2], []]", std::format("{}", nested_empty)); | |
| } | |
| TEST(FormatterTest, SmartPointerFormat) { | |
| std::vector<std::shared_ptr<int>> int_ptrs = { | |
| std::make_shared<int>(42), | |
| std::make_shared<int>(123), | |
| nullptr, | |
| }; | |
| EXPECT_EQ("[42, 123, null]", std::format("{}", int_ptrs)); | |
| std::vector<std::shared_ptr<std::string>> str_ptrs = { | |
| std::make_shared<std::string>("hello"), | |
| std::make_shared<std::string>("world"), | |
| nullptr, | |
| }; | |
| EXPECT_EQ("[hello, world, null]", std::format("{}", str_ptrs)); | |
| std::map<std::string, std::shared_ptr<int>> map_with_ptr_values = { | |
| {"one", std::make_shared<int>(1)}, | |
| {"two", std::make_shared<int>(2)}, | |
| {"null", nullptr}, | |
| }; | |
| EXPECT_EQ("{null: null, one: 1, two: 2}", std::format("{}", map_with_ptr_values)); | |
| std::unordered_map<std::string, std::shared_ptr<double>> scores = { | |
| {"Alice", std::make_shared<double>(95.5)}, | |
| {"Bob", std::make_shared<double>(87.0)}, | |
| {"Charlie", nullptr}, | |
| }; | |
| std::string str = std::format("{}", scores); | |
| EXPECT_THAT(str, ::testing::HasSubstr("Alice: 95.5")); | |
| EXPECT_THAT(str, ::testing::HasSubstr("Bob: 87")); | |
| EXPECT_THAT(str, ::testing::HasSubstr("Charlie: null")); | |
| std::vector<std::map<std::string, std::shared_ptr<int>>> nested = { | |
| {{"a", std::make_shared<int>(1)}, {"b", std::make_shared<int>(2)}}, | |
| {{"c", std::make_shared<int>(3)}, {"d", nullptr}}, | |
| }; | |
| EXPECT_EQ("[{a: 1, b: 2}, {c: 3, d: null}]", std::format("{}", nested)); | |
| } | |
| TEST(FormatterTest, StatisticsFileFormat) { | |
| StatisticsFile statistics_file{ | |
| .snapshot_id = 123, | |
| .path = "test_path", | |
| .file_size_in_bytes = 100, | |
| .file_footer_size_in_bytes = 20, | |
| .blob_metadata = {BlobMetadata{.type = "type1", | |
| .source_snapshot_id = 1, | |
| .source_snapshot_sequence_number = 1, | |
| .fields = {1, 2, 3}, | |
| .properties = {{"key1", "value1"}}}, | |
| BlobMetadata{.type = "type2", | |
| .source_snapshot_id = 2, | |
| .source_snapshot_sequence_number = 2, | |
| .fields = {4, 5, 6}, | |
| .properties = {}}}}; | |
| const std::string expected = | |
| "StatisticsFile[" | |
| "snapshotId=123,path=test_path,fileSizeInBytes=100,fileFooterSizeInBytes=20," | |
| "blobMetadata=[" | |
| "BlobMetadata[type='type1',sourceSnapshotId=1,sourceSnapshotSequenceNumber=1," | |
| "fields=[1, 2, 3],properties={key1: value1}], " | |
| "BlobMetadata[type='type2',sourceSnapshotId=2,sourceSnapshotSequenceNumber=2," | |
| "fields=[4, 5, 6],properties={}]" | |
| "]" | |
| "]"; | |
| EXPECT_EQ(expected, std::format("{}", statistics_file)); | |
| } | |
| // For Types that has a ToString function | |
| TEST(FormatterTest, TableIdentifierFormat) { | |
| TableIdentifier empty_ns_table{ | |
| .ns = Namespace({}), | |
| .name = "table_name", | |
| }; | |
| EXPECT_EQ("table_name", std::format("{}", empty_ns_table)); | |
| TableIdentifier table{ | |
| .ns = Namespace({"ns1", "ns2"}), | |
| .name = "table_name", | |
| }; | |
| EXPECT_EQ("ns1.ns2.table_name", std::format("{}", table)); | |
| } | |
| } // namespace iceberg |