rgot 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +5 -5
- data/.gitignore +1 -1
- data/Gemfile +4 -0
- data/Gemfile.lock +73 -0
- data/README.md +72 -2
- data/Rakefile +3 -0
- data/Steepfile +4 -0
- data/bin/rgot +1 -1
- data/lib/rgot/b.rb +17 -14
- data/lib/rgot/benchmark_result.rb +6 -0
- data/lib/rgot/cli.rb +99 -72
- data/lib/rgot/common.rb +8 -4
- data/lib/rgot/example_parser.rb +6 -1
- data/lib/rgot/f.rb +230 -0
- data/lib/rgot/m.rb +121 -22
- data/lib/rgot/pb.rb +2 -2
- data/lib/rgot/t.rb +8 -4
- data/lib/rgot/version.rb +3 -1
- data/lib/rgot.rb +12 -8
- data/rbs_collection.lock.yaml +49 -0
- data/rbs_collection.yaml +53 -0
- data/rgot.gemspec +1 -1
- data/sig/patch.rbs +3 -0
- data/sig/rgot.rbs +232 -0
- metadata +10 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: e2f0075689755b0a44db0674a5069769d1ee4c2567774d7bb7422ba5b27c8960
         | 
| 4 | 
            +
              data.tar.gz: 9ddd64091ca0daeff256fcc5c305aad378a92472f4522b875512fb35915d74aa
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 2e24662ccc2f6f4644eec95f9764975b86d2ea40f49c3c8ae569f428809ca08df79e6517d2bbcf0ec7d08e610867972133a1a9ab5df245cf36896afb8ace7e63
         | 
| 7 | 
            +
              data.tar.gz: ac5c041deb124812d911d0af697a06a398ced2c79bc54f6058ec4cb2499af9dd814007f3e0c8951c50448892ba0fbc0a6846dfd879c3497601b4aebf5d00116e
         | 
    
        data/.github/workflows/main.yml
    CHANGED
    
    | @@ -14,13 +14,13 @@ jobs: | |
| 14 14 | 
             
                strategy:
         | 
| 15 15 | 
             
                  matrix:
         | 
| 16 16 | 
             
                    ruby:
         | 
| 17 | 
            -
                      - '2. | 
| 18 | 
            -
                      - ' | 
| 19 | 
            -
                      - '3. | 
| 20 | 
            -
                      - '3. | 
| 17 | 
            +
                      - '2.7.7'
         | 
| 18 | 
            +
                      - '3.0.5'
         | 
| 19 | 
            +
                      - '3.1.3'
         | 
| 20 | 
            +
                      - '3.2.0'
         | 
| 21 21 |  | 
| 22 22 | 
             
                steps:
         | 
| 23 | 
            -
                - uses: actions/checkout@ | 
| 23 | 
            +
                - uses: actions/checkout@v3
         | 
| 24 24 | 
             
                - name: Set up Ruby
         | 
| 25 25 | 
             
                  uses: ruby/setup-ruby@v1
         | 
| 26 26 | 
             
                  with:
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/Gemfile
    CHANGED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | @@ -0,0 +1,73 @@ | |
| 1 | 
            +
            PATH
         | 
| 2 | 
            +
              remote: .
         | 
| 3 | 
            +
              specs:
         | 
| 4 | 
            +
                rgot (1.3.0)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            GEM
         | 
| 7 | 
            +
              remote: https://rubygems.org/
         | 
| 8 | 
            +
              specs:
         | 
| 9 | 
            +
                activesupport (7.0.4)
         | 
| 10 | 
            +
                  concurrent-ruby (~> 1.0, >= 1.0.2)
         | 
| 11 | 
            +
                  i18n (>= 1.6, < 2)
         | 
| 12 | 
            +
                  minitest (>= 5.1)
         | 
| 13 | 
            +
                  tzinfo (~> 2.0)
         | 
| 14 | 
            +
                ast (2.4.2)
         | 
