blob: 77864fbf8e6110e69670c7d8b8d3b2065f85a140 [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "rs_bindings_from_cc/cmdline.h"
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "common/status_test_matchers.h"
#include "rs_bindings_from_cc/bazel_types.h"
namespace crubit {
namespace {
using ::testing::AllOf;
using ::testing::ElementsAre;
using ::testing::HasSubstr;
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
namespace {
absl::StatusOr<Cmdline> TestCmdline(std::string target,
std::vector<std::string> public_headers,
std::string target_args) {
return Cmdline::CreateForTesting(
std::move(target), "cc_out", "rs_out", "ir_out", "namespaces_out",
"crubit_support_path", "clang_format_exe_path", "rustfmt_exe_path",
"rustfmt_config_path",
/*do_nothing=*/false, std::move(public_headers), std::move(target_args),
/* extra_rs_srcs= */ {},
/* srcs_to_scan_for_instantiations= */ {},
/* instantiations_out= */ "",
/* error_report_out= */ "", SourceLocationDocComment::Disabled);
}
absl::StatusOr<Cmdline> TestCmdline(std::vector<std::string> public_headers,
std::string target_args) {
return TestCmdline("//:target", std::move(public_headers),
std::move(target_args));
}
} // namespace
TEST(CmdlineTest, BasicCorrectInput) {
ASSERT_OK_AND_ASSIGN(
Cmdline cmdline,
Cmdline::CreateForTesting(
"//:t1", "cc_out", "rs_out", "ir_out", "namespaces_out",
"crubit_support_path", "clang_format_exe_path", "rustfmt_exe_path",
"rustfmt_config_path",
/* do_nothing= */ false, {"h1"},
R"([{"t": "//:t1", "h": ["h1", "h2"]}])", {"extra_file.rs"},
{"scan_for_instantiations.rs"}, "instantiations_out",
"error_report_out", SourceLocationDocComment::Disabled));
EXPECT_EQ(cmdline.cc_out(), "cc_out");
EXPECT_EQ(cmdline.rs_out(), "rs_out");
EXPECT_EQ(cmdline.ir_out(), "ir_out");
EXPECT_EQ(cmdline.namespaces_out(), "namespaces_out");
EXPECT_EQ(cmdline.crubit_support_path(), "crubit_support_path");
EXPECT_EQ(cmdline.clang_format_exe_path(), "clang_format_exe_path");
EXPECT_EQ(cmdline.rustfmt_exe_path(), "rustfmt_exe_path");
EXPECT_EQ(cmdline.rustfmt_config_path(), "rustfmt_config_path");
EXPECT_EQ(cmdline.instantiations_out(), "instantiations_out");
EXPECT_EQ(cmdline.error_report_out(), "error_report_out");
EXPECT_EQ(cmdline.do_nothing(), false);
EXPECT_EQ(cmdline.current_target().value(), "//:t1");
EXPECT_THAT(cmdline.public_headers(), ElementsAre(HeaderName("h1")));
EXPECT_THAT(cmdline.extra_rs_srcs(), ElementsAre("extra_file.rs"));
EXPECT_THAT(cmdline.srcs_to_scan_for_instantiations(),
ElementsAre("scan_for_instantiations.rs"));
EXPECT_THAT(
cmdline.headers_to_targets(),
UnorderedElementsAre(Pair(HeaderName("h1"), BazelLabel("//:t1")),
Pair(HeaderName("h2"), BazelLabel("//:t1"))));
EXPECT_EQ(cmdline.generate_source_location_in_doc_comment(),
SourceLocationDocComment::Disabled);
}
TEST(CmdlineTest, TargetArgsEmpty) {
ASSERT_THAT(TestCmdline({"h1"}, ""),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("please specify --target_args")));
}
TEST(CmdlineTest, TargetArgsInvalidJson) {
ASSERT_THAT(
TestCmdline({"h1"}, "#!$%"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr("Invalid JSON"))));
}
TEST(CmdlineTest, TargetArgsIntInsteadOfTopLevelArray) {
ASSERT_THAT(TestCmdline({"h1"}, "123"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr("array"))));
}
TEST(CmdlineTest, TargetArgsIntInTopLevelArray) {
ASSERT_THAT(TestCmdline({"h1"}, "[123, 456]"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"))));
}
TEST(CmdlineTest, TargetArgsIntInsteadOfHeadersArray) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "//:t1", "h": 123}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr(".h"),
HasSubstr("array"))));
}
TEST(CmdlineTest, TargetArgsMissingTarget) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"h": ["h1", "h2"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr(".t"),
HasSubstr("missing"))));
}
TEST(CmdlineTest, TargetArgsMissingHeader) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "//:t1"}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"),
HasSubstr("Couldn't find header"))));
}
TEST(CmdlineTest, TargetArgsEmptyHeader) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "t1", "h": ["", "h2"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr("`h`"),
HasSubstr("empty string"))));
}
TEST(CmdlineTest, TargetArgsEmptyTarget) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "", "h": ["h1", "h2"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr("`t`"),
HasSubstr("empty string"))));
}
TEST(CmdlineTest, TargetArgsIntInsteadOfTarget) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": 123, "h": ["h1", "h2"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr(".t"),
HasSubstr("string"))));
}
TEST(CmdlineTest, TargetArgsIntInsteadOfHeader) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "//:t1", "h": [123, "h2"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr(".h"),
HasSubstr("string"))));
}
TEST(CmdlineTest, TargetArgsDuplicateHeader) {
for (const char* target : {"//:t1", "//:t2"}) {
ASSERT_OK_AND_ASSIGN(Cmdline cmdline, TestCmdline(target, {"h1"}, R"([
{"t": "//:t1", "h": ["h1"]},
{"t": "//:t2", "h": ["h1", "h2"]} ])"));
EXPECT_THAT(
cmdline.headers_to_targets(),
UnorderedElementsAre(Pair(HeaderName("h1"), BazelLabel("//:t1")),
Pair(HeaderName("h2"), BazelLabel("//:t2"))));
EXPECT_EQ(cmdline.current_target().value(), target);
}
}
TEST(CmdlineTest, PublicHeadersEmpty) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_THAT(TestCmdline({}, std::string(kTargetsAndHeaders)),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("please specify --public_headers")));
}
TEST(CmdlineTest, PublicHeadersWhereFirstHeaderMissingInMap) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_THAT(
TestCmdline({"missing-in-map.h"}, std::string(kTargetsAndHeaders)),
StatusIs(
absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("missing-in-map.h"), HasSubstr("Couldn't find"))));
}
TEST(CmdlineTest, PublicHeadersWhereSecondHeaderMissingInMap) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_THAT(
TestCmdline({"a.h", "missing.h"}, std::string(kTargetsAndHeaders)),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("missing.h"), HasSubstr("Couldn't find"))));
}
TEST(CmdlineTest, PublicHeadersCoveringMultipleTargets) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]},
{"t": "//:target2", "h": ["c.h", "d.h"]}
])";
ASSERT_OK_AND_ASSIGN(Cmdline cmdline,
TestCmdline("//:target1", {"a.h", "c.h"},
std::string(kTargetsAndHeaders)));
EXPECT_EQ(cmdline.current_target().value(), "//:target1");
EXPECT_THAT(
cmdline.headers_to_targets(),
UnorderedElementsAre(Pair(HeaderName("a.h"), BazelLabel("//:target1")),
Pair(HeaderName("b.h"), BazelLabel("//:target1")),
Pair(HeaderName("c.h"), BazelLabel("//:target2")),
Pair(HeaderName("d.h"), BazelLabel("//:target2"))));
}
TEST(CmdlineTest, TargetArgsIntInsteadOfFeaturesArray) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "t1", "f": 123}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr(".f"),
HasSubstr("array"))));
}
TEST(CmdlineTest, TargetArgsEmptyFeature) {
ASSERT_THAT(TestCmdline({"h1"}, R"([{"t": "t1", "f": ["", "h2"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr("`f`"),
HasSubstr("empty string"))));
}
TEST(CmdlineTest, TargetArgsIntInsteadOfFeature) {
ASSERT_THAT(
TestCmdline({"h1"}, R"([{"t": "t1", "f": [123, "experimental"]}])"),
StatusIs(absl::StatusCode::kInvalidArgument,
AllOf(HasSubstr("--target_args"), HasSubstr(".f"),
HasSubstr("string"))));
}
TEST(CmdlineTest, InstantiationsOutEmpty) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_THAT(
(Cmdline::CreateForTesting(
"//:target1", "cc_out", "rs_out", "ir_out", "namespaces_out",
"crubit_support_path", "clang_format_exe_path", "rustfmt_exe_path",
"rustfmt_config_path",
/* do_nothing= */ false, {"a.h"}, std::string(kTargetsAndHeaders),
/* extra_rs_srcs= */ {}, {"lib.rs"},
/* instantiations_out= */ "", "error_report_out",
SourceLocationDocComment::Enabled)),
StatusIs(
absl::StatusCode::kInvalidArgument,
HasSubstr(
"please specify both --rust_sources and --instantiations_out "
"when requesting a template instantiation mode")));
}
TEST(CmdlineTest, RustSourcesEmpty) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_THAT(
Cmdline::CreateForTesting(
"//:target1", "cc_out", "rs_out", "ir_out", "namespaces_out",
"crubit_support_path", "clang_format_exe_path", "rustfmt_exe_path",
"rustfmt_config_path",
/* do_nothing= */ false, {"a.h"}, std::string(kTargetsAndHeaders),
/* extra_rs_srcs= */ {},
/* srcs_to_scan_for_instantiations= */ {}, "instantiations_out",
"error_report_out", SourceLocationDocComment::Enabled),
StatusIs(
absl::StatusCode::kInvalidArgument,
HasSubstr(
"please specify both --rust_sources and --instantiations_out "
"when requesting a template instantiation mode")));
}
TEST(CmdlineTest, CcOutEmpty) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_THAT(
Cmdline::CreateForTesting(
"//:target1",
/* cc_out= */ "", "rs_out", "ir_out", "namespaces_out",
"crubit_support_path", "clang_format_exe_path", "rustfmt_exe_path",
"rustfmt_config_path",
/* do_nothing= */ false, {"a.h"}, std::string(kTargetsAndHeaders),
/* extra_rs_srcs= */ {},
/* srcs_to_scan_for_instantiations= */ {},
/* instantiations_out= */ "", "error_report_out",
SourceLocationDocComment::Enabled),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("please specify --cc_out")));
}
TEST(CmdlineTest, RsOutEmpty) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_THAT(
Cmdline::CreateForTesting(
"//:target1", "cc_out", /* rs_out= */ "", "namespaces_out", "ir_out",
"crubit_support_path", "clang_format_exe_path", "rustfmt_exe_path",
"rustfmt_config_path",
/* do_nothing= */ false, {"a.h"}, std::string(kTargetsAndHeaders),
/* extra_rs_srcs= */ {},
/* srcs_to_scan_for_instantiations= */ {},
/* instantiations_out= */ "", "error_report_out",
SourceLocationDocComment::Enabled),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("please specify --rs_out")));
}
TEST(CmdlineTest, IrOutEmpty) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_OK(Cmdline::CreateForTesting(
"//:target1", "cc_out", "rs_out", /* ir_out= */ "", "namespaces_out",
"crubit_support_path", "clang_format_exe_path", "rustfmt_exe_path",
"rustfmt_config_path",
/* do_nothing= */ false, {"a.h"}, std::string(kTargetsAndHeaders),
/* extra_rs_srcs= */ {},
/* srcs_to_scan_for_instantiations= */ {},
/* instantiations_out= */ "", "error_report_out",
SourceLocationDocComment::Enabled));
}
TEST(CmdlineTest, ClangFormatExePathEmpty) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_THAT(
Cmdline::CreateForTesting(
"//:target1", "cc_out", "rs_out", "ir_out", "namespaces_out",
"crubit_support_path",
/* clang_format_exe_path= */ "", "rustfmt_exe_path",
"rustfmt_config_path",
/* do_nothing= */ false, {"a.h"}, std::string(kTargetsAndHeaders),
/* extra_rs_srcs= */ {},
/* srcs_to_scan_for_instantiations= */ {},
/* instantiations_out= */ "", "error_report_out",
SourceLocationDocComment::Enabled),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("please specify --clang_format_exe_path")));
}
TEST(CmdlineTest, RustfmtExePathEmpty) {
constexpr absl::string_view kTargetsAndHeaders = R"([
{"t": "//:target1", "h": ["a.h", "b.h"]}
])";
ASSERT_THAT(
Cmdline::CreateForTesting(
"//:target1", "cc_out", "rs_out", "ir_out", "namespaces_out",
"crubit_support_path", "clang_format_exe_path",
/* rustfmt_exe_path= */ "", "rustfmt_config_path",
/* do_nothing= */ false, {"a.h"}, std::string(kTargetsAndHeaders),
/* extra_rs_srcs= */ {},
/* srcs_to_scan_for_instantiations= */ {},
/* instantiations_out= */ "", "error_report_out",
SourceLocationDocComment::Enabled),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("please specify --rustfmt_exe_path")));
}
} // namespace
} // namespace crubit