blob: f0b1f53eb086ce798026d370ddd165ec0d53f1a9 [file]
/*
* 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include "iceberg/exception.h"
#include "iceberg/result.h"
#include "iceberg/test/matchers.h"
#include "iceberg/util/error_collector.h"
#include "iceberg/util/macros.h"
namespace {
using ::iceberg::HasErrorMessage;
using ::iceberg::HasValue;
using ::iceberg::IsError;
using ::iceberg::IsOk;
// The macros expand here, in a namespace with its own nested iceberg namespace, so a
// macro that names iceberg::X instead of ::iceberg::X fails to compile.
namespace caller {
namespace iceberg {}
::iceberg::Result<int> Parse(bool valid) {
if (!valid) {
return ::iceberg::InvalidArgument("Invalid input");
}
return 42;
}
::iceberg::Result<int> AddOne(bool valid) {
ICEBERG_ASSIGN_OR_RAISE(auto value, Parse(valid));
return value + 1;
}
::iceberg::Status Validate(bool valid) {
ICEBERG_RETURN_UNEXPECTED(Parse(valid));
return {};
}
::iceberg::Status CheckRange(int value) {
ICEBERG_PRECHECK(value > 0, "Value must be positive, got {}", value);
ICEBERG_CHECK(value < 100, "Value must be below 100, got {}", value);
return {};
}
int AddOneOrThrow(bool valid) {
ICEBERG_ASSIGN_OR_THROW(auto value, Parse(valid));
return value + 1;
}
int CheckPositiveOrDie(int value) {
ICEBERG_CHECK_OR_DIE(value > 0, "Value must be positive, got {}", value);
return value;
}
class TestBuilder : public ::iceberg::ErrorCollector {
public:
TestBuilder& Set(int value) {
ICEBERG_BUILDER_CHECK(value > 0, "Value must be positive, got {}", value);
ICEBERG_BUILDER_ASSIGN_OR_RETURN(value_, Parse(value < 100));
ICEBERG_BUILDER_ASSIGN_OR_RETURN_WITH_ERROR(value_, Parse(value < 50),
"Value {} is too large", value);
return *this;
}
private:
int value_ = 0;
};
} // namespace caller
using caller::AddOne;
using caller::AddOneOrThrow;
using caller::CheckPositiveOrDie;
using caller::CheckRange;
using caller::TestBuilder;
using caller::Validate;
} // namespace
TEST(ErrorMacrosTest, AssignOrRaise) {
EXPECT_THAT(AddOne(true), HasValue(::testing::Eq(43)));
EXPECT_THAT(AddOne(false), IsError(iceberg::ErrorKind::kInvalidArgument));
}
TEST(ErrorMacrosTest, ReturnUnexpected) {
EXPECT_THAT(Validate(true), IsOk());
EXPECT_THAT(Validate(false), HasErrorMessage("Invalid input"));
}
TEST(ErrorMacrosTest, PrecheckAndCheck) {
EXPECT_THAT(CheckRange(1), IsOk());
EXPECT_THAT(CheckRange(0), IsError(iceberg::ErrorKind::kInvalidArgument));
EXPECT_THAT(CheckRange(100), IsError(iceberg::ErrorKind::kValidationFailed));
}
TEST(ErrorMacrosTest, AssignOrThrow) {
EXPECT_EQ(AddOneOrThrow(true), 43);
EXPECT_THROW(AddOneOrThrow(false), iceberg::IcebergError);
}
TEST(ErrorMacrosTest, CheckOrDie) {
EXPECT_EQ(CheckPositiveOrDie(1), 1);
EXPECT_THROW(CheckPositiveOrDie(0), iceberg::IcebergError);
}
TEST(ErrorMacrosTest, BuilderMacros) {
EXPECT_THAT(TestBuilder().Set(1).CheckErrors(), IsOk());
EXPECT_THAT(TestBuilder().Set(0).CheckErrors(),
HasErrorMessage("Value must be positive, got 0"));
EXPECT_THAT(TestBuilder().Set(150).CheckErrors(), HasErrorMessage("Invalid input"));
EXPECT_THAT(TestBuilder().Set(70).CheckErrors(),
HasErrorMessage("Value 70 is too large"));
}