| 15 | 
            +
                concurrent-ruby (1.1.10)
         | 
| 16 | 
            +
                csv (3.2.6)
         | 
| 17 | 
            +
                debug (1.7.1)
         | 
| 18 | 
            +
                ffi (1.15.5)
         | 
| 19 | 
            +
                fileutils (1.7.0)
         | 
| 20 | 
            +
                i18n (1.12.0)
         | 
| 21 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 22 | 
            +
                json (2.6.3)
         | 
| 23 | 
            +
                language_server-protocol (3.17.0.2)
         | 
| 24 | 
            +
                listen (3.7.1)
         | 
| 25 | 
            +
                  rb-fsevent (~> 0.10, >= 0.10.3)
         | 
| 26 | 
            +
                  rb-inotify (~> 0.9, >= 0.9.10)
         | 
| 27 | 
            +
                logger (1.5.3)
         | 
| 28 | 
            +
                minitest (5.17.0)
         | 
| 29 | 
            +
                parallel (1.22.1)
         | 
| 30 | 
            +
                parser (3.2.0.0)
         | 
| 31 | 
            +
                  ast (~> 2.4.1)
         | 
| 32 | 
            +
                rainbow (3.1.1)
         | 
| 33 | 
            +
                rake (13.0.6)
         | 
| 34 | 
            +
                rb-fsevent (0.11.2)
         | 
| 35 | 
            +
                rb-inotify (0.10.1)
         | 
| 36 | 
            +
                  ffi (~> 1.0)
         | 
| 37 | 
            +
                rbs (2.8.2)
         | 
| 38 | 
            +
                securerandom (0.2.2)
         | 
| 39 | 
            +
                steep (1.3.0)
         | 
| 40 | 
            +
                  activesupport (>= 5.1)
         | 
| 41 | 
            +
                  csv (>= 3.0.9)
         | 
| 42 | 
            +
                  fileutils (>= 1.1.0)
         | 
| 43 | 
            +
                  json (>= 2.1.0)
         | 
| 44 | 
            +
                  language_server-protocol (>= 3.15, < 4.0)
         | 
| 45 | 
            +
                  listen (~> 3.0)
         | 
| 46 | 
            +
                  logger (>= 1.3.0)
         | 
| 47 | 
            +
                  parallel (>= 1.0.0)
         | 
| 48 | 
            +
                  parser (>= 3.1)
         | 
| 49 | 
            +
                  rainbow (>= 2.2.2, < 4.0)
         | 
| 50 | 
            +
                  rbs (>= 2.8.0)
         | 
| 51 | 
            +
                  securerandom (>= 0.1)
         | 
| 52 | 
            +
                  strscan (>= 1.0.0)
         | 
| 53 | 
            +
                  terminal-table (>= 2, < 4)
         | 
| 54 | 
            +
                strscan (3.0.5)
         | 
| 55 | 
            +
                terminal-table (3.0.2)
         | 
| 56 | 
            +
                  unicode-display_width (>= 1.1.1, < 3)
         | 
| 57 | 
            +
                tzinfo (2.0.5)
         | 
| 58 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 59 | 
            +
                unicode-display_width (2.4.2)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            PLATFORMS
         | 
| 62 | 
            +
              ruby
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            DEPENDENCIES
         | 
| 65 | 
            +
              bundler
         | 
| 66 | 
            +
              debug
         | 
| 67 | 
            +
              rake
         | 
| 68 | 
            +
              rbs
         | 
| 69 | 
            +
              rgot!
         | 
| 70 | 
            +
              steep
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            BUNDLED WITH
         | 
| 73 | 
            +
               2.4.2
         | 
    
        data/README.md
    CHANGED
    
    | @@ -93,6 +93,33 @@ ok	FooTest	2.782s | |
| 93 93 |  | 
| 94 94 | 
             
            `b.n` is automatically adjusted.
         | 
