Skip to content

Commit

Permalink
refactor(cli): add allocator argument to parse_options
Browse files Browse the repository at this point in the history
This argument will be used in the future to let us drop some uses of
std::vector.
  • Loading branch information
strager committed Oct 29, 2023
1 parent 9fa7b7a commit 3d7b0d6
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 52 deletions.
3 changes: 2 additions & 1 deletion src/quick-lint-js/cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ void init() {
}

void run(int argc, char **argv) {
Options o = parse_options(argc, argv);
Monotonic_Allocator options_allocator("run options_allocator");
Options o = parse_options(argc, argv, &options_allocator);
run(std::move(o));
}

Expand Down
3 changes: 2 additions & 1 deletion src/quick-lint-js/cli/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ QLJS_WARNING_IGNORE_GCC("-Wshadow=local")
using namespace std::literals::string_view_literals;

namespace quick_lint_js {
Options parse_options(int argc, char** argv) {
Options parse_options(int argc, char** argv,
[[maybe_unused]] Monotonic_Allocator* allocator) {
Options o;

Monotonic_Allocator temporary_allocator("parse_options");
Expand Down
4 changes: 3 additions & 1 deletion src/quick-lint-js/cli/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include <optional>
#include <quick-lint-js/container/monotonic-allocator.h>
#include <quick-lint-js/diag/diag-code-list.h>
#include <vector>

Expand Down Expand Up @@ -86,7 +87,8 @@ Resolved_Input_File_Language get_language(const File_To_Lint &file,
Resolved_Input_File_Language get_language(const char *file,
Raw_Input_File_Language language);

Options parse_options(int argc, char **argv);
// Returns portions of argv and memory allocated by allocator.
Options parse_options(int argc, char **argv, Monotonic_Allocator *allocator);
}

// quick-lint-js finds bugs in JavaScript programs.
Expand Down
105 changes: 56 additions & 49 deletions test/test-options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,29 @@ using namespace std::literals::string_view_literals;

namespace quick_lint_js {
namespace {
Options parse_options(std::initializer_list<const char *> arguments) {
std::vector<char *> argv;
argv.emplace_back(const_cast<char *>("(program)"));
for (const char *argument : arguments) {
argv.emplace_back(const_cast<char *>(argument));
class Test_Options : public ::testing::Test {
public:
Options parse_options(std::initializer_list<const char *> arguments) {
std::vector<char *> argv;
argv.emplace_back(const_cast<char *>("(program)"));
for (const char *argument : arguments) {
argv.emplace_back(const_cast<char *>(argument));
}
return quick_lint_js::parse_options(narrow_cast<int>(argv.size()),
argv.data(), &this->allocator);
}
return quick_lint_js::parse_options(narrow_cast<int>(argv.size()),
argv.data());
}

Options parse_options_no_errors(std::initializer_list<const char *> arguments) {
Options o = parse_options(arguments);
EXPECT_THAT(o.error_unrecognized_options, IsEmpty());
EXPECT_THAT(o.warning_language_without_file, IsEmpty());
EXPECT_THAT(o.warning_vim_bufnr_without_file, IsEmpty());
return o;
}
Options parse_options_no_errors(
std::initializer_list<const char *> arguments) {
Options o = this->parse_options(arguments);
EXPECT_THAT(o.error_unrecognized_options, IsEmpty());
EXPECT_THAT(o.warning_language_without_file, IsEmpty());
EXPECT_THAT(o.warning_vim_bufnr_without_file, IsEmpty());
return o;
}

Monotonic_Allocator allocator{"Test_Options"};
};

struct Dumped_Errors {
bool have_errors;
Expand All @@ -54,7 +60,7 @@ Dumped_Errors dump_errors(const Options &o) {
};
}

TEST(Test_Options, default_options_with_no_files) {
TEST_F(Test_Options, default_options_with_no_files) {
Options o = parse_options_no_errors({});
EXPECT_FALSE(o.print_parser_visits);
EXPECT_FALSE(o.help);
Expand All @@ -65,15 +71,15 @@ TEST(Test_Options, default_options_with_no_files) {
EXPECT_THAT(o.files_to_lint, IsEmpty());
}

TEST(Test_Options, default_options_with_files) {
TEST_F(Test_Options, default_options_with_files) {
Options o = parse_options_no_errors({"foo.js"});
EXPECT_FALSE(o.print_parser_visits);
EXPECT_FALSE(o.snarky);
ASSERT_EQ(o.files_to_lint.size(), 1);
EXPECT_EQ(o.files_to_lint[0].path, "foo.js"sv);
}

TEST(Test_Options, hyphen_hyphen_treats_remaining_arguments_as_files) {
TEST_F(Test_Options, hyphen_hyphen_treats_remaining_arguments_as_files) {
{
Options o = parse_options_no_errors({"--", "foo.js"});
ASSERT_EQ(o.files_to_lint.size(), 1);
Expand All @@ -91,21 +97,21 @@ TEST(Test_Options, hyphen_hyphen_treats_remaining_arguments_as_files) {
}
}

TEST(Test_Options, debug_parser_visits) {
TEST_F(Test_Options, debug_parser_visits) {
Options o = parse_options_no_errors({"--debug-parser-visits", "foo.js"});
EXPECT_TRUE(o.print_parser_visits);
ASSERT_EQ(o.files_to_lint.size(), 1);
EXPECT_EQ(o.files_to_lint[0].path, "foo.js"sv);
}

TEST(Test_Options, snarky) {
TEST_F(Test_Options, snarky) {
Options o = parse_options_no_errors({"--snarky", "foo.js"});
EXPECT_TRUE(o.snarky);
ASSERT_EQ(o.files_to_lint.size(), 1);
EXPECT_EQ(o.files_to_lint[0].path, "foo.js"sv);
}

TEST(Test_Options, debug_parser_visits_shorthand) {
TEST_F(Test_Options, debug_parser_visits_shorthand) {
{
Options o = parse_options_no_errors({"--debug-p", "foo.js"});
EXPECT_TRUE(o.print_parser_visits);
Expand All @@ -117,7 +123,7 @@ TEST(Test_Options, debug_parser_visits_shorthand) {
}
}

TEST(Test_Options, output_format) {
TEST_F(Test_Options, output_format) {
{
Options o = parse_options_no_errors({});
EXPECT_EQ(o.output_format, Output_Format::default_format);
Expand All @@ -139,7 +145,7 @@ TEST(Test_Options, output_format) {
}
}

TEST(Test_Options, invalid_output_format) {
TEST_F(Test_Options, invalid_output_format) {
{
Options o = parse_options({"--output-format=unknown-garbage"});
EXPECT_THAT(o.error_unrecognized_options,
Expand All @@ -155,7 +161,7 @@ TEST(Test_Options, invalid_output_format) {
}
}

TEST(Test_Options, vim_file_bufnr) {
TEST_F(Test_Options, vim_file_bufnr) {
{
Options o = parse_options_no_errors({"one.js", "two.js"});
ASSERT_EQ(o.files_to_lint.size(), 2);
Expand Down Expand Up @@ -217,7 +223,7 @@ TEST(Test_Options, vim_file_bufnr) {
}
}

TEST(Test_Options, path_for_config_search) {
TEST_F(Test_Options, path_for_config_search) {
{
Options o = parse_options_no_errors({"one.js", "two.js"});
ASSERT_EQ(o.files_to_lint.size(), 2);
Expand Down Expand Up @@ -289,7 +295,7 @@ TEST(Test_Options, path_for_config_search) {
}
}

TEST(Test_Options, config_file) {
TEST_F(Test_Options, config_file) {
{
Options o = parse_options_no_errors({"one.js", "two.js"});
ASSERT_EQ(o.files_to_lint.size(), 2);
Expand Down Expand Up @@ -353,7 +359,7 @@ TEST(Test_Options, config_file) {
}
}

TEST(Test_Options, language) {
TEST_F(Test_Options, language) {
constexpr Raw_Input_File_Language default_language =
Raw_Input_File_Language::default_;

Expand Down Expand Up @@ -448,7 +454,7 @@ TEST(Test_Options, language) {
}
}

TEST(Test_Options, language_after_file) {
TEST_F(Test_Options, language_after_file) {
Options o = parse_options({"file.js", "--language=javascript-jsx"});
EXPECT_THAT(o.warning_language_without_file,
ElementsAreArray({"javascript-jsx"sv}));
Expand All @@ -461,7 +467,7 @@ TEST(Test_Options, language_after_file) {
u8"input file name or --stdin\n");
}

TEST(Test_Options, multiple_languages) {
TEST_F(Test_Options, multiple_languages) {
Options o = parse_options(
{"--language=javascript", "--language=javascript-jsx", "test.jsx"});
EXPECT_THAT(o.warning_language_without_file,
Expand All @@ -474,15 +480,16 @@ TEST(Test_Options, multiple_languages) {
u8"input file name or --stdin\n");
}

TEST(Test_Options, invalid_language) {
TEST_F(Test_Options, invalid_language) {
Options o = parse_options({"--language=badlanguageid", "test.js"});
EXPECT_THAT(o.warning_language_without_file, IsEmpty());
// TODO(strager): Highlight the full option, not just the value.
EXPECT_THAT(o.error_unrecognized_options,
ElementsAreArray({"badlanguageid"sv}));
}

TEST(Test_Options, default_language_is_javascript_jsx_regardless_of_extension) {
TEST_F(Test_Options,
default_language_is_javascript_jsx_regardless_of_extension) {
constexpr auto default_language = Raw_Input_File_Language::default_;
constexpr auto javascript_jsx = Resolved_Input_File_Language::javascript_jsx;
EXPECT_EQ(get_language("<stdin>", default_language), javascript_jsx);
Expand All @@ -495,8 +502,8 @@ TEST(Test_Options, default_language_is_javascript_jsx_regardless_of_extension) {
EXPECT_EQ(get_language("hi.txt", default_language), javascript_jsx);
}

TEST(Test_Options,
experimental_default_language_guesses_language_from_extension) {
TEST_F(Test_Options,
experimental_default_language_guesses_language_from_extension) {
constexpr auto default_language =
Raw_Input_File_Language::experimental_default;
constexpr auto javascript_jsx = Resolved_Input_File_Language::javascript_jsx;
Expand All @@ -522,7 +529,7 @@ TEST(Test_Options,
}
}

TEST(Test_Options, get_language_overwritten) {
TEST_F(Test_Options, get_language_overwritten) {
constexpr auto in_javascript = Raw_Input_File_Language::javascript;
constexpr auto in_javascript_jsx = Raw_Input_File_Language::javascript_jsx;
constexpr auto javascript = Resolved_Input_File_Language::javascript;
Expand All @@ -539,7 +546,7 @@ TEST(Test_Options, get_language_overwritten) {
EXPECT_EQ(get_language("hi.txt", in_javascript), javascript);
}

TEST(Test_Options, lsp_server) {
TEST_F(Test_Options, lsp_server) {
{
Options o = parse_options_no_errors({"--lsp-server"});
EXPECT_TRUE(o.lsp_server);
Expand All @@ -551,7 +558,7 @@ TEST(Test_Options, lsp_server) {
}
}

TEST(Test_Options, stdin_file) {
TEST_F(Test_Options, stdin_file) {
{
Options o = parse_options_no_errors({"--stdin", "one.js"});
ASSERT_EQ(o.files_to_lint.size(), 2);
Expand All @@ -577,7 +584,7 @@ TEST(Test_Options, stdin_file) {
}
}

TEST(Test_Options, is_stdin_emplaced_only_once) {
TEST_F(Test_Options, is_stdin_emplaced_only_once) {
{
Options o = parse_options_no_errors({"--stdin", "one.js", "-", "two.js"});
ASSERT_EQ(o.files_to_lint.size(), 3);
Expand All @@ -590,7 +597,7 @@ TEST(Test_Options, is_stdin_emplaced_only_once) {
}
}

TEST(Test_Options, path_for_stdin) {
TEST_F(Test_Options, path_for_stdin) {
{
Options o = parse_options_no_errors({"--stdin-path", "a.js", "--stdin"});
ASSERT_EQ(o.files_to_lint.size(), 1);
Expand Down Expand Up @@ -641,7 +648,7 @@ TEST(Test_Options, path_for_stdin) {
}
}

TEST(Test_Options, print_help) {
TEST_F(Test_Options, print_help) {
{
Options o = parse_options_no_errors({"--help"});
EXPECT_TRUE(o.help);
Expand All @@ -658,12 +665,12 @@ TEST(Test_Options, print_help) {
}
}

TEST(Test_Options, list_debug_apps) {
TEST_F(Test_Options, list_debug_apps) {
Options o = parse_options_no_errors({"--debug-apps"});
EXPECT_TRUE(o.list_debug_apps);
}

TEST(Test_Options, print_version) {
TEST_F(Test_Options, print_version) {
{
Options o = parse_options_no_errors({"--version"});
EXPECT_TRUE(o.version);
Expand All @@ -680,7 +687,7 @@ TEST(Test_Options, print_version) {
}
}

TEST(Test_Options, exit_fail_on) {
TEST_F(Test_Options, exit_fail_on) {
{
Options o = parse_options_no_errors({"--exit-fail-on=E0003", "file.js"});
EXPECT_TRUE(
Expand All @@ -692,7 +699,7 @@ TEST(Test_Options, exit_fail_on) {
}
}

TEST(Test_Options, invalid_vim_file_bufnr) {
TEST_F(Test_Options, invalid_vim_file_bufnr) {
{
Options o = parse_options({"--vim-file-bufnr=garbage", "file.js"});
EXPECT_THAT(o.error_unrecognized_options, ElementsAreArray({"garbage"sv}));
Expand All @@ -705,7 +712,7 @@ TEST(Test_Options, invalid_vim_file_bufnr) {
}
}

TEST(Test_Options, no_following_filename_vim_file_bufnr) {
TEST_F(Test_Options, no_following_filename_vim_file_bufnr) {
{
Options o = parse_options({"foo.js", "--vim-file-bufnr=1"});
o.output_format = Output_Format::vim_qflist_json;
Expand Down Expand Up @@ -776,7 +783,7 @@ TEST(Test_Options, no_following_filename_vim_file_bufnr) {
}
}

TEST(Test_Options, using_vim_file_bufnr_without_format) {
TEST_F(Test_Options, using_vim_file_bufnr_without_format) {
{
for (const auto &format : {
Output_Format::default_format,
Expand All @@ -803,7 +810,7 @@ TEST(Test_Options, using_vim_file_bufnr_without_format) {
}
}

TEST(Test_Options, using_vim_file_bufnr_in_lsp_mode) {
TEST_F(Test_Options, using_vim_file_bufnr_in_lsp_mode) {
{
Options o = parse_options({"--lsp-server", "--vim-file-bufnr=1"});

Expand All @@ -824,7 +831,7 @@ TEST(Test_Options, using_vim_file_bufnr_in_lsp_mode) {
}
}

TEST(Test_Options, using_language_in_lsp_mode) {
TEST_F(Test_Options, using_language_in_lsp_mode) {
{
Options o = parse_options({"--lsp-server", "--language=javascript"});

Expand All @@ -846,7 +853,7 @@ TEST(Test_Options, using_language_in_lsp_mode) {
}
}

TEST(Test_Options, invalid_option) {
TEST_F(Test_Options, invalid_option) {
{
Options o = parse_options({"--option-does-not-exist", "foo.js"});
EXPECT_THAT(o.error_unrecognized_options,
Expand Down Expand Up @@ -875,7 +882,7 @@ TEST(Test_Options, invalid_option) {
}
}

TEST(Test_Options, dump_errors) {
TEST_F(Test_Options, dump_errors) {
{
Options o;
o.error_unrecognized_options.clear();
Expand Down

0 comments on commit 3d7b0d6

Please sign in to comment.