require_relative 'engine_adapter' module SassSpec::CLI require 'optparse' def self.parse options = { engine_adapter: nil, spec_directory: nil, generate: false, tap: false, skip: false, verbose: false, filter: "", implementation: 'sass' } OptionParser.new do |opts| opts.banner = "Usage: ./sass-spec.rb [options] [spec_directory...] Examples: Run `sassc --style compressed input.scss`: ./sass-spec.rb -c 'sass --style compressed' Run tests only in the spec/basic folder: ./sass-spec.rb spec/basic This script will search for all files under the spec (or specified) directory that are named input.scss. It will then run a specified binary and check that the output matches the expected output. If you want set up your own test suite, follow a similar hierarchy as described in the initial comment of this script for your test hierarchy. This command can also be used to annotate tests to control which tests are ran and when. For details: ./sass-spec.rb annotate -h Make sure the command you provide prints to stdout. " opts.on("-v", "--verbose", "Run verbosely") do options[:verbose] = true end opts.on("-t", "--tap", "Output TAP compatible report") do options[:tap] = true end opts.on("-c", "--command COMMAND", "Sets a specific binary to run") do |v| options[:engine_adapter] = ExecutableEngineAdapter.new(v) options[:engine_adapter].args = options[:cmd_args] end opts.on("--dart PATH", "Run Dart Sass, whose repo should be at the given path.") do |path| options[:engine_adapter] = DartEngineAdapter.new(path) options[:engine_adapter].args = options[:cmd_args] end opts.on("--cmd-args ARGS", "Pass ARGS to command or Dart Sass.") do |args| if (adapter = options[:engine_adapter]) && adapter.is_a?(DartEngineAdapter) adapter.args = args elsif (adapter = options[:engine_adapter]) && adapter.is_a?(ExecutableEngineAdapter) adapter.args = args else options[:cmd_args] = args end end opts.on("-g", "--generate", "Run test(s) and generate expected output file(s).") do options[:generate] = true end opts.on("--run-todo", "Run any tests marked as todo. Defaults to false.") do options[:run_todo] = true end opts.on("--probe-todo", "Run and report tests marked as todo that unexpectedly pass. Defaults to false.") do options[:probe_todo] = options[:run_todo] = true end opts.on("--impl NAME", "Sets the name of the implementation being tested. Defaults to 'sass'") do |name| options[:implementation] = name end opts.on("--filter PATTERN", "Run tests that match the pattern you provide") do |pattern| options[:filter] = pattern end opts.on("--limit NUMBER", "Limit the number of tests run to this positive integer.") do |limit| raise "--limit must receive a positive integer" if limit.to_i < 0 options[:limit] = limit.to_i end opts.on("--migrate-impl", "Copy tests that fail and make them pass for the current implementatino.") do options[:migrate_impl] = true end opts.on("--silent", "Don't show any logs") do options[:silent] = true end opts.on("--check-annotations", "Check if any test annotations are unnecessary.") do options[:check_annotations] = true end opts.on("--interactive", "When a test fails, enter into a dialog for how to handle it.") do options[:interactive] = true end end.parse! raise "Must specify either --dart or --command." if options[:engine_adapter].nil? options[:spec_dirs_to_run] = ARGV.dup.map{|d| File.expand_path(d)} if ARGV.any? if options[:implementation] && options[:engine_adapter].respond_to?(:set_description) options[:engine_adapter].set_description(options[:implementation]) end options end end