mutant 0.3.6 → 0.5.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/.travis.yml +1 -0
- data/Changelog.md +13 -0
- data/Gemfile +1 -1
- data/Guardfile +7 -25
- data/LICENSE +1 -1
- data/README.md +16 -10
- data/config/flay.yml +1 -1
- data/config/reek.yml +11 -11
- data/config/rubocop.yml +1 -1
- data/lib/mutant.rb +3 -10
- data/lib/mutant/cli.rb +199 -80
- data/lib/mutant/config.rb +3 -3
- data/lib/mutant/killer.rb +20 -0
- data/lib/mutant/matcher/filter.rb +3 -8
- data/lib/mutant/matcher/method/instance.rb +1 -1
- data/lib/mutant/matcher/namespace.rb +31 -2
- data/lib/mutant/matcher/null.rb +26 -0
- data/lib/mutant/mutation.rb +0 -1
- data/lib/mutant/reporter/cli/printer.rb +29 -0
- data/lib/mutant/reporter/cli/printer/config.rb +16 -116
- data/lib/mutant/runner/config.rb +47 -1
- data/lib/mutant/strategy.rb +39 -1
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/walker.rb +51 -0
- data/mutant-rspec.gemspec +24 -0
- data/mutant.gemspec +7 -3
- data/spec/integration/mutant/rspec_spec.rb +11 -6
- data/spec/integration/mutant/zombie_spec.rb +2 -2
- data/spec/shared/method_matcher_behavior.rb +6 -6
- data/spec/spec_helper.rb +2 -2
- data/spec/unit/mutant/cli_new_spec.rb +49 -34
- data/spec/unit/mutant/context/scope/root_spec.rb +1 -1
- data/spec/unit/mutant/loader/eval_spec.rb +2 -2
- data/spec/unit/mutant/matcher/chain_spec.rb +1 -1
- data/spec/unit/mutant/matcher/methods/instance_spec.rb +1 -1
- data/spec/unit/mutant/matcher/methods/singleton_spec.rb +1 -1
- data/spec/unit/mutant/matcher/namespace_spec.rb +1 -1
- data/spec/unit/mutant/mutation_spec.rb +1 -1
- data/spec/unit/mutant/{killer/rspec_spec.rb → rspec/killer_spec.rb} +2 -1
- data/spec/unit/mutant/runner/config_spec.rb +36 -21
- data/spec/unit/mutant_spec.rb +7 -9
- metadata +25 -22
- data/lib/mutant/cli/builder.rb +0 -167
- data/lib/mutant/killer/rspec.rb +0 -95
- data/lib/mutant/predicate.rb +0 -70
- data/lib/mutant/predicate/attribute.rb +0 -68
- data/lib/mutant/predicate/blacklist.rb +0 -27
- data/lib/mutant/predicate/matcher.rb +0 -38
- data/lib/mutant/predicate/whitelist.rb +0 -28
- data/lib/mutant/strategy/rspec.rb +0 -76
- data/spec/unit/mutant/cli/builder/rspec_spec.rb +0 -38
- data/spec/unit/mutant/matcher/filter_spec.rb +0 -19
- data/spec/unit/mutant/predicate_spec.rb +0 -135
    
        data/lib/mutant/config.rb
    CHANGED
    
    | @@ -8,10 +8,10 @@ module Mutant | |
| 8 8 | 
             
                  :debug,
         | 
| 9 9 | 
             
                  :strategy,
         | 
| 10 10 | 
             
                  :matcher,
         | 
| 11 | 
            -
                  :subject_predicate,
         | 
| 12 11 | 
             
                  :reporter,
         | 
| 13 12 | 
             
                  :fail_fast,
         | 
| 14 | 
            -
                  :zombie
         | 
| 13 | 
            +
                  :zombie,
         | 
| 14 | 
            +
                  :expected_coverage
         | 
| 15 15 | 
             
                )
         | 
| 16 16 |  | 
| 17 17 | 
             
                # Enumerate subjects
         | 
