pork 1.5.0 → 2.1.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 +5 -5
- data/.gitlab-ci.yml +40 -0
- data/.gitmodules +1 -1
- data/CHANGES.md +41 -0
- data/Gemfile +0 -4
- data/README.md +63 -18
- data/Rakefile +5 -4
- data/TODO.md +0 -2
- data/lib/pork/api.rb +35 -0
- data/lib/pork/env.rb +1 -1
- data/lib/pork/executor.rb +24 -10
- data/lib/pork/extra/show_source.rb +21 -2
- data/lib/pork/isolator.rb +145 -0
- data/lib/pork/mode/parallel.rb +6 -7
- data/lib/pork/mode/sequential.rb +5 -5
- data/lib/pork/mode/shuffled.rb +5 -5
- data/lib/pork/more/bottomup_backtrace.rb +0 -2
- data/lib/pork/more/color.rb +0 -2
- data/lib/pork/more/should.rb +9 -9
- data/lib/pork/report/description.rb +7 -7
- data/lib/pork/report/progressbar.rb +1 -2
- data/lib/pork/report.rb +17 -13
- data/lib/pork/runner.rb +54 -0
- data/lib/pork/stat.rb +1 -1
- data/lib/pork/suite.rb +74 -0
- data/lib/pork/version.rb +1 -1
- data/lib/pork.rb +10 -18
- data/pork.gemspec +23 -23
- data/task/README.md +8 -8
- data/task/gemgem.rb +32 -8
- data/test/test_around.rb +64 -0
- data/test/test_bacon.rb +7 -6
- data/test/test_isolator.rb +29 -0
- data/test/test_meta.rb +40 -0
- data/test/test_nested.rb +24 -1
- data/test/test_pork_test.rb +29 -26
- data/test/test_readme.rb +6 -2
- data/test/test_stat.rb +19 -17
- data/test/test_suite.rb +10 -0
- metadata +20 -11
- data/.travis.yml +0 -15
- data/lib/pork/imp.rb +0 -88
- data/lib/pork/isolate.rb +0 -98
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 6ef62f89f8c80fddee9ebd8e670cfa8de340a312531d022a3e49510dc7dd218f
         | 
| 4 | 
            +
              data.tar.gz: 1f3af07cdc623ec24ba294fc41409f958a7fb8c89961388d98915bc648dfb142
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: e8c95acab07773aa0fd2f629c41c7a08d50b747c44649a3981021c5f64d0bc08f58a1b2de3ac78c317c3519c692dff2c6f473f32fcf37d806f367e65bb5fac28
         | 
| 7 | 
            +
              data.tar.gz: 7b24bb5ec0792941b51ed0b2f69b90f17465fd68401db9835b42ac17b8719ed3c2936a683c6aa22f6165f9d9b01c94d5f5e90329c55c83868d051f4883004910
         | 
    
        data/.gitlab-ci.yml
    ADDED
    
    | @@ -0,0 +1,40 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            stages:
         | 
| 3 | 
            +
              - test
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            .test:
         | 
| 6 | 
            +
              stage: test
         | 
| 7 | 
            +
              image: ruby:${RUBY_VERSION}-bullseye
         | 
| 8 | 
            +
              variables:
         | 
| 9 | 
            +
                GIT_DEPTH: "1"
         | 
| 10 | 
            +
                GIT_SUBMODULE_STRATEGY: recursive
         | 
| 11 | 
            +
                GIT_SUBMODULE_PATHS: task
         | 
| 12 | 
            +
                RUBYOPT: --enable-frozen-string-literal
         | 
| 13 | 
            +
              before_script:
         | 
| 14 | 
            +
                - bundle install --retry=3
         | 
| 15 | 
            +
                - unset CI # Coverage doesn't work well with frozen literal
         | 
| 16 | 
            +
              script:
         | 
| 17 | 
            +
                - ruby -vr bundler/setup -S rake test
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            ruby:3.0:
         | 
| 20 | 
            +
              extends:
         | 
| 21 | 
            +
                - .test
         | 
| 22 | 
            +
              variables:
         | 
| 23 | 
            +
                RUBY_VERSION: '3.0'
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ruby:3.1:
         | 
| 26 | 
            +
              extends:
         | 
| 27 | 
            +
                - .test
         | 
| 28 | 
            +
              variables:
         | 
| 29 | 
            +
                RUBY_VERSION: '3.1'
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            ruby:3.2:
         | 
| 32 | 
            +
              extends:
         | 
| 33 | 
            +
                - .test
         | 