| 95 95 |  | 
| 96 | 
            +
            ## Fuzzing
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            ```
         | 
| 99 | 
            +
            $ rgot target_file_test.rb --fuzz . --fuzztime 1
         | 
| 100 | 
            +
            ```
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            Fuzzing tests are also supported.
         | 
| 103 | 
            +
            Please refer to the gloang documentation for details.
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            https://go.dev/security/fuzz/
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            ```ruby
         | 
| 108 | 
            +
            module FooTest
         | 
| 109 | 
            +
              # To enable fuzzing, the method name
         | 
| 110 | 
            +
              # should be prefixed with `fuzz`.
         | 
| 111 | 
            +
              def fuzz_any_func(f)
         | 
| 112 | 
            +
                f.add(5, "hello")
         | 
| 113 | 
            +
                f.fuzz do |t, i, s|
         | 
| 114 | 
            +
                  out, err = foo(i, s)
         | 
| 115 | 
            +
                  if err != nil && out != ""
         | 
| 116 | 
            +
                    t.errorf("%s, %s", out, err)
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
            end
         | 
| 121 | 
            +
            ```
         | 
| 122 | 
            +
             | 
| 96 123 | 
             
            ## Example
         | 
| 97 124 |  | 
| 98 125 | 
             
            Rgot's example feature is the best and if you want to write the sample code of your library.
         | 
| @@ -189,6 +216,8 @@ Method name should be set `test_*` for testing. | |
| 189 216 |  | 
| 190 217 | 
             
            And benchmark method should be set `benchmark_*`.
         | 
| 191 218 |  | 
| 219 | 
            +
            And fuzz method should be set `fuzz_*`.
         | 
| 220 | 
            +
             | 
| 192 221 | 
             
            And example method should be set `example_*`.
         | 
| 193 222 |  | 
| 194 223 | 
             
            ```ruby
         | 
| @@ -199,6 +228,9 @@ module XxxTest | |
| 199 228 | 
             
              def benchmark_any_name(b)
         | 
| 200 229 | 
             
              end
         | 
| 201 230 |  | 
| 231 | 
            +
              def fuzz_any_name(f)
         | 
| 232 | 
            +
              end
         | 
| 233 | 
            +
             | 
| 202 234 | 
             
              def example_any_name
         | 
| 203 235 | 
             
              end
         | 
| 204 236 | 
             
            end
         | 
| @@ -218,6 +250,8 @@ Usage: rgot [options] | |
| 218 250 | 
             
                    --thread [count,...]         set thread counts of comma split
         | 
| 219 251 | 
             
                    --require [path]             load some code before running
         | 
| 220 252 | 
             
                    --load-path [path]           Specify $LOAD_PATH directory
         | 
| 253 | 
            +
                    --fuzz [regexp]              run the fuzz test matching `regexp`
         | 
| 254 | 
            +
                    --fuzztime [sec]             time to spend fuzzing; default is to run indefinitely
         | 
| 221 255 | 
             
            ```
         | 
| 222 256 |  | 
| 223 257 | 
             
            ## Basic
         | 
| @@ -341,7 +375,7 @@ And this is default virtual main code. | |
| 341 375 | 
             
            ```ruby
         | 
| 342 376 | 
             
            module TestSomeCode
         | 
| 343 377 | 
             
              def test_main(m)
         | 
| 344 | 
            -
                 | 
| 378 | 
            +
                m.run
         | 
| 345 379 | 
             
              end
         | 
| 346 380 | 
             
            end
         | 
| 347 381 | 
             
            ```
         | 
| @@ -362,7 +396,7 @@ module TestSomeCode | |
| 362 396 | 
             
                the_before_running_some_code
         | 
| 363 397 | 
             
                code = m.run
         | 
| 364 398 | 
             
                the_after_running_some_code
         | 
| 365 | 
            -
                 | 
| 399 | 
            +
                code
         | 