| @@ -28,7 +28,7 @@ module Mutant | |
| 28 28 | 
             
                #
         | 
| 29 29 | 
             
                def subjects(&block)
         | 
| 30 30 | 
             
                  return to_enum(__method__) unless block_given?
         | 
| 31 | 
            -
                   | 
| 31 | 
            +
                  matcher.each(&block)
         | 
| 32 32 | 
             
                  self
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
    
        data/lib/mutant/killer.rb
    CHANGED
    
    | @@ -99,5 +99,25 @@ module Mutant | |
| 99 99 | 
             
                #
         | 
| 100 100 | 
             
                abstract_method :run
         | 
| 101 101 |  | 
| 102 | 
            +
                # Null killer that never kills a mutation
         | 
| 103 | 
            +
                class Null < self
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                private
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  # Run killer
         | 
| 108 | 
            +
                  #
         | 
| 109 | 
            +
                  # @return [true]
         | 
| 110 | 
            +
                  #   when mutant was killed
         | 
| 111 | 
            +
                  #
         | 
| 112 | 
            +
                  # @return [false]
         | 
| 113 | 
            +
                  #   otherwise
         | 
| 114 | 
            +
                  #
         | 
| 115 | 
            +
                  # @api private
         | 
| 116 | 
            +
                  #
         | 
| 117 | 
            +
                  def run
         | 
| 118 | 
            +
                    false
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                end
         | 
| 102 122 | 
             
              end # Killer
         | 
| 103 123 | 
             
            end # Mutant
         | 
| @@ -4,7 +4,7 @@ module Mutant | |
| 4 4 | 
             
              class Matcher
         | 
| 5 5 | 
             
                # Matcher filter
         | 
| 6 6 | 
             
                class Filter < self
         | 