| 34 | 
            +
              variables:
         | 
| 35 | 
            +
                RUBY_VERSION: '3.2'
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            jruby:latest:
         | 
| 38 | 
            +
              extends:
         | 
| 39 | 
            +
                - .test
         | 
| 40 | 
            +
              image: jruby:latest
         | 
    
        data/.gitmodules
    CHANGED
    
    
    
        data/CHANGES.md
    CHANGED
    
    | @@ -1,5 +1,46 @@ | |
| 1 1 | 
             
            # CHANGES
         | 
| 2 2 |  | 
| 3 | 
            +
            ## Pork 2.1.0 -- 2022-12-28
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ### Bugs fixed
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            * `Pork.show_source` can work under frozen literal string mode now.
         | 
| 8 | 
            +
            * Fix picking the right test for the file line number from `ENV['PORK_TEST']`
         | 
| 9 | 
            +
              (I totally forgot the details for this from 2017, but I think it should
         | 
| 10 | 
            +
              make it more accurate anyway)
         | 
| 11 | 
            +
            * Ruby 3.2 compatibility fix. (Removed the use of `Random::DEFAULT`)
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ### Enhancement
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            * Introduced `Pork::API.around` which will pass the test object to the block,
         | 
| 16 | 
            +
              and whenever the object is called with `call` it'll run the test. Note that
         | 
| 17 | 
            +
              if `call` was never called, it'll act like `Pork::API.before` and the test
         | 
| 18 | 
            +
              will still run unlike RSpec. To skip the test, call `skip` directly.
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            ## Pork 2.0.0 -- 2016-09-10
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ### Incompatible changes
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            * `Pork::Executor` is now renamed to `Pork::Suite`, and the new
         | 
| 25 | 
            +
              `Pork::Executor` would be served as the real executor who's responsible
         | 
| 26 | 
            +
              for running the test suites!
         | 
| 27 | 
            +
            * `Pork::Executor.execute` would now take a hash as the argument.
         | 
| 28 | 
            +
            * `Pork::Suite.after` would now run in a reverse manner because that would
         | 
| 29 | 
            +
              serve better as a destructor.
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            ### Enhancement
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            * `Pork::Suite.desc` would now preserve the original argument being passed to
         | 
| 34 | 
            +
              `Pork::Suite.describe`, rather than converting it to a string.
         | 
| 35 | 
            +
            * Major internal structure cleanup. Now we don't include everything into the
         | 
| 36 | 
            +
              context, but use different objects to do different things. For example,
         | 
| 37 | 
            +
              now we have `Pork::Isolator` to isolate the context.
         | 
| 38 | 
            +
            * Introduced `Pork.execute_extensions` which would be extending to
         | 
| 39 | 
            +
              `Pork::Executor`. The only extension for it for now is `Pork::Should`.
         | 
| 40 | 
            +
            * Don't crash if `Pork.loaded` was never called.
         | 
| 41 | 
            +
            * Now you could also make assertions in `after` block without triggering
         | 
| 42 | 
            +
              `Missing assertions` errors.
         | 
| 43 | 
            +
             | 
| 3 44 | 
             
            ## Pork 1.5.0 -- 2016-03-10
         | 
| 4 45 |  | 
| 5 46 | 
             
            ### Enhancement
         | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # Pork [](https://gitlab.com/godfat/pork/-/pipelines)
         | 