| 366 400 | 
             
              end
         | 
| 367 401 | 
             
            end
         | 
| 368 402 | 
             
            ```
         | 
| @@ -515,3 +549,39 @@ def benchmark_foo(b) | |
| 515 549 | 
             
              end
         | 
| 516 550 | 
             
            end
         | 
| 517 551 | 
             
            ```
         | 
| 552 | 
            +
             | 
| 553 | 
            +
            ## Rgot::F (Fuzzing)
         | 
| 554 | 
            +
             | 
| 555 | 
            +
            ### Rgot::F#add
         | 
| 556 | 
            +
             | 
| 557 | 
            +
            Set the sample value with `#add`. This value is also used as a test. It guesses the type from the value and generates a random value.
         | 
| 558 | 
            +
             | 
| 559 | 
            +
            ### Rgot::F#fuzz
         | 
| 560 | 
            +
             | 
| 561 | 
            +
            Generate the random value generated by `#fuzz` and execute the code.
         | 
| 562 | 
            +
            The `t` becomes an instance of `Rgot::T` and the test can be run as usual.
         | 
| 563 | 
            +
             | 
| 564 | 
            +
            ```ruby
         | 
| 565 | 
            +
            def fuzz_foo(f)
         | 
| 566 | 
            +
              f.add(100, "hello")
         | 
| 567 | 
            +
              f.fuzz do |t, i, s|
         | 
| 568 | 
            +
                i #=> 100, 84, 17, 9, 66, ...
         | 
| 569 | 
            +
                s #=> "hello", "Y\xD5\xAB\xBA\x8E", "r\x95D\xA5\xF7", "\xCEj=\x9C\xBD", ...
         | 
| 570 | 
            +
                if !foo(i, s)
         | 
| 571 | 
            +
                  t.error("fail with i=#{i}, s=#{s}")
         | 
| 572 | 
            +
                end
         | 
| 573 | 
            +
              end
         | 
| 574 | 
            +
            end
         | 
| 575 | 
            +
            ```
         | 
| 576 | 
            +
             | 
| 577 | 
            +
            # TODO
         | 
| 578 | 
            +
             | 
| 579 | 
            +
            - [ ] Support to save and load fuzzing data
         | 
| 580 | 
            +
             | 
| 581 | 
            +
            ## v2
         | 
| 582 | 
            +
             | 
| 583 | 
            +
            - [ ] Support sub testing
         | 
| 584 | 
            +
            - [ ] Fix duration argument unit
         | 
| 585 | 
            +
            - [ ] Refactoring
         | 
| 586 | 
            +
              - [ ] Fix M#initialize argument
         | 
| 587 | 
            +
              - [ ] Fix internal class API
         | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/Steepfile
    ADDED
    
    
    
        data/bin/rgot
    CHANGED
    
    
    
        data/lib/rgot/b.rb
    CHANGED
    
    | @@ -1,12 +1,16 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Rgot
         | 
| 2 4 | 
             
              class B < Common
         | 
