lib/rgot/m.rb in rgot-1.2.0 vs lib/rgot/m.rb in rgot-1.3.0

- old
+ new

@@ -10,33 +10,51 @@ :bench, :benchtime, :timeout, :cpu, :thread, + :fuzz, + :fuzztime, ); end - def initialize(tests:, benchmarks:, examples:, test_module: nil, opts: Options.new) + def initialize(tests:, benchmarks:, examples:, fuzz_targets: nil, test_module: nil, opts: Options.new) + unless fuzz_targets + raise "Require `fuzz_targets` keyword" if Gem::Version.new("2.0") <= Gem::Version.new(Rgot::VERSION) + warn "`Rgot::M#initialize` will require the `fuzz_targets` keyword in the next major version." + end unless test_module raise "Require `test_module` keyword" if Gem::Version.new("2.0") <= Gem::Version.new(Rgot::VERSION) warn "`Rgot::M#initialize` will require the `test_module` keyword in the next major version." end @tests = tests @benchmarks = benchmarks @examples = examples + @fuzz_targets = fuzz_targets || [] @test_module = test_module @opts = opts - @cpu_list = nil - @thread_list = nil + + @cpu_list = [] + @thread_list = [] + @fs = @fuzz_targets.map do |fuzz_target| + F.new( + fuzz_target: fuzz_target, + opts: F::Options.new( + fuzz: opts.fuzz, + fuzztime: opts.fuzztime, + ) + ) + end end def run duration = Rgot.now test_ok = false + fuzz_targets_ok = false example_ok = false - if @tests.empty? && @benchmarks.empty? && @examples.empty? + if @tests.empty? && @benchmarks.empty? && @examples.empty? && @fuzz_targets.empty? warn "rgot: warning: no tests to run" end begin parse_option @@ -45,26 +63,33 @@ raise end Timeout.timeout(@opts.timeout.to_f) do test_ok = run_tests + fuzz_targets_ok = run_fuzz_tests example_ok = run_examples end - if !test_ok || !example_ok + if !test_ok || !example_ok || !fuzz_targets_ok puts "FAIL" puts "exit status 1" puts sprintf("%s\t%s\t%.3fs", "FAIL", @test_module, Rgot.now - duration) + return 1 + end - 1 - else - puts "PASS" - run_benchmarks - puts sprintf("%s\t%s\t%.3fs", "ok ", @test_module, Rgot.now - duration) - - 0 + if !run_fuzzing() + puts "FAIL" + puts "exit status 1" + puts sprintf("%s\t%s\t%.3fs", "FAIL", @test_module, Rgot.now - duration) + return 1 end + + puts "PASS" + run_benchmarks + puts sprintf("%s\t%s\t%.3fs", "ok ", @test_module, Rgot.now - duration) + + 0 end private def parse_option @@ -88,13 +113,11 @@ t = T.new(test.module, test.name.to_sym) if Rgot.verbose? puts "=== RUN #{test.name}" end t.run - if t.failed? - ok = false - end + ok = ok && !t.failed? end ok end def run_benchmarks @@ -128,10 +151,54 @@ end end ok end + def run_fuzz_tests + ok = true + @fs.each do |f| + if Rgot.verbose? + if f.fuzz? + puts "=== FUZZ #{f.name}" + else + puts "=== RUN #{f.name}" + end + end + f.run_testing + ok = ok && !f.failed? + end + ok + end + + def run_fuzzing + if @fuzz_targets.empty? || @opts.fuzz.nil? + return true + end + + fuzzing_fs = @fs.select(&:fuzz?) + + if fuzzing_fs.empty? + puts "rgot: warning: no fuzz tests to fuzz" + return true + end + + if fuzzing_fs.length > 1 + names = fuzzing_fs.map(&:name) + puts "rgot: will not fuzz, --fuzz matches more than one fuzz test: #{names.inspect}" + return false + end + + ok = true + + fuzzing_fs.each do |f| + f.run_fuzzing + ok = ok && !f.failed? + end + + ok + end + def run_examples ok = true @examples.each do |example| if Rgot.verbose? puts "=== RUN #{example.name}" @@ -141,16 +208,16 @@ example.module.extend(example.module) method = example.module.instance_method(example.name).bind(example.module) out, _ = capture do method.call end - file = method.source_location[0] - r = ExampleParser.new(File.read(file)) - r.parse - e = r.examples.find { |re| re.name == example.name } + file = method.source_location&.[](0) or raise("bug") + example_parser = ExampleParser.new(File.read(file)) + example_parser.parse + e = example_parser.examples.find { |er| er.name == example.name } or raise("bug") duration = Rgot.now - start - if e && e.output.strip != out.strip + if e.output.strip != out.strip printf("--- FAIL: %s (%.2fs)\n", e.name, duration) ok = false puts "got:" puts out.strip puts "want:"