| 7 | 
            -
                  include Concord.new(:matcher, : | 
| 7 | 
            +
                  include Concord.new(:matcher, :predicate)
         | 
| 8 8 |  | 
| 9 9 | 
             
                  # Enumerate matches
         | 
| 10 10 | 
             
                  #
         | 
| @@ -16,14 +16,9 @@ module Mutant | |
| 16 16 | 
             
                  #
         | 
| 17 17 | 
             
                  # @api private
         | 
| 18 18 | 
             
                  #
         | 
| 19 | 
            -
                  def each
         | 
| 19 | 
            +
                  def each(&block)
         | 
| 20 20 | 
             
                    return to_enum unless block_given?
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                    matcher.each do |subject|
         | 
| 23 | 
            -
                      next if filter.match?(subject)
         | 
| 24 | 
            -
                      yield subject
         | 
| 25 | 
            -
                    end
         | 
| 26 | 
            -
             | 
| 21 | 
            +
                    matcher.select(&predicate.method(:call)).each(&block)
         | 
| 27 22 | 
             
                    self
         | 
| 28 23 | 
             
                  end
         | 
| 29 24 |  | 
| @@ -54,6 +54,29 @@ module Mutant | |
| 54 54 | 
             
                    end
         | 
| 55 55 | 
             
                  end
         | 
| 56 56 |  | 
| 57 | 
            +
                  # Return scope name
         | 
| 58 | 
            +
                  #
         | 
| 59 | 
            +
                  # @param [Class,Module] scope
         | 
| 60 | 
            +
                  #
         | 
| 61 | 
            +
                  # @return [String]
         | 
| 62 | 
            +
                  #   if scope has a name and does not raise exceptions optaining it
         | 
| 63 | 
            +
                  #
         | 
| 64 | 
            +
                  # @return [nil]
         | 
| 65 | 
            +
                  #   otherwise
         | 
| 66 | 
            +
                  #
         | 
| 67 | 
            +
                  # @api private
         | 
| 68 | 
            +
                  #
         | 
| 69 | 
            +
                  def self.scope_name(scope)
         | 
| 70 | 
            +
                    scope.name
         | 
| 71 | 
            +
                  rescue => exception
         | 
| 72 | 
            +
                    $stderr.puts <<-MESSAGE
         | 
| 73 | 
            +
            WARNING:
         | 
| 74 | 
            +
            While optaining #{scope.class}#name from: #{scope.inspect}
         | 
| 75 | 
            +
            It raised an error: #{exception.inspect} fix your lib!
         | 
| 76 | 
            +
                    MESSAGE
         | 
| 77 | 
            +
                    nil
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 57 80 | 
             
                  # Yield scope if name matches pattern
         | 
| 58 81 | 
             
                  #
         | 
| 59 82 | 
             
                  # @param [Module,Class] scope
         | 
| @@ -63,9 +86,15 @@ module Mutant | |
| 63 86 | 
             
                  # @api private
         | 
| 64 87 | 
             
                  #
         | 
| 65 88 | 
             
                  def emit_scope(scope)
         | 
| 66 | 
            -
                    name = scope | 
| 89 | 
            +
                    name = self.class.scope_name(scope)
         | 
| 67 90 | 
             
                    # FIXME: Fix nokogiri to return a string here
         | 
| 68 | 
            -
                     | 
| 91 | 
            +
                    unless name.nil? or name.kind_of?(String)
         | 
| 92 | 
            +
                      $stderr.puts <<-MESSAGE
         | 
| 93 | 
            +
            WARNING:
         | 
| 94 | 
            +
            #{scope.class}#name did not return a string or nil.
         | 
| 95 | 
            +
            Fix your lib!
         | 
| 96 | 
            +
                      MESSAGE
         | 
| 97 | 
            +
                    end
         | 
| 69 98 | 
             
                    if pattern =~ name
         | 
| 70 99 | 
             
                      yield scope
         | 
| 71 100 | 
             
                    end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mutant
         | 
| 4 | 
            +
              class Matcher
         | 
| 5 | 
            +
                # A null matcher, that does not match any subjects
         | 
| 6 | 
            +
                class Null < self
         | 
| 7 | 
            +
                  include Equalizer.new
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  # Enumerate subjects
         | 
| 10 | 
            +
                  #
         | 
| 11 | 
            +
                  # @return [Enumerator<Subject]
         | 
| 12 | 
            +
                  #   if no block given
         | 
| 13 | 
            +
                  #
         | 
| 14 | 
            +
                  # @return [self]
         | 
| 15 | 
            +
                  #   otherwise
         | 
| 16 | 
            +
                  #
         | 
| 17 | 
            +
                  # @api private
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  def each(&block)
         | 
| 20 | 
            +
                    return to_enum unless block_given?
         | 
| 21 | 
            +
                    self
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                end # Null
         | 
| 25 | 
            +
              end # Matcher
         | 
| 26 | 
            +
            end # Mutant
         | 
    
        data/lib/mutant/mutation.rb
    CHANGED
    
    
| @@ -10,6 +10,35 @@ module Mutant | |
| 10 10 |  | 
| 11 11 | 
             
                    REGISTRY = {}
         | 
| 12 12 |  | 
| 13 | 
            +
                    # Create delegators to object
         | 
| 14 | 
            +
                    #
         | 
| 15 | 
            +
                    # @return [undefined]
         | 
| 16 | 
            +
                    #
         | 
| 17 | 
            +
                    # @api private
         | 
| 18 | 
            +
                    #
         | 
| 19 | 
            +
                    def self.delegate(*names)
         | 
| 20 | 
            +
                      names.each do |name|
         | 
| 21 | 
            +
                        define_delegator(name)
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                    private_class_method :delegate
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    # Create delegator to object
         | 
| 27 | 
            +
                    #
         | 
| 28 | 
            +
                    # @param [Symbol] name
         | 
| 29 | 
            +
                    #
         | 
| 30 | 
            +
                    # @return [undefined]
         | 
| 31 | 
            +
                    #
         | 
| 32 | 
            +
                    # @api private
         | 
| 33 | 
            +
                    #
         | 
| 34 | 
            +
                    def self.define_delegator(name)
         | 
| 35 | 
            +
                      define_method(name) do
         | 
| 36 | 
            +
                        object.public_send(name)
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
                      private name
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                    private_class_method :define_delegator
         | 
| 41 | 
            +
             | 
| 13 42 | 
             
                    # Registre handler for class
         | 
| 14 43 | 
             
                    #
         | 
| 15 44 | 
             
                    # @param [Class] klass
         | 
| @@ -10,6 +10,8 @@ module Mutant | |
| 10 10 |  | 
| 11 11 | 
             
                      handle(Mutant::Config)
         | 
| 12 12 |  | 
| 13 | 
            +
                      delegate :matcher, :strategy, :expected_coverage
         | 
| 14 | 
            +
             | 
| 13 15 | 
             
                      # Report configuration
         | 
| 14 16 | 
             
                      #
         | 
| 15 17 | 
             
                      # @param [Mutant::Config] config
         | 
| @@ -20,9 +22,9 @@ module Mutant | |
| 20 22 | 
             
                      #
         | 
| 21 23 | 
             
                      def run
         | 
| 22 24 | 
             
                        info 'Mutant configuration:'
         | 
| 23 | 
            -
                        info 'Matcher: | 
| 24 | 
            -
                        info ' | 
| 25 | 
            -
                        info ' | 
| 25 | 
            +
                        info 'Matcher:         %s',     matcher.inspect
         | 
| 26 | 
            +
                        info 'Strategy:        %s',     strategy.inspect
         | 
| 27 | 
            +
                        info 'Expect Coverage: %02f%%', expected_coverage.inspect
         | 
| 26 28 | 
             
                        self
         | 
| 27 29 | 
             
                      end
         | 
| 28 30 |  | 
| @@ -31,6 +33,11 @@ module Mutant | |
| 31 33 |  | 
| 32 34 | 
             
                        handle(Mutant::Runner::Config)
         | 
| 33 35 |  | 
| 36 | 
            +
                        delegate(
         | 
| 37 | 
            +
                          :amount_kills, :amount_mutations, :amount_kils,
         | 
| 38 | 
            +
                          :coverage, :subjects, :failed_subjects, :runtime, :mutations
         | 
| 39 | 
            +
                        )
         | 
| 40 | 
            +
             | 
| 34 41 | 
             
                        # Run printer
         | 
| 35 42 | 
             
                        #
         | 
| 36 43 | 
             
                        # @return [self]
         | 
| @@ -42,73 +49,18 @@ module Mutant | |
| 42 49 | 
             
                          info   'Subjects:  %s',      amount_subjects
         | 
| 43 50 | 
             
                          info   'Mutations: %s',      amount_mutations
         | 
| 44 51 | 
             
                          info   'Kills:     %s',      amount_kills
         | 
| 52 | 
            +
                          info   'Alive:     %s',      amount_alive
         | 
| 45 53 | 
             
                          info   'Runtime:   %0.2fs',  runtime
         | 
| 46 54 | 
             
                          info   'Killtime:  %0.2fs',  killtime
         | 
| 47 55 | 
             
                          info   'Overhead:  %0.2f%%', overhead
         | 
| 48 56 | 
             
                          status 'Coverage:  %0.2f%%', coverage
         | 
| 49 | 
            -
                          status ' | 
| 57 | 
            +
                          status 'Expected:  %0.2f%%', object.config.expected_coverage
         | 
| 50 58 | 
             
                          print_generic_stats
         | 
| 51 59 | 
             
                          self
         | 
| 52 60 | 
             
                        end
         | 
| 53 61 |  | 
| 54 62 | 
             
                      private
         | 
| 55 63 |  | 
| 56 | 
            -
                        # Return subjects
         | 
| 57 | 
            -
                        #
         | 
| 58 | 
            -
                        # @return [Array<Subject>]
         | 
| 59 | 
            -
                        #
         | 
| 60 | 
            -
                        # @api private
         | 
| 61 | 
            -
                        #
         | 
| 62 | 
            -
                        def subjects
         | 
| 63 | 
            -
                          object.subjects
         | 
| 64 | 
            -
                        end
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                        # Walker for all ast nodes
         | 
| 67 | 
            -
                        class Walker
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                          # Run walkter
         | 
| 70 | 
            -
                          #
         | 
| 71 | 
            -
                          # @param [Parser::AST::Node] root
         | 
| 72 | 
            -
                          #
         | 
| 73 | 
            -
                          # @return [self]
         | 
| 74 | 
            -
                          #
         | 
| 75 | 
            -
                          # @api private
         | 
| 76 | 
            -
                          #
         | 
| 77 | 
            -
                          def self.run(root, &block)
         | 
| 78 | 
            -
                            new(root, block)
         | 
| 79 | 
            -
                            self
         | 
| 80 | 
            -
                          end
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                          private_class_method :new
         | 
| 83 | 
            -
             | 
| 84 | 
            -
                          # Initialize and run walker
         | 
| 85 | 
            -
                          #
         | 
| 86 | 
            -
                          # @param [Parser::AST::Node] root
         | 
| 87 | 
            -
                          # @param [#call(node)] block
         | 
| 88 | 
            -
                          #
         | 
| 89 | 
            -
                          # @return [undefined]
         | 
| 90 | 
            -
                          #
         | 
| 91 | 
            -
                          # @api private
         | 
| 92 | 
            -
                          #
         | 
| 93 | 
            -
                          def initialize(root, block)
         | 
| 94 | 
            -
                            @root, @block = root, block
         | 
| 95 | 
            -
                            dispatch(root)
         | 
| 96 | 
            -
                          end
         | 
| 97 | 
            -
             | 
| 98 | 
            -
                        private
         | 
| 99 | 
            -
             | 
| 100 | 
            -
                          # Perform dispatch
         | 
| 101 | 
            -
                          #
         | 
| 102 | 
            -
                          # @return [undefined]
         | 
| 103 | 
            -
                          #
         | 
| 104 | 
            -
                          # @api private
         | 
| 105 | 
            -
                          #
         | 
| 106 | 
            -
                          def dispatch(node)
         | 
| 107 | 
            -
                            @block.call(node)
         | 
| 108 | 
            -
                            node.children.grep(Parser::AST::Node).each(&method(:dispatch))
         | 
| 109 | 
            -
                          end
         | 
| 110 | 
            -
                        end
         | 
| 111 | 
            -
             | 
| 112 64 | 
             
                        # Print generic stats
         | 
| 113 65 | 
             
                        #
         | 
| 114 66 | 
             
                        # @return [undefined]
         | 
| @@ -131,7 +83,7 @@ module Mutant | |
| 131 83 | 
             
                        # @api private
         | 
| 132 84 | 
             
                        #
         | 
| 133 85 | 
             
                        def generic_stats
         | 
| 134 | 
            -
                           | 
| 86 | 
            +
                          subjects.each_with_object(Hash.new(0)) do |runner, stats|
         | 
| 135 87 | 
             
                            Walker.run(runner.subject.node) do |node|
         | 
| 136 88 | 
             
                              if Mutator::Registry.lookup(node) == Mutator::Node::Generic
         | 
| 137 89 | 
             
                                stats[node.type] += 1
         | 
| @@ -157,32 +109,11 @@ module Mutant | |
| 157 109 | 
             
                        # @api private
         | 
| 158 110 | 
             
                        #
         | 
| 159 111 | 
             
                        def print_mutations
         | 
| 160 | 
            -
                           | 
| 112 | 
            +
                          failed_subjects.each do |subject|
         | 
| 161 113 | 
             
                            Subject::Runner::Details.run(subject, output)
         | 
| 162 114 | 
             
                          end
         | 
| 163 115 | 
             
                        end
         | 
| 164 116 |  | 
| 165 | 
            -
                        # Return mutations
         | 
| 166 | 
            -
                        #
         | 
| 167 | 
            -
                        # @return [Array<Mutation>]
         | 
| 168 | 
            -
                        #
         | 
| 169 | 
            -
                        # @api private
         | 
| 170 | 
            -
                        #
         | 
| 171 | 
            -
                        def mutations
         | 
| 172 | 
            -
                          subjects.map(&:mutations).flatten
         | 
| 173 | 
            -
                        end
         | 
| 174 | 
            -
                        memoize :mutations
         | 
| 175 | 
            -
             | 
| 176 | 
            -
                        # Return amount of mutations
         | 
| 177 | 
            -
                        #
         | 
| 178 | 
            -
                        # @return [Fixnum]
         | 
| 179 | 
            -
                        #
         | 
| 180 | 
            -
                        # @api private
         | 
| 181 | 
            -
                        #
         | 
| 182 | 
            -
                        def amount_mutations
         | 
| 183 | 
            -
                          mutations.length
         | 
| 184 | 
            -
                        end
         | 
| 185 | 
            -
             | 
| 186 117 | 
             
                        # Return amount of time in killers
         | 
| 187 118 | 
             
                        #
         | 
| 188 119 | 
             
                        # @return [Float]
         | 
| @@ -194,16 +125,6 @@ module Mutant | |
| 194 125 | 
             
                        end
         | 
| 195 126 | 
             
                        memoize :killtime
         | 
| 196 127 |  | 
| 197 | 
            -
                        # Return amount of kills
         | 
| 198 | 
            -
                        #
         | 
| 199 | 
            -
                        # @return [Fixnum]
         | 
| 200 | 
            -
                        #
         | 
| 201 | 
            -
                        # @api private
         | 
| 202 | 
            -
                        #
         | 
| 203 | 
            -
                        def amount_kills
         | 
| 204 | 
            -
                          mutations.select(&:success?).length
         | 
| 205 | 
            -
                        end
         | 
| 206 | 
            -
             | 
| 207 128 | 
             
                        # Return mutant overhead
         | 
| 208 129 | 
             
                        #
         | 
| 209 130 | 
             
                        # @return [Float]
         | 
| @@ -215,27 +136,6 @@ module Mutant | |
| 215 136 | 
             
                          Rational(runtime - killtime, runtime) * 100
         | 
| 216 137 | 
             
                        end
         | 
| 217 138 |  | 
| 218 | 
            -
                        # Return runtime
         | 
| 219 | 
            -
                        #
         | 
| 220 | 
            -
                        # @return [Float]
         | 
| 221 | 
            -
                        #
         | 
| 222 | 
            -
                        # @api private
         | 
| 223 | 
            -
                        #
         | 
| 224 | 
            -
                        def runtime
         | 
| 225 | 
            -
                          object.runtime
         | 
| 226 | 
            -
                        end
         | 
| 227 | 
            -
             | 
| 228 | 
            -
                        # Return coverage
         | 
| 229 | 
            -
                        #
         | 
| 230 | 
            -
                        # @return [Float]
         | 
| 231 | 
            -
                        #
         | 
| 232 | 
            -
                        # @api private
         | 
| 233 | 
            -
                        #
         | 
| 234 | 
            -
                        def coverage
         | 
| 235 | 
            -
                          return 0 if amount_mutations.zero?
         | 
| 236 | 
            -
                          Rational(amount_kills, amount_mutations) * 100
         | 
| 237 | 
            -
                        end
         | 
| 238 | 
            -
             | 
| 239 139 | 
             
                        # Return amount of alive mutations
         | 
| 240 140 | 
             
                        #
         | 
| 241 141 | 
             
                        # @return [Fixnum]
         | 
| @@ -243,12 +143,12 @@ module Mutant | |
| 243 143 | 
             
                        # @api private
         | 
| 244 144 | 
             
                        #
         | 
| 245 145 | 
             
                        def amount_alive
         | 
| 246 | 
            -
                          amount_mutations - amount_kills
         | 
| 146 | 
            +
                          object.amount_mutations - amount_kills
         | 
| 247 147 | 
             
                        end
         | 
| 248 148 |  | 
| 249 149 | 
             
                      end # Runner
         | 
| 250 150 | 
             
                    end # Config
         | 
| 251 151 | 
             
                  end # Printer
         | 
| 252 | 
            -
                end #  | 
| 152 | 
            +
                end # CLI
         | 
| 253 153 | 
             
              end # Reporter
         | 
| 254 154 | 
             
            end # Mutant
         | 
    
        data/lib/mutant/runner/config.rb
    CHANGED
    
    | @@ -40,6 +40,8 @@ module Mutant | |
| 40 40 | 
             
                  end
         | 
| 41 41 | 
             
                  memoize :failed_subjects
         | 
| 42 42 |  | 
| 43 | 
            +
                  COVERAGE_PRECISION = 1
         | 
| 44 | 
            +
             | 
| 43 45 | 
             
                  # Test if run was successful
         | 
| 44 46 | 
             
                  #
         | 
| 45 47 | 
             
                  # @return [true]
         | 
| @@ -51,7 +53,7 @@ module Mutant | |
| 51 53 | 
             
                  # @api private
         | 
| 52 54 | 
             
                  #
         | 
| 53 55 | 
             
                  def success?
         | 
| 54 | 
            -
                     | 
| 56 | 
            +
                    coverage.round(COVERAGE_PRECISION) == config.expected_coverage.round(COVERAGE_PRECISION)
         | 
| 55 57 | 
             
                  end
         | 
| 56 58 | 
             
                  memoize :success?
         | 
| 57 59 |  | 
| @@ -65,6 +67,50 @@ module Mutant | |
| 65 67 | 
             
                    config.strategy
         | 
| 66 68 | 
             
                  end
         | 
| 67 69 |  | 
| 70 | 
            +
                  # Return coverage
         | 
| 71 | 
            +
                  #
         | 
| 72 | 
            +
                  # @return [Float]
         | 
| 73 | 
            +
                  #
         | 
| 74 | 
            +
                  # @api private
         | 
| 75 | 
            +
                  #
         | 
| 76 | 
            +
                  def coverage
         | 
| 77 | 
            +
                    return 0.0 if amount_mutations.zero?
         | 
| 78 | 
            +
                    Rational(amount_kills, amount_mutations) * 100
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                  memoize :coverage
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  # Return amount of kills
         | 
| 83 | 
            +
                  #
         | 
| 84 | 
            +
                  # @return [Fixnum]
         | 
| 85 | 
            +
                  #
         | 
| 86 | 
            +
                  # @api private
         | 
| 87 | 
            +
                  #
         | 
| 88 | 
            +
                  def amount_kills
         | 
| 89 | 
            +
                    mutations.select(&:success?).length
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
                  memoize :amount_kills
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  # Return mutations
         | 
| 94 | 
            +
                  #
         | 
| 95 | 
            +
                  # @return [Array<Mutation>]
         | 
| 96 | 
            +
                  #
         | 
| 97 | 
            +
                  # @api private
         | 
| 98 | 
            +
                  #
         | 
| 99 | 
            +
                  def mutations
         | 
| 100 | 
            +
                    subjects.map(&:mutations).flatten
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
                  memoize :mutations
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  # Return amount of mutations
         | 
| 105 | 
            +
                  #
         | 
| 106 | 
            +
                  # @return [Fixnum]
         | 
| 107 | 
            +
                  #
         | 
| 108 | 
            +
                  # @api private
         | 
| 109 | 
            +
                  #
         | 
| 110 | 
            +
                  def amount_mutations
         | 
| 111 | 
            +
                    mutations.length
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
             | 
| 68 114 | 
             
                private
         | 
| 69 115 |  | 
| 70 116 | 
             
                  # Run config
         |