| 3 | 
            -
                Options = Struct.new(
         | 
| 5 | 
            +
                Options = _ = Struct.new(
         | 
| 4 6 | 
             
                  :procs,
         | 
| 5 7 | 
             
                  :threads,
         | 
| 6 8 | 
             
                  :benchtime,
         | 
| 7 9 | 
             
                )
         | 
| 8 10 |  | 
| 11 | 
            +
                # @dynamic n, n=
         | 
| 9 12 | 
             
                attr_accessor :n
         | 
| 13 | 
            +
             | 
| 10 14 | 
             
                def initialize(benchmark_module, name, opts = Options.new)
         | 
| 11 15 | 
             
                  super()
         | 
| 12 16 | 
             
                  @n = 1
         | 
| @@ -14,7 +18,7 @@ module Rgot | |
| 14 18 | 
             
                  @name = name
         | 
| 15 19 | 
             
                  @opts = opts
         | 
| 16 20 | 
             
                  @timer_on = false
         | 
| 17 | 
            -
                  @duration = 0
         | 
| 21 | 
            +
                  @duration = 0.0
         | 
| 18 22 | 
             
                  @module.extend @module if @module
         | 
| 19 23 | 
             
                end
         | 
| 20 24 |  | 
| @@ -36,34 +40,34 @@ module Rgot | |
| 36 40 | 
             
                  if @timer_on
         | 
| 37 41 | 
             
                    @start = Rgot.now
         | 
| 38 42 | 
             
                  end
         | 
| 39 | 
            -
                  @duration = 0
         | 
| 43 | 
            +
                  @duration = 0.0
         | 
| 40 44 | 
             
                end
         | 
| 41 45 |  | 
| 42 46 | 
             
                def run(&block)
         | 
| 43 47 | 
             
                  n = 1
         | 
| 44 48 | 
             
                  benchtime = (@opts.benchtime || 1).to_f
         | 
| 45 49 | 
             
                  catch(:skip) do
         | 
| 46 | 
            -
                    run_n(n | 
| 47 | 
            -
                    while !failed? && @duration < benchtime &&  | 
| 50 | 
            +
                    run_n(n, block)
         | 
| 51 | 
            +
                    while !failed? && @duration < benchtime && n < 1e9
         | 
| 48 52 | 
             
                      if @duration < (benchtime / 100.0)
         | 
| 49 | 
            -
                         | 
| 53 | 
            +
                        n *= 100
         | 
| 50 54 | 
             
                      elsif @duration < (benchtime / 10.0)
         | 
| 51 | 
            -
                         | 
| 55 | 
            +
                        n *= 10
         | 
| 52 56 | 
             
                      elsif @duration < (benchtime / 5.0)
         | 
| 53 | 
            -
                         | 
| 57 | 
            +
                        n *= 5
         | 
| 54 58 | 
             
                      elsif @duration < (benchtime / 2.0)
         | 
| 55 | 
            -
                         | 
| 59 | 
            +
                        n *= 2
         | 
| 56 60 | 
             
                      else
         | 
| 57 | 
            -
                        if  | 
| 61 | 
            +
                        if n == 1
         | 
| 58 62 | 
             
                          break
         | 
| 59 63 | 
             
                        end
         | 
| 60 | 
            -
                         | 
| 64 | 
            +
                        n = [(n * 1.2).to_i, n + 1].max || raise
         | 
| 61 65 | 
             
                      end
         | 
| 62 | 
            -
                      run_n( | 
| 66 | 
            +
                      run_n(n, block)
         | 
| 63 67 | 
             
                    end
         | 
| 64 68 | 
             
                  end
         | 
| 65 69 |  | 
| 66 | 
            -
                  BenchmarkResult.new(n:  | 
| 70 | 
            +
                  BenchmarkResult.new(n: n, t: @duration)
         | 
| 67 71 | 
             
                end
         | 
| 68 72 |  | 
| 69 73 | 
             
                def run_parallel
         | 
| @@ -81,7 +85,6 @@ module Rgot | |
| 81 85 | 
             
                      }.each(&:join)
         | 
| 82 86 | 
             
                    end
         | 
| 83 87 | 
             
                  end
         | 
| 84 | 
            -
                  @n *= procs * threads
         | 
| 85 88 | 
             
                  Process.waitall
         | 
| 86 89 | 
             
                end
         | 
| 87 90 |  | 
    
        data/lib/rgot/cli.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require 'optparse'
         | 
| 2 4 |  | 
| 3 5 | 
             
            require_relative '../rgot'
         | 
| @@ -11,7 +13,7 @@ module Rgot | |
| 11 13 | 
             
                def run
         | 
| 12 14 | 
             
                  opts = Rgot::M::Options.new
         | 
| 13 15 | 
             
                  parse_option(opts)
         | 
| 14 | 
            -
                   | 
| 16 | 
            +
                  main_process(opts)
         | 
| 15 17 | 
             
                end
         | 
| 16 18 |  | 
| 17 19 | 
             
                private
         | 
| @@ -50,6 +52,15 @@ module Rgot | |
| 50 52 | 
             
                    o.on '--load-path [path]', "Specify $LOAD_PATH directory" do |arg|
         | 
| 51 53 | 
             
                      $LOAD_PATH.unshift(arg)
         | 
| 52 54 | 
             
                    end
         | 
| 55 | 
            +
                    o.on '--fuzz [regexp]', "run the fuzz test matching `regexp`" do |arg|
         | 
| 56 | 
            +
                      unless arg
         | 
| 57 | 
            +
                        raise Rgot::OptionError, "missing argument for flag --fuzz"
         | 
| 58 | 
            +
                      end
         | 
| 59 | 
            +
                      opts.fuzz = arg
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
                    o.on '--fuzztime [sec]', "time to spend fuzzing; default is to run indefinitely" do |arg|
         | 
| 62 | 
            +
                      opts.fuzztime = arg
         | 
| 63 | 
            +
                    end
         | 
| 53 64 | 
             
                  end
         | 
| 54 65 | 
             
                  parser.parse!(@argv)
         | 
| 55 66 |  | 
| @@ -74,81 +85,97 @@ module Rgot | |
| 74 85 | 
             
                  end
         | 
| 75 86 | 
             
                end
         | 
| 76 87 |  | 
| 77 | 
            -
                def  | 
| 88 | 
            +
                def main_process(opts)
         | 
| 78 89 | 
             
                  code = 0
         | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
                          duration = Rgot.now
         | 
| 114 | 
            -
                          at_exit do
         | 
| 115 | 
            -
                            template = "%s\t%s\t%.3fs"
         | 
| 116 | 
            -
             | 
| 117 | 
            -
                            case $!
         | 
| 118 | 
            -
                            when SystemExit
         | 
| 119 | 
            -
                              if $!.success?
         | 
| 120 | 
            -
                                # exit 0
         | 
| 121 | 
            -
                                puts sprintf(template, "ok  ", test_module, Rgot.now - duration)
         | 
| 122 | 
            -
                              else
         | 
| 123 | 
            -
                                # exit 1
         | 
| 124 | 
            -
                                puts "exit status #{$!.status}"
         | 
| 125 | 
            -
                                puts sprintf(template, "FAIL", test_module, Rgot.now - duration)
         | 
| 126 | 
            -
                              end
         | 
| 127 | 
            -
                            when NilClass
         | 
| 128 | 
            -
                              # not raise, not exit
         | 
| 129 | 
            -
                            else
         | 
| 130 | 
            -
                              # any exception
         | 
| 131 | 
            -
                              puts sprintf(template, "FAIL", test_module, Rgot.now - duration)
         | 
| 132 | 
            -
                            end
         | 
| 133 | 
            -
                          end
         | 
| 134 | 
            -
                          m = Rgot::M.new(tests: tests, benchmarks: benchmarks, examples: examples, opts: opts)
         | 
| 135 | 
            -
                          if main
         | 
| 136 | 
            -
                            main.module.extend main.module
         | 
| 137 | 
            -
                            main.module.instance_method(main.name).bind(main.module).call(m)
         | 
| 138 | 
            -
                          else
         | 
| 139 | 
            -
                            exit m.run
         | 
| 140 | 
            -
                          end
         | 
| 141 | 
            -
                        end
         | 
| 142 | 
            -
                      end
         | 
| 143 | 
            -
                    ensure
         | 
| 144 | 
            -
                      _, status = Process.waitpid2(pid)
         | 
| 145 | 
            -
                      unless status.success?
         | 
| 146 | 
            -
                        code = 1
         | 
| 147 | 
            -
                      end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  testing_files.each do |testing_file|
         | 
| 92 | 
            +
                    result = child_process(opts, testing_file)
         | 
| 93 | 
            +
                    unless result == 0
         | 
| 94 | 
            +
                      code = 1
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  code
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def child_process(opts, testing_file)
         | 
| 102 | 
            +
                  node = RubyVM::AbstractSyntaxTree.parse_file(testing_file).children[2]
         | 
| 103 | 
            +
                  test_module_name = find_toplevel_name(node)
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  if opts.fuzz
         | 
| 106 | 
            +
                    # fuzzing observes changes in coverage.
         | 
| 107 | 
            +
                    require 'coverage'
         | 
| 108 | 
            +
                    Coverage.start(oneshot_lines: true)
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                  load testing_file
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  test_module = Object.const_get(test_module_name)
         | 
| 113 | 
            +
                  tests = []
         | 
| 114 | 
            +
                  benchmarks = []
         | 
| 115 | 
            +
                  examples = []
         | 
| 116 | 
            +
                  fuzz_targets = []
         | 
| 117 | 
            +
                  main = nil
         | 
| 118 | 
            +
                  methods = test_module.public_instance_methods
         | 
| 119 | 
            +
                  methods.grep(/\Atest_/).each do |m|
         | 
| 120 | 
            +
                    if m == :test_main && main.nil?
         | 
| 121 | 
            +
                      main = Rgot::InternalTest.new(test_module, m)
         | 
| 122 | 
            +
                    else
         | 
| 123 | 
            +
                      tests << Rgot::InternalTest.new(test_module, m)
         | 
| 148 124 | 
             
                    end
         | 
| 149 125 | 
             
                  end
         | 
| 150 126 |  | 
| 151 | 
            -
                   | 
| 127 | 
            +
                  methods.grep(/\Abenchmark_/).each do |m|
         | 
| 128 | 
            +
                    benchmarks << Rgot::InternalBenchmark.new(test_module, m)
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  methods.grep(/\Aexample_?/).each do |m|
         | 
| 132 | 
            +
                    examples << Rgot::InternalExample.new(test_module, m)
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                  methods.grep(/\Afuzz_/).each do |m|
         | 
| 136 | 
            +
                    fuzz_targets << Rgot::InternalFuzzTarget.new(test_module, m)
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  m = Rgot::M.new(
         | 
| 140 | 
            +
                    test_module: test_module,
         | 
| 141 | 
            +
                    tests: tests,
         | 
| 142 | 
            +
                    benchmarks: benchmarks,
         | 
| 143 | 
            +
                    examples: examples,
         | 
| 144 | 
            +
                    fuzz_targets: fuzz_targets,
         | 
| 145 | 
            +
                    opts: opts
         | 
| 146 | 
            +
                  )
         | 
| 147 | 
            +
                  if main
         | 
| 148 | 
            +
                    main.module.extend main.module
         | 
| 149 | 
            +
                    main.module.instance_method(:test_main).bind(main.module).call(m)
         | 
| 150 | 
            +
                  else
         | 
| 151 | 
            +
                    m.run
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                def find_toplevel_name(node)
         | 
| 156 | 
            +
                  case node.type
         | 
| 157 | 
            +
                  when :MODULE
         | 
| 158 | 
            +
                    find_toplevel_name(node.children.first)
         | 
| 159 | 
            +
                  when :CONST, :COLON3
         | 
| 160 | 
            +
                    node.children.first
         | 
| 161 | 
            +
                  when :COLON2
         | 
| 162 | 
            +
                    case node.children
         | 
| 163 | 
            +
                    in [nil, sym]
         | 
| 164 | 
            +
                      # module Foo
         | 
| 165 | 
            +
                      sym
         | 
| 166 | 
            +
                    in [namespace, sym]
         | 
| 167 | 
            +
                      # module Foo::Bar
         | 
| 168 | 
            +
                      find_toplevel_name(namespace)
         | 
| 169 | 
            +
                    end
         | 
| 170 | 
            +
                  when :BLOCK
         | 
| 171 | 
            +
                    module_node = node.children.find { |c| c.type == :MODULE }
         | 
| 172 | 
            +
                    unless module_node
         | 
| 173 | 
            +
                      raise "no module found"
         | 
| 174 | 
            +
                    end
         | 
| 175 | 
            +
                    find_toplevel_name(module_node)
         | 
| 176 | 
            +
                  else
         | 
| 177 | 
            +
                    raise node.type.to_s
         | 
| 178 | 
            +
                  end
         | 
| 152 179 | 
             
                end
         | 
| 153 180 | 
             
              end
         | 
| 154 181 | 
             
            end
         | 
    
        data/lib/rgot/common.rb
    CHANGED
    
    | @@ -1,17 +1,20 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require 'thread'
         | 
| 2 4 | 
             
            require 'pathname'
         | 
| 3 5 |  | 
| 4 6 | 
             
            module Rgot
         | 
| 5 7 | 
             
              class Common
         | 
| 8 | 
            +
                # @dynamic output, output=
         | 
| 6 9 | 
             
                attr_accessor :output
         | 
| 7 10 |  | 
| 8 11 | 
             
                def initialize
         | 
| 9 | 
            -
                  @output = ""
         | 
| 12 | 
            +
                  @output = "".dup
         | 
| 10 13 | 
             
                  @failed = false
         | 
| 11 14 | 
             
                  @skipped = false
         | 
| 12 15 | 
             
                  @finished = false
         | 
| 13 16 | 
             
                  @start = Rgot.now
         | 
| 14 | 
            -
                  @mutex = Mutex.new
         | 
| 17 | 
            +
                  @mutex = Thread::Mutex.new
         | 
| 15 18 | 
             
                end
         | 
| 16 19 |  | 
| 17 20 | 
             
                def failed?
         | 
| @@ -98,9 +101,10 @@ module Rgot | |
| 98 101 | 
             
                  # internal_log -> synchronize -> internal_log -> other log -> running method
         | 
| 99 102 | 
             
                  c = caller[4]
         | 
| 100 103 | 
             
                  path = c.sub(/:.*/, '')
         | 
| 101 | 
            -
                  line = c.match(/:(\d+?):/)[1 | 
| 104 | 
            +
                  line = c.match(/:(\d+?):/)&.[](1)
         | 
| 102 105 | 
             
                  relative_path = Pathname.new(path).relative_path_from(Pathname.new(Dir.pwd)).to_s
         | 
| 103 | 
            -
                   | 
| 106 | 
            +
                  # Every line is indented at least 4 spaces.
         | 
| 107 | 
            +
                  "    #{relative_path}:#{line}: #{str}\n"
         | 
| 104 108 | 
             
                end
         | 
| 105 109 |  | 
| 106 110 | 
             
                def internal_log(msg)
         | 
    
        data/lib/rgot/example_parser.rb
    CHANGED
    
    | @@ -1,14 +1,19 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require 'ripper'
         | 
| 2 4 |  | 
| 3 5 | 
             
            module Rgot
         | 
| 4 6 | 
             
              class ExampleParser < Ripper
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                # @dynamic examples, examples=
         | 
| 5 9 | 
             
                attr_accessor :examples
         | 
| 10 | 
            +
             | 
| 6 11 | 
             
                def initialize(code)
         | 
| 7 12 | 
             
                  super
         | 
| 8 13 | 
             
                  @examples = []
         | 
| 9 14 | 
             
                  @in_def = false
         | 
| 10 15 | 
             
                  @has_output = false
         | 
| 11 | 
            -
                  @output = ""
         | 
| 16 | 
            +
                  @output = "".dup
         | 
| 12 17 | 
             
                end
         | 
| 13 18 |  | 
| 14 19 | 
             
                def on_def(method, args, body)
         |