From 7294f2da67345213595ad3eb8aa5eed971c6f0f1 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 8 May 2021 23:45:54 -0600 Subject: [PATCH] Change ConfigSource to "applicator" Remove unecessary abstract base class. Shorten name of CLI arguments config applicator. --- src/spectator.cr | 4 +- .../command_line_arguments_config_source.cr | 207 ----------------- .../config/cli_arguments_applicator.cr | 208 ++++++++++++++++++ src/spectator/config_source.cr | 10 - 4 files changed, 210 insertions(+), 219 deletions(-) delete mode 100644 src/spectator/command_line_arguments_config_source.cr create mode 100644 src/spectator/config/cli_arguments_applicator.cr delete mode 100644 src/spectator/config_source.cr diff --git a/src/spectator.cr b/src/spectator.cr index 88238a8..bff5ef3 100644 --- a/src/spectator.cr +++ b/src/spectator.cr @@ -107,11 +107,11 @@ module Spectator private def apply_config_file(file_path = CONFIG_FILE_PATH) : Nil return unless File.exists?(file_path) args = File.read(file_path).lines - CommandLineArgumentsConfigSource.new(args).apply(@@config_builder) + Config::CLIArgumentsApplicator.new(args).apply(@@config_builder) end # Applies configuration options from the command-line arguments private def apply_command_line_args : Nil - CommandLineArgumentsConfigSource.new.apply(@@config_builder) + Config::CLIArgumentsApplicator.new.apply(@@config_builder) end end diff --git a/src/spectator/command_line_arguments_config_source.cr b/src/spectator/command_line_arguments_config_source.cr deleted file mode 100644 index 1eeba61..0000000 --- a/src/spectator/command_line_arguments_config_source.cr +++ /dev/null @@ -1,207 +0,0 @@ -require "option_parser" -require "./config_source" -require "./formatting" -require "./line_example_filter" -require "./location" -require "./location_example_filter" -require "./name_example_filter" - -module Spectator - # Generates configuration from the command-line arguments. - class CommandLineArgumentsConfigSource < ConfigSource - # Logger for this class. - Log = Spectator::Log.for("config") - - # Creates the configuration source. - # By default, the command-line arguments (ARGV) are used. - # But custom arguments can be passed in. - def initialize(@args : Array(String) = ARGV) - end - - # Applies the specified configuration to a builder. - # Calling this method from multiple sources builds up the final configuration. - def apply(builder : ConfigBuilder) : Nil - OptionParser.parse(@args) do |parser| - control_parser_options(parser, builder) - filter_parser_options(parser, builder) - output_parser_options(parser, builder) - end - end - - # Adds options to the parser for controlling the test execution. - private def control_parser_options(parser, builder) - fail_fast_option(parser, builder) - fail_blank_option(parser, builder) - dry_run_option(parser, builder) - random_option(parser, builder) - seed_option(parser, builder) - order_option(parser, builder) - end - - # Adds the fail-fast option to the parser. - private def fail_fast_option(parser, builder) - parser.on("-f", "--fail-fast", "Stop testing on first failure") do - Log.debug { "Enabling fail-fast (-f)" } - builder.fail_fast - end - end - - # Adds the fail-blank option to the parser. - private def fail_blank_option(parser, builder) - parser.on("-b", "--fail-blank", "Fail if there are no examples") do - Log.debug { "Enabling fail-blank (-b)" } - builder.fail_blank - end - end - - # Adds the dry-run option to the parser. - private def dry_run_option(parser, builder) - parser.on("-d", "--dry-run", "Don't run any tests, output what would have run") do - Log.debug { "Enabling dry-run (-d)" } - builder.dry_run - end - end - - # Adds the randomize examples option to the parser. - private def random_option(parser, builder) - parser.on("-r", "--rand", "Randomize the execution order of tests") do - Log.debug { "Randomizing test order (-r)" } - builder.randomize - end - end - - # Adds the random seed option to the parser. - private def seed_option(parser, builder) - parser.on("--seed INTEGER", "Set the seed for the random number generator (implies -r)") do |seed| - Log.debug { "Randomizing test order and setting RNG seed to #{seed}" } - builder.randomize - builder.random_seed = seed.to_u64 - end - end - - # Adds the example order option to the parser. - private def order_option(parser, builder) - parser.on("--order ORDER", "Set the test execution order. ORDER should be one of: defined, rand, or rand:SEED") do |method| - case method.downcase - when "defined" - Log.debug { "Disabling randomized tests (--order defined)" } - builder.randomize = false - when /^rand/ - builder.randomize - parts = method.split(':', 2) - if (seed = parts[1]?) - Log.debug { "Randomizing test order and setting RNG seed to #{seed} (--order rand:#{seed})" } - builder.random_seed = seed.to_u64 - else - Log.debug { "Randomizing test order (--order rand)" } - end - else - nil - end - end - end - - # Adds options to the parser for filtering examples. - private def filter_parser_options(parser, builder) - example_option(parser, builder) - line_option(parser, builder) - location_option(parser, builder) - end - - # Adds the example filter option to the parser. - private def example_option(parser, builder) - parser.on("-e", "--example STRING", "Run examples whose full nested names include STRING") do |pattern| - Log.debug { "Filtering for examples named '#{pattern}' (-e '#{pattern}')" } - filter = NameExampleFilter.new(pattern) - builder.add_example_filter(filter) - end - end - - # Adds the line filter option to the parser. - private def line_option(parser, builder) - parser.on("-l", "--line LINE", "Run examples whose line matches LINE") do |line| - Log.debug { "Filtering for examples on line #{line} (-l #{line})" } - filter = LineExampleFilter.new(line.to_i) - builder.add_example_filter(filter) - end - end - - # Adds the location filter option to the parser. - private def location_option(parser, builder) - parser.on("--location FILE:LINE", "Run the example at line 'LINE' in the file 'FILE', multiple allowed") do |location| - Log.debug { "Filtering for examples at #{location} (--location '#{location}')" } - location = Location.parse(location) - filter = LocationExampleFilter.new(location) - builder.add_example_filter(filter) - end - end - - # Adds options to the parser for changing output. - private def output_parser_options(parser, builder) - verbose_option(parser, builder) - help_option(parser, builder) - profile_option(parser, builder) - json_option(parser, builder) - tap_option(parser, builder) - junit_option(parser, builder) - no_color_option(parser, builder) - end - - # Adds the verbose output option to the parser. - private def verbose_option(parser, builder) - parser.on("-v", "--verbose", "Verbose output using document formatter") do - Log.debug { "Setting output format to document (-v)" } - builder.formatter = Formatting::DocumentFormatter.new - end - end - - # Adds the help output option to the parser. - private def help_option(parser, builder) - parser.on("-h", "--help", "Show this help") do - puts parser - exit - end - end - - # Adds the profile output option to the parser. - private def profile_option(parser, builder) - parser.on("-p", "--profile", "Display the 10 slowest specs") do - Log.debug { "Enabling timing information (-p)" } - builder.profile - end - end - - # Adds the JSON output option to the parser. - private def json_option(parser, builder) - parser.on("--json", "Generate JSON output") do - Log.debug { "Setting output format to JSON (--json)" } - builder.formatter = Formatting::JsonFormatter.new - end - end - - # Adds the TAP output option to the parser. - private def tap_option(parser, builder) - parser.on("--tap", "Generate TAP output (Test Anything Protocol)") do - Log.debug { "Setting output format to TAP (--tap)" } - builder.formatter = Formatting::TAPFormatter.new - end - end - - # Adds the JUnit output option to the parser. - private def junit_option(parser, builder) - parser.on("--junit_output OUTPUT_DIR", "Generate JUnit XML output") do |output_dir| - Log.debug { "Setting output format to JUnit XML (--junit_output '#{output_dir}')" } - formatter = Formatting::JUnitFormatter.new(output_dir) - builder.add_formatter(formatter) - end - end - - # Adds the "no color" output option to the parser. - private def no_color_option(parser, builder) - parser.on("--no-color", "Disable colored output") do - Log.debug { "Disabling color output (--no-color)" } - Colorize.enabled = false - end - end - end -end diff --git a/src/spectator/config/cli_arguments_applicator.cr b/src/spectator/config/cli_arguments_applicator.cr new file mode 100644 index 0000000..396157f --- /dev/null +++ b/src/spectator/config/cli_arguments_applicator.cr @@ -0,0 +1,208 @@ +require "option_parser" +require "../formatting" +require "../line_example_filter" +require "../location" +require "../location_example_filter" +require "../name_example_filter" + +module Spectator + class Config + # Applies command-line arguments to a configuration. + class CLIArgumentsApplicator + # Logger for this class. + Log = Spectator::Log.for("config") + + # Creates the configuration source. + # By default, the command-line arguments (ARGV) are used. + # But custom arguments can be passed in. + def initialize(@args : Array(String) = ARGV) + end + + # Applies the specified configuration to a builder. + # Calling this method from multiple sources builds up the final configuration. + def apply(builder) : Nil + OptionParser.parse(@args) do |parser| + control_parser_options(parser, builder) + filter_parser_options(parser, builder) + output_parser_options(parser, builder) + end + end + + # Adds options to the parser for controlling the test execution. + private def control_parser_options(parser, builder) + fail_fast_option(parser, builder) + fail_blank_option(parser, builder) + dry_run_option(parser, builder) + random_option(parser, builder) + seed_option(parser, builder) + order_option(parser, builder) + end + + # Adds the fail-fast option to the parser. + private def fail_fast_option(parser, builder) + parser.on("-f", "--fail-fast", "Stop testing on first failure") do + Log.debug { "Enabling fail-fast (-f)" } + builder.fail_fast + end + end + + # Adds the fail-blank option to the parser. + private def fail_blank_option(parser, builder) + parser.on("-b", "--fail-blank", "Fail if there are no examples") do + Log.debug { "Enabling fail-blank (-b)" } + builder.fail_blank + end + end + + # Adds the dry-run option to the parser. + private def dry_run_option(parser, builder) + parser.on("-d", "--dry-run", "Don't run any tests, output what would have run") do + Log.debug { "Enabling dry-run (-d)" } + builder.dry_run + end + end + + # Adds the randomize examples option to the parser. + private def random_option(parser, builder) + parser.on("-r", "--rand", "Randomize the execution order of tests") do + Log.debug { "Randomizing test order (-r)" } + builder.randomize + end + end + + # Adds the random seed option to the parser. + private def seed_option(parser, builder) + parser.on("--seed INTEGER", "Set the seed for the random number generator (implies -r)") do |seed| + Log.debug { "Randomizing test order and setting RNG seed to #{seed}" } + builder.randomize + builder.random_seed = seed.to_u64 + end + end + + # Adds the example order option to the parser. + private def order_option(parser, builder) + parser.on("--order ORDER", "Set the test execution order. ORDER should be one of: defined, rand, or rand:SEED") do |method| + case method.downcase + when "defined" + Log.debug { "Disabling randomized tests (--order defined)" } + builder.randomize = false + when /^rand/ + builder.randomize + parts = method.split(':', 2) + if (seed = parts[1]?) + Log.debug { "Randomizing test order and setting RNG seed to #{seed} (--order rand:#{seed})" } + builder.random_seed = seed.to_u64 + else + Log.debug { "Randomizing test order (--order rand)" } + end + else + nil + end + end + end + + # Adds options to the parser for filtering examples. + private def filter_parser_options(parser, builder) + example_option(parser, builder) + line_option(parser, builder) + location_option(parser, builder) + end + + # Adds the example filter option to the parser. + private def example_option(parser, builder) + parser.on("-e", "--example STRING", "Run examples whose full nested names include STRING") do |pattern| + Log.debug { "Filtering for examples named '#{pattern}' (-e '#{pattern}')" } + filter = NameExampleFilter.new(pattern) + builder.add_example_filter(filter) + end + end + + # Adds the line filter option to the parser. + private def line_option(parser, builder) + parser.on("-l", "--line LINE", "Run examples whose line matches LINE") do |line| + Log.debug { "Filtering for examples on line #{line} (-l #{line})" } + filter = LineExampleFilter.new(line.to_i) + builder.add_example_filter(filter) + end + end + + # Adds the location filter option to the parser. + private def location_option(parser, builder) + parser.on("--location FILE:LINE", "Run the example at line 'LINE' in the file 'FILE', multiple allowed") do |location| + Log.debug { "Filtering for examples at #{location} (--location '#{location}')" } + location = Location.parse(location) + filter = LocationExampleFilter.new(location) + builder.add_example_filter(filter) + end + end + + # Adds options to the parser for changing output. + private def output_parser_options(parser, builder) + verbose_option(parser, builder) + help_option(parser, builder) + profile_option(parser, builder) + json_option(parser, builder) + tap_option(parser, builder) + junit_option(parser, builder) + no_color_option(parser, builder) + end + + # Adds the verbose output option to the parser. + private def verbose_option(parser, builder) + parser.on("-v", "--verbose", "Verbose output using document formatter") do + Log.debug { "Setting output format to document (-v)" } + builder.formatter = Formatting::DocumentFormatter.new + end + end + + # Adds the help output option to the parser. + private def help_option(parser, builder) + parser.on("-h", "--help", "Show this help") do + puts parser + exit + end + end + + # Adds the profile output option to the parser. + private def profile_option(parser, builder) + parser.on("-p", "--profile", "Display the 10 slowest specs") do + Log.debug { "Enabling timing information (-p)" } + builder.profile + end + end + + # Adds the JSON output option to the parser. + private def json_option(parser, builder) + parser.on("--json", "Generate JSON output") do + Log.debug { "Setting output format to JSON (--json)" } + builder.formatter = Formatting::JSONFormatter.new + end + end + + # Adds the TAP output option to the parser. + private def tap_option(parser, builder) + parser.on("--tap", "Generate TAP output (Test Anything Protocol)") do + Log.debug { "Setting output format to TAP (--tap)" } + builder.formatter = Formatting::TAPFormatter.new + end + end + + # Adds the JUnit output option to the parser. + private def junit_option(parser, builder) + parser.on("--junit_output OUTPUT_DIR", "Generate JUnit XML output") do |output_dir| + Log.debug { "Setting output format to JUnit XML (--junit_output '#{output_dir}')" } + formatter = Formatting::JUnitFormatter.new(output_dir) + builder.add_formatter(formatter) + end + end + + # Adds the "no color" output option to the parser. + private def no_color_option(parser, builder) + parser.on("--no-color", "Disable colored output") do + Log.debug { "Disabling color output (--no-color)" } + Colorize.enabled = false + end + end + end + end +end diff --git a/src/spectator/config_source.cr b/src/spectator/config_source.cr deleted file mode 100644 index 472ea8a..0000000 --- a/src/spectator/config_source.cr +++ /dev/null @@ -1,10 +0,0 @@ -require "./config_builder" - -module Spectator - # Interface for all places that configuration can originate. - abstract class ConfigSource - # Applies the specified configuration to a builder. - # Calling this method from multiple sources builds up the final configuration. - abstract def apply(builder : ConfigBuilder) : Nil - end -end