| 2 2 |  | 
| 3 3 | 
             
            by Lin Jen-Shin ([godfat](http://godfat.org))
         | 
| 4 4 |  | 
| @@ -7,6 +7,7 @@ by Lin Jen-Shin ([godfat](http://godfat.org)) | |
| 7 7 | 
             
            * [github](https://github.com/godfat/pork)
         | 
| 8 8 | 
             
            * [rubygems](https://rubygems.org/gems/pork)
         | 
| 9 9 | 
             
            * [rdoc](http://rdoc.info/github/godfat/pork)
         | 
| 10 | 
            +
            * [issues](https://github.com/godfat/pork/issues) (feel free to ask for support)
         | 
| 10 11 |  | 
| 11 12 | 
             
            ## DESCRIPTION:
         | 
| 12 13 |  | 
| @@ -93,7 +94,7 @@ end | |
| 93 94 |  | 
| 94 95 | 
             
            describe 'C' do
         | 
| 95 96 | 
             
              # Also, we're not forced to include something in all describe blocks.
         | 
| 96 | 
            -
              # If we want, we could do this instead: `Pork:: | 
| 97 | 
            +
              # If we want, we could do this instead: `Pork::Suite.include(Module.new)`
         | 
| 97 98 | 
             
              # That would be the same as including in `Bacon::Context`
         | 
| 98 99 | 
             
              would 'not respond_to? in_module nor in_describe' do
         | 
| 99 100 | 
             
                should.not.respond_to?(:in_module)
         | 
| @@ -147,7 +148,7 @@ end | |
| 147 148 |  | 
| 148 149 | 
             
            ## REQUIREMENTS:
         | 
| 149 150 |  | 
| 150 | 
            -
            * Tested with MRI (official CRuby) | 
| 151 | 
            +
            * Tested with MRI (official CRuby) and JRuby.
         | 
| 151 152 | 
             
            * (Optional) [method_source][] if you would like to print the source for the
         | 
| 152 153 | 
             
              failing tests.
         | 
| 153 154 | 
             
            * (Optional) [ruby-progressbar][] if you like porgressbar for showing
         | 
| @@ -298,7 +299,7 @@ Pork.autorun | |
| 298 299 |  | 
| 299 300 | 
             
            Here it `require 'pork/should'`, and it would load the monkey patches for
         | 
| 300 301 | 
             
            inserting `Kernel#should` shown in SYNOPSIS. This is actually optional,
         | 
| 301 | 
            -
            and could be replaced with `Pork:: | 
| 302 | 
            +
            and could be replaced with `Pork::Suite#expect`. For example, we could
         | 
| 302 303 | 
             
            also write it this way:
         | 
| 303 304 |  | 
| 304 305 | 
             
            ``` ruby
         | 
| @@ -580,16 +581,16 @@ So this creates a test suite which should be containing various test cases | |
| 580 581 | 
             
            suite, which accepts anything could be converted to a string. The _default_
         | 
| 581 582 | 
             
            description is `:default` (which would be converted to `'default: '`)
         | 
| 582 583 |  | 
| 583 | 
            -
            Each `describe` block would create a new subclass of `Pork:: | 
| 584 | 
            +
            Each `describe` block would create a new subclass of `Pork::Suite` for
         | 
| 584 585 | 
             
            isolating test suites. Each nested `describe` block would be a subclass of
         | 
| 585 | 
            -
            its parent `Pork:: | 
| 586 | 
            +
            its parent `Pork::Suite`.
         | 
| 586 587 |  | 
| 587 588 | 
             
            ``` ruby
         | 
| 588 589 | 
             
            require 'pork/auto'
         | 
| 589 590 |  | 
| 590 591 | 
             
            describe do
         | 
| 591 592 | 
             
              would 'be default: for the default description' do
         | 
| 592 | 
            -
                self.class.desc.should.eq  | 
| 593 | 
            +
                self.class.desc.should.eq :default
         | 
| 593 594 | 
             
              end
         | 
| 594 595 | 
             
            end
         | 
| 595 596 | 
             
            ```
         | 
| @@ -602,7 +603,7 @@ description of the test case, which accepts anything could be converted to | |
| 602 603 | 
             
            a string. The _default_ description is also `:default`.
         | 
| 603 604 |  | 
| 604 605 | 
             
            Each `would` block would be run inside a new instance of the describing
         | 
| 605 | 
            -
            `Pork:: | 
| 606 | 
            +
            `Pork::Suite` to isolate instance variables.
         | 
| 606 607 |  | 
| 607 608 | 
             
            ### Pork::API.before
         | 
| 608 609 |  | 
| @@ -637,20 +638,21 @@ end | |
| 637 638 | 
             
            Each `after` block would be called after each `would` block (test case).
         | 
| 638 639 | 
             
            You would probably want to cleanup stuffs inside `after` blocks.
         | 
| 639 640 |  | 
| 640 | 
            -
             | 
| 641 | 
            +
            Note that each nested `describe` would also run parents' `after` block in a
         | 
| 642 | 
            +
            reverse manner as opposed to `before`.
         | 
| 641 643 |  | 
| 642 644 | 
             
            ``` ruby
         | 
| 643 645 | 
             
            require 'pork/auto'
         | 
| 644 646 |  | 
| 645 647 | 
             
            describe do
         | 
| 646 648 | 
             
              after do
         | 
| 647 | 
            -
                @a.should.eq  | 
| 648 | 
            -
                @a += 1
         | 
| 649 | 
            +
                @a.should.eq 2
         | 
| 649 650 | 
             
              end
         | 
| 650 651 |  | 
| 651 652 | 
             
              describe do
         | 
| 652 653 | 
             
                after do
         | 
| 653 | 
            -
                  @a.should.eq  | 
| 654 | 
            +
                  @a.should.eq 1
         | 
| 655 | 
            +
                  @a += 1
         | 
| 654 656 | 
             
                end
         | 
| 655 657 |  | 
| 656 658 | 
             
                would do
         | 
| @@ -661,6 +663,49 @@ describe do | |
| 661 663 | 
             
            end
         | 
| 662 664 | 
             
            ```
         | 
| 663 665 |  | 
| 666 | 
            +
            ### Pork::API.around
         | 
| 667 | 
            +
             | 
| 668 | 
            +
            Each `around` block would be called before each `would` block (test case),
         | 
| 669 | 
            +
            and whenever it's called, it can take an argument representing the `would`
         | 
| 670 | 
            +
            block (test case). Whenever `call` is called on the test case, it will run.
         | 
| 671 | 
            +
            Essentially it's wrapping around the `would` block.
         | 
| 672 | 
            +
             | 
| 673 | 
            +
            Note that each nested `describe` would also run parents' `around` block,
         | 
| 674 | 
            +
            following the same order of `before` (in order) and `after` (reverse order).
         | 
| 675 | 
            +
             | 
| 676 | 
            +
            ``` ruby
         | 
| 677 | 
            +
            require 'pork/auto'
         | 
| 678 | 
            +
             | 
| 679 | 
            +
            describe do
         | 
| 680 | 
            +
              around do |test|
         | 
| 681 | 
            +
                @a = 0
         | 
| 682 | 
            +
             | 
| 683 | 
            +
                test.call
         | 
| 684 | 
            +
             | 
| 685 | 
            +
                @a.should.eq 2
         | 
| 686 | 
            +
              end
         | 
| 687 | 
            +
             | 
| 688 | 
            +
              describe do
         | 
| 689 | 
            +
                around do |test|
         | 
| 690 | 
            +
                  @a.should.eq 0
         | 
| 691 | 
            +
                  @a += 1
         | 
| 692 | 
            +
             | 
| 693 | 
            +
                  test.call
         | 
| 694 | 
            +
             | 
| 695 | 
            +
                  @a.should.eq 1
         | 
| 696 | 
            +
                  @a += 1
         | 
| 697 | 
            +
                end
         | 
| 698 | 
            +
             | 
| 699 | 
            +
                would do
         | 
| 700 | 
            +
                  @a.should.eq 1
         | 
| 701 | 
            +
                end
         | 
| 702 | 
            +
              end
         | 
| 703 | 
            +
            end
         | 
| 704 | 
            +
            ```
         | 
| 705 | 
            +
             | 
| 706 | 
            +
            Note that if `test.call` was never called, it'll just act like a `before`
         | 
| 707 | 
            +
            block. All the tests will still run unlike RSpec.
         | 
| 708 | 
            +
             | 
| 664 709 | 
             
            ### Pork::API.copy and Pork::API.paste
         | 
| 665 710 |  | 
| 666 711 | 
             
            It could be a bit confusing at first, but just think of `copy` as a way to
         | 
| @@ -694,7 +739,7 @@ describe do | |
| 694 739 | 
             
            end
         | 
| 695 740 | 
             
            ```
         | 
| 696 741 |  | 
| 697 | 
            -
            ### Pork:: | 
| 742 | 
            +
            ### Pork::Suite#expect
         | 
| 698 743 |  | 
| 699 744 | 
             
            It is the core of `Kernel#should`. Think of:
         | 
| 700 745 |  | 
| @@ -720,7 +765,7 @@ is equivalent to: | |
| 720 765 | 
             
            expect(object, 'message').eq(1)
         | 
| 721 766 | 
             
            ```
         | 
| 722 767 |  | 
| 723 | 
            -
            ### Pork:: | 
| 768 | 
            +
            ### Pork::Suite#skip
         | 
| 724 769 |  | 
| 725 770 | 
             
            At times we might want to skip some tests while leave the codes there without
         | 
| 726 771 | 
             
            removing them or commenting them out. This is where `skip` would be helpful.
         | 
| @@ -735,7 +780,7 @@ describe do | |
| 735 780 | 
             
            end
         | 
| 736 781 | 
             
            ```
         | 
| 737 782 |  | 
| 738 | 
            -
            ### Pork:: | 
| 783 | 
            +
            ### Pork::Suite#ok
         | 
| 739 784 |  | 
| 740 785 | 
             
            Because Pork would complain if a test case does not have any assertions,
         | 
| 741 786 | 
             
            sometimes we might want to tell Pork that it's ok because we've already
         | 
| @@ -758,7 +803,7 @@ describe do | |
| 758 803 | 
             
            end
         | 
| 759 804 | 
             
            ```
         | 
| 760 805 |  | 
| 761 | 
            -
            ### Pork:: | 
| 806 | 
            +
            ### Pork::Suite#flunk
         | 
| 762 807 |  | 
| 763 808 | 
             
            If we're writing program carefully, there are a few cases where a condition
         | 
| 764 809 | 
             
            would never meet. We could `raise "IMPOSSIBLE"` or we could simply call
         | 
| @@ -1067,9 +1112,9 @@ Have you seen Rainbows!? | |
| 1067 1112 |  | 
| 1068 1113 | 
             
            ## LICENSE:
         | 
| 1069 1114 |  | 
| 1070 | 
            -
            Apache License 2.0
         | 
| 1115 | 
            +
            Apache License 2.0 (Apache-2.0)
         | 
| 1071 1116 |  | 
| 1072 | 
            -
            Copyright (c) 2014- | 
| 1117 | 
            +
            Copyright (c) 2014-2022, Lin Jen-Shin (godfat)
         | 
| 1073 1118 |  | 
| 1074 1119 | 
             
            Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 1075 1120 | 
             
            you may not use this file except in compliance with the License.
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -1,16 +1,17 @@ | |
| 1 1 |  | 
| 2 2 | 
             
            begin
         | 
| 3 | 
            -
              require "#{ | 
| 3 | 
            +
              require "#{__dir__}/task/gemgem"
         | 
| 4 4 | 
             
            rescue LoadError
         | 
| 5 | 
            -
              sh 'git submodule update --init'
         | 
| 5 | 
            +
              sh 'git submodule update --init --recursive'
         | 
| 6 6 | 
             
              exec Gem.ruby, '-S', $PROGRAM_NAME, *ARGV
         | 
| 7 7 | 
             
            end
         | 
| 8 8 |  | 
| 9 | 
            -
            Gemgem.init( | 
| 9 | 
            +
            Gemgem.init(__dir__) do |s|
         | 
| 10 10 | 
             
              require 'pork/version'
         | 
| 11 11 | 
             
              s.name    = 'pork'
         | 
| 12 12 | 
             
              s.version = Pork::VERSION
         | 
| 13 | 
            +
              s.files.delete('screenshot.png')
         | 
| 14 | 
            +
             | 
| 13 15 | 
             
              %w[method_source ruby-progressbar].
         | 
| 14 16 | 
             
                each(&s.method(:add_development_dependency))
         | 
| 15 | 
            -
              s.files.delete('screenshot.png')
         | 
| 16 17 | 
             
            end
         | 
    
        data/TODO.md
    CHANGED
    
    
    
        data/lib/pork/api.rb
    ADDED
    
    | @@ -0,0 +1,35 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            require 'pork/suite'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Pork
         | 
| 5 | 
            +
              module API
         | 
| 6 | 
            +
                module_function
         | 
| 7 | 
            +
                def before &block
         | 
| 8 | 
            +
                  Suite.before(&block)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def after &block
         | 
| 12 | 
            +
                  Suite.after(&block)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def around &block
         | 
| 16 | 
            +
                  Suite.around(&block)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def copy desc=:default, &block
         | 
| 20 | 
            +
                  Suite.copy(desc, &block)
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def paste desc=:default, *args
         | 
| 24 | 
            +
                  Suite.paste(desc, *args)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def describe desc=:default, opts={}, &suite
         | 
| 28 | 
            +
                  Suite.describe(desc, opts, &suite)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def would desc=:default, opts={}, &test
         | 
| 32 | 
            +
                  Suite.would(desc, opts, &test)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
    
        data/lib/pork/env.rb
    CHANGED
    
    
    
        data/lib/pork/executor.rb
    CHANGED
    
    | @@ -1,16 +1,30 @@ | |
| 1 1 |  | 
| 2 | 
            -
            require 'pork/ | 
| 3 | 
            -
            require 'pork/ | 
| 4 | 
            -
            require 'pork/context'
         | 
| 2 | 
            +
            require 'pork/suite'
         | 
| 3 | 
            +
            require 'pork/isolator'
         | 
| 5 4 |  | 
| 6 5 | 
             
            module Pork
         | 
| 7 | 
            -
              class Executor < Struct.new(: | 
| 8 | 
            -
                 | 
| 9 | 
            -
             | 
| 10 | 
            -
                 | 
| 6 | 
            +
              class Executor < Struct.new(:isolator)
         | 
| 7 | 
            +
                def self.[] index
         | 
| 8 | 
            +
                  Isolator[][index]
         | 
| 9 | 
            +
                end
         | 
| 11 10 |  | 
| 12 | 
            -
                 | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 11 | 
            +
                def self.execute mode: Pork.execute_mode,
         | 
| 12 | 
            +
                                 stat: Pork.stat,
         | 
| 13 | 
            +
                                 suite: Suite,
         | 
| 14 | 
            +
                                 isolator: Isolator[suite],
         | 
| 15 | 
            +
                                 paths: isolator.all_paths
         | 
| 16 | 
            +
                  require "pork/mode/#{mode}"
         | 
| 17 | 
            +
                  Pork.const_get(mode.capitalize).new(isolator).execute(stat, paths)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def initialize new_isolator
         | 
| 21 | 
            +
                  super(new_isolator)
         | 
| 22 | 
            +
                  extensions = Pork.execute_extensions
         | 
| 23 | 
            +
                  extend(*extensions.reverse) if extensions.any?
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def execute stat=Stat.new, paths=isolator.all_paths
         | 
| 27 | 
            +
                  raise NotImplementedError
         | 
| 28 | 
            +
                end
         | 
| 15 29 | 
             
              end
         | 
| 16 30 | 
             
            end
         | 
| @@ -3,12 +3,31 @@ require 'method_source' | |
| 3 3 |  | 
| 4 4 | 
             
            module Pork
         | 
| 5 5 | 
             
              module ShowSource
         | 
| 6 | 
            +
                module FrozenStringFix
         | 
| 7 | 
            +
                  def extract_first_expression(lines, consume=0, &block)
         | 
| 8 | 
            +
                    code = consume.zero? ? [] : lines.slice!(0..(consume - 1))
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    lines.each do |v|
         | 
| 11 | 
            +
                      code << v
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                      result = block ? block.call(code.join) : code.join
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                      if complete_expression?(result)
         | 
| 16 | 
            +
                        return result
         | 
| 17 | 
            +
                      end
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                    raise SyntaxError, "unexpected $end"
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                MethodSource.extend(FrozenStringFix)
         | 
| 24 | 
            +
             | 
| 6 25 | 
             
                def show_source test, err
         | 
| 7 26 | 
             
                  source = test.source
         | 
| 8 27 | 
             
                  sopath = "#{test.source_location.first}:"
         | 
| 9 28 | 
             
                  lowers = test.source_location.last
         | 
| 10 29 | 
             
                  uppers = lowers + source.size
         | 
| 11 | 
            -
                  lineno = reject_pork(test, err).find do |backtrace|
         | 
| 30 | 
            +
                  lineno = reject_pork(test, err.backtrace).find do |backtrace|
         | 
| 12 31 | 
             
                    # find the line from the test source, exclude everything else
         | 
| 13 32 | 
             
                    next unless backtrace.start_with?(sopath)
         | 
| 14 33 | 
             
                    number = backtrace[/(?<=\.rb:)\d+/].to_i
         | 
| @@ -28,7 +47,7 @@ module Pork | |
| 28 47 | 
             
                    end
         | 
| 29 48 | 
             
                  end.join
         | 
| 30 49 | 
             
                  "\n#{result.chomp}"
         | 
| 31 | 
            -
                rescue SyntaxError => e
         | 
| 50 | 
            +
                rescue SyntaxError, MethodSource::SourceNotFoundError => e
         | 
| 32 51 | 
             
                  "\nPork bug: Cannot parse the source. Please report: #{e}"
         | 
| 33 52 | 
             
                end
         | 
| 34 53 | 
             
              end
         | 
| @@ -0,0 +1,145 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            require 'pork/env'
         | 
| 3 | 
            +
            require 'pork/suite'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Pork
         | 
| 6 | 
            +
              class Isolator < Struct.new(:suite)
         | 
| 7 | 
            +
                def self.[] suite=Suite
         | 
| 8 | 
            +
                  @map ||= {}
         | 
| 9 | 
            +
                  @map[suite] ||= new(suite)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def all_tests
         | 
| 13 | 
            +
                  @all_tests ||= build_all_tests
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def all_paths
         | 
| 17 | 
            +
                  (all_tests[:files] || {}).values.flat_map(&:values).flatten(1).uniq
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def [] index
         | 
| 21 | 
            +
                  by_groups(index) || by_source(index)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def by_groups groups
         | 
| 25 | 
            +
                  return unless tests = all_tests[:groups]
         | 
| 26 | 
            +
                  paths = groups.split(',').flat_map do |g|
         | 
| 27 | 
            +
                    tests[g.strip] || []
         | 
| 28 | 
            +
                  end.uniq
         | 
| 29 | 
            +
                  paths unless paths.empty?
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def by_source source
         | 
| 33 | 
            +
                  return unless tests = all_tests[:files]
         | 
| 34 | 
            +
                  file_str, line_str = source.split(':')
         | 
| 35 | 
            +
                  file, line = File.expand_path(file_str), line_str.to_i
         | 
| 36 | 
            +
                  return unless cases = tests[file]
         | 
| 37 | 
            +
                  if line.zero?
         | 
| 38 | 
            +
                    cases.values.flatten(1).uniq
         | 
| 39 | 
            +
                  else
         | 
| 40 | 
            +
                    _, paths = cases.reverse_each.find{ |(l, _)| l <= line }
         | 
| 41 | 
            +
                    paths
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                protected
         | 
| 46 | 
            +
                def isolate stat, path, super_env=nil
         | 
| 47 | 
            +
                  env = Env.new(super_env)
         | 
| 48 | 
            +
                  idx = path.first
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  suite.tests.first(idx).each do |(type, arg, _)|
         | 
| 51 | 
            +
                    case type
         | 
| 52 | 
            +
                    when :before
         | 
| 53 | 
            +
                      env.before << arg
         | 
| 54 | 
            +
                    when :after
         | 
| 55 | 
            +
                      env.after  << arg
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  if path.size == 1
         | 
| 60 | 
            +
                    _, desc, test = suite.tests[idx]
         | 
| 61 | 
            +
                    suite.run(stat, desc, test, env)
         | 
| 62 | 
            +
                  else
         | 
| 63 | 
            +
                    Isolator[suite.tests[idx][1]].isolate(stat, path.drop(1), env)
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  stat
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def build_all_tests result={}, path=[]
         | 
| 70 | 
            +
                  suite.tests.each_with_index.inject(result) do |
         | 
| 71 | 
            +
                    tests, ((type, imp, block, opts), index)|
         | 
| 72 | 
            +
                    current = path + [index]
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    case type
         | 
| 75 | 
            +
                    when :describe, :would
         | 
| 76 | 
            +
                      source_location = expand_source_location(block)
         | 
| 77 | 
            +
                      init_source_store_path(tests, source_location)
         | 
| 78 | 
            +
                    end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                    case type
         | 
| 81 | 
            +
                    when :describe
         | 
| 82 | 
            +
                      Isolator[imp].build_all_tests(tests, current) do |nested|
         | 
| 83 | 
            +
                        store_path(tests, nested, source_location, opts[:groups])
         | 
| 84 | 
            +
                      end
         | 
| 85 | 
            +
                    when :would
         | 
| 86 | 
            +
                      yield(current) if block_given?
         | 
| 87 | 
            +
                      store_path(tests, current, source_location, opts[:groups])
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                    tests
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def expand_source_location block
         | 
| 95 | 
            +
                  file, line = block.source_location
         | 
| 96 | 
            +
                  [File.expand_path(file), line]
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                def init_source_store_path tests, source_location
         | 
| 100 | 
            +
                  source, line = source_location
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  root = tests[:files] ||= {}
         | 
| 103 | 
            +
                  map = root[source] ||= {}
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  # Most of the time, line is always getting larger because we're
         | 
| 106 | 
            +
                  # scanning from top to bottom, and we really need to make sure
         | 
| 107 | 
            +
                  # that the map is sorted because whenever we're looking up which
         | 
| 108 | 
            +
                  # test we want from a particular line, we want to find the closest
         | 
| 109 | 
            +
                  # block rounding up. See Isolator#by_source
         | 
| 110 | 
            +
                  # However, it's not always appending from top to bottom, because
         | 
| 111 | 
            +
                  # we might be adding more tests from Suite#paste, and the original
         | 
| 112 | 
            +
                  # test could be defined in the same file, on previous lines!
         | 
| 113 | 
            +
                  # Because of this, we really need to make sure the map is balanced.
         | 
| 114 | 
            +
                  # If we ever have ordered map in Ruby, we don't have to do this...
         | 
| 115 | 
            +
                  # See the test for Isolator.all_tests (test/test_isolator.rb)
         | 
| 116 | 
            +
                  balanced_append(map, line, [])
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                def store_path tests, path, source_location, groups
         | 
| 120 | 
            +
                  store_for_groups(tests, path, groups) if groups
         | 
| 121 | 
            +
                  store_for_source(tests, path, source_location)
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                def store_for_groups tests, path, groups
         | 
| 125 | 
            +
                  map = tests[:groups] ||= {}
         | 
| 126 | 
            +
                  groups.each do |g|
         | 
| 127 | 
            +
                    (map[g.to_s] ||= []) << path
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                def store_for_source tests, path, source_location
         | 
| 132 | 
            +
                  source, line = source_location
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                  tests[:files][source][line] << path
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                def balanced_append map, key, value
         | 
| 138 | 
            +
                  last_key = map.reverse_each.first.first unless map.empty?
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                  map[key] ||= []
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                  map.replace(Hash[map.sort]) if last_key && key < last_key
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
              end
         | 
| 145 | 
            +
            end
         | 
    
        data/lib/pork/mode/parallel.rb
    CHANGED
    
    | @@ -2,22 +2,21 @@ | |
| 2 2 | 
             
            require 'pork/mode/shuffled'
         | 
| 3 3 |  | 
| 4 4 | 
             
            module Pork
         | 
| 5 | 
            -
               | 
| 5 | 
            +
              class Parallel < Struct.new(:isolator)
         | 
| 6 6 | 
             
                def cores
         | 
| 7 7 | 
             
                  8
         | 
| 8 8 | 
             
                end
         | 
| 9 9 |  | 
| 10 | 
            -
                def  | 
| 10 | 
            +
                def execute stat=Stat.new, paths=isolator.all_paths
         | 
| 11 | 
            +
                  executor = Shuffled.new(isolator)
         | 
| 11 12 | 
             
                  stat.prepare(paths)
         | 
| 12 13 | 
             
                  paths.shuffle.each_slice(cores).map do |paths_slice|
         | 
| 13 14 | 
             
                    Thread.new do
         | 
| 14 | 
            -
                      execute( | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 15 | 
            +
                      executor.execute(
         | 
| 16 | 
            +
                        Stat.new(stat.reporter, stat.protected_exceptions),
         | 
| 17 | 
            +
                        paths_slice)
         | 
| 17 18 | 
             
                    end
         | 
| 18 19 | 
             
                  end.map(&:value).inject(stat, &:merge)
         | 
| 19 20 | 
             
                end
         | 
| 20 21 | 
             
              end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
              Executor.extend(Parallel)
         | 
| 23 22 | 
             
            end
         | 
    
        data/lib/pork/mode/sequential.rb
    CHANGED
    
    | @@ -1,11 +1,11 @@ | |
| 1 1 |  | 
| 2 | 
            +
            require 'pork/executor'
         | 
| 3 | 
            +
             | 
| 2 4 | 
             
            module Pork
         | 
| 3 | 
            -
               | 
| 4 | 
            -
                def  | 
| 5 | 
            +
              class Sequential < Executor
         | 
| 6 | 
            +
                def execute stat=Stat.new, paths=isolator.all_paths
         | 
| 5 7 | 
             
                  stat.prepare(paths)
         | 
| 6 | 
            -
                  paths.inject(stat, &method(:isolate))
         | 
| 8 | 
            +
                  paths.inject(stat, &isolator.method(:isolate))
         | 
| 7 9 | 
             
                end
         | 
| 8 10 | 
             
              end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
              Executor.extend(Sequential)
         | 
| 11 11 | 
             
            end
         | 
    
        data/lib/pork/mode/shuffled.rb
    CHANGED
    
    | @@ -1,11 +1,11 @@ | |
| 1 1 |  | 
| 2 | 
            +
            require 'pork/executor'
         | 
| 3 | 
            +
             | 
| 2 4 | 
             
            module Pork
         | 
| 3 | 
            -
               | 
| 4 | 
            -
                def  | 
| 5 | 
            +
              class Shuffled < Executor
         | 
| 6 | 
            +
                def execute stat=Stat.new, paths=isolator.all_paths
         | 
| 5 7 | 
             
                  stat.prepare(paths)
         | 
| 6 | 
            -
                  paths.shuffle.inject(stat, &method(:isolate))
         | 
| 8 | 
            +
                  paths.shuffle.inject(stat, &isolator.method(:isolate))
         | 
| 7 9 | 
             
                end
         | 
| 8 10 | 
             
              end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
              Executor.extend(Shuffled)
         | 
| 11 11 | 
             
            end
         |