mutant 0.1.1 → 0.2.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.
Files changed (225) hide show
  1. data/.gitignore +5 -11
  2. data/.rspec +0 -1
  3. data/.travis.yml +14 -3
  4. data/Changelog.md +3 -0
  5. data/Gemfile +5 -1
  6. data/Gemfile.devtools +49 -0
  7. data/Guardfile +18 -0
  8. data/README.md +67 -0
  9. data/Rakefile +4 -1
  10. data/TODO +13 -0
  11. data/bin/mutant +14 -0
  12. data/bin/zombie +14 -0
  13. data/config/flay.yml +3 -0
  14. data/config/flog.yml +2 -0
  15. data/config/roodi.yml +26 -0
  16. data/config/site.reek +93 -0
  17. data/config/yardstick.yml +2 -0
  18. data/lib/inflector.rb +7 -0
  19. data/lib/inflector/defaults.rb +62 -0
  20. data/lib/inflector/inflections.rb +209 -0
  21. data/lib/inflector/methods.rb +149 -0
  22. data/lib/inflector/version.rb +3 -0
  23. data/lib/mutant.rb +96 -21
  24. data/lib/mutant/cli.rb +309 -0
  25. data/lib/mutant/color.rb +61 -0
  26. data/lib/mutant/context.rb +36 -0
  27. data/lib/mutant/context/scope.rb +138 -0
  28. data/lib/mutant/differ.rb +100 -0
  29. data/lib/mutant/helper.rb +38 -0
  30. data/lib/mutant/killer.rb +136 -0
  31. data/lib/mutant/killer/forking.rb +41 -0
  32. data/lib/mutant/killer/rspec.rb +49 -0
  33. data/lib/mutant/killer/static.rb +19 -0
  34. data/lib/mutant/loader.rb +129 -0
  35. data/lib/mutant/matcher.rb +55 -0
  36. data/lib/mutant/matcher/chain.rb +66 -0
  37. data/lib/mutant/matcher/method.rb +173 -0
  38. data/lib/mutant/matcher/method/classifier.rb +126 -0
  39. data/lib/mutant/matcher/method/instance.rb +67 -0
  40. data/lib/mutant/matcher/method/singleton.rb +141 -0
  41. data/lib/mutant/matcher/object_space.rb +114 -0
  42. data/lib/mutant/matcher/scope_methods.rb +127 -0
  43. data/lib/mutant/mutation.rb +101 -12
  44. data/lib/mutant/mutation/filter.rb +75 -0
  45. data/lib/mutant/mutation/filter/code.rb +68 -0
  46. data/lib/mutant/mutation/filter/regexp.rb +39 -0
  47. data/lib/mutant/mutation/filter/whitelist.rb +47 -0
  48. data/lib/mutant/mutator.rb +134 -30
  49. data/lib/mutant/mutator/node.rb +163 -0
  50. data/lib/mutant/mutator/node/arguments.rb +24 -0
  51. data/lib/mutant/mutator/node/block.rb +24 -0
  52. data/lib/mutant/mutator/node/define.rb +24 -0
  53. data/lib/mutant/mutator/node/if_statement.rb +93 -0
  54. data/lib/mutant/mutator/node/literal.rb +54 -0
  55. data/lib/mutant/mutator/node/literal/array.rb +28 -0
  56. data/lib/mutant/mutator/node/literal/boolean.rb +49 -0
  57. data/lib/mutant/mutator/node/literal/dynamic.rb +24 -0
  58. data/lib/mutant/mutator/node/literal/empty_array.rb +26 -0
  59. data/lib/mutant/mutator/node/literal/fixnum.rb +37 -0
  60. data/lib/mutant/mutator/node/literal/float.rb +48 -0
  61. data/lib/mutant/mutator/node/literal/hash.rb +89 -0
  62. data/lib/mutant/mutator/node/literal/nil.rb +25 -0
  63. data/lib/mutant/mutator/node/literal/range.rb +94 -0
  64. data/lib/mutant/mutator/node/literal/regex.rb +43 -0
  65. data/lib/mutant/mutator/node/literal/string.rb +26 -0
  66. data/lib/mutant/mutator/node/literal/symbol.rb +26 -0
  67. data/lib/mutant/mutator/node/noop.rb +55 -0
  68. data/lib/mutant/mutator/node/receiver_case.rb +140 -0
  69. data/lib/mutant/mutator/node/return.rb +31 -0
  70. data/lib/mutant/mutator/node/send.rb +112 -0
  71. data/lib/mutant/mutator/registry.rb +48 -0
  72. data/lib/mutant/mutator/util.rb +87 -0
  73. data/lib/mutant/random.rb +24 -27
  74. data/lib/mutant/reporter.rb +48 -30
  75. data/lib/mutant/reporter/cli.rb +221 -0
  76. data/lib/mutant/reporter/null.rb +42 -0
  77. data/lib/mutant/reporter/stats.rb +64 -0
  78. data/lib/mutant/runner.rb +112 -0
  79. data/lib/mutant/strategy.rb +42 -0
  80. data/lib/mutant/strategy/rspec.rb +59 -0
  81. data/lib/mutant/strategy/rspec/example_lookup.rb +122 -0
  82. data/lib/mutant/subject.rb +115 -0
  83. data/lib/mutant/support/method_object.rb +31 -0
  84. data/locator.rb +87 -0
  85. data/mutant.gemspec +21 -21
  86. data/spec/integration/mutant/differ_spec.rb +15 -0
  87. data/spec/integration/mutant/loader_spec.rb +21 -0
  88. data/spec/integration/mutant/method_matching_spec.rb +269 -0
  89. data/spec/integration/mutant/rspec_killer_spec.rb +24 -0
  90. data/spec/integration/mutant/runner_spec.rb +26 -0
  91. data/spec/integration/mutant/zombie_spec.rb +8 -0
  92. data/spec/rcov.opts +7 -0
  93. data/spec/shared/command_method_behavior.rb +7 -0
  94. data/spec/shared/each_method_behaviour.rb +15 -0
  95. data/spec/shared/hash_method_behavior.rb +17 -0
  96. data/spec/shared/idempotent_method_behavior.rb +7 -0
  97. data/spec/shared/invertible_method_behaviour.rb +9 -0
  98. data/spec/shared/method_filter_parse_behavior.rb +16 -0
  99. data/spec/shared/method_match_behavior.rb +39 -0
  100. data/spec/shared/mutator_behavior.rb +46 -0
  101. data/spec/spec_helper.rb +11 -14
  102. data/spec/support/compress_helper.rb +10 -0
  103. data/spec/support/rspec.rb +22 -0
  104. data/spec/support/test_app.rb +5 -0
  105. data/spec/support/zombie.rb +141 -0
  106. data/spec/unit/mutant/cli/class_methods/new_spec.rb +87 -0
  107. data/spec/unit/mutant/cli/class_methods/run_spec.rb +38 -0
  108. data/spec/unit/mutant/context/root_spec.rb +11 -0
  109. data/spec/unit/mutant/context/scope/class_methods/build_spec.rb +29 -0
  110. data/spec/unit/mutant/context/scope/root_spec.rb +22 -0
  111. data/spec/unit/mutant/context/scope/unqualified_name_spec.rb +27 -0
  112. data/spec/unit/mutant/killer/fail_ques_spec.rb +39 -0
  113. data/spec/unit/mutant/killer/rspec/class_methods/new_spec.rb +32 -0
  114. data/spec/unit/mutant/loader/eval/class_methods/run_spec.rb +33 -0
  115. data/spec/unit/mutant/loader/rubinius/class_methods/run_spec.rb +42 -0
  116. data/spec/unit/mutant/matcher/chain/each_spec.rb +37 -0
  117. data/spec/unit/mutant/matcher/chain/matchers_spec.rb +12 -0
  118. data/spec/unit/mutant/matcher/class_methods/from_string_spec.rb +49 -0
  119. data/spec/unit/mutant/matcher/class_methods/parse_spec.rb +12 -0
  120. data/spec/unit/mutant/matcher/each_spec.rb +14 -0
  121. data/spec/unit/mutant/matcher/method/class_methods/parse_spec.rb +21 -0
  122. data/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb +34 -0
  123. data/spec/unit/mutant/matcher/method/method_spec.rb +11 -0
  124. data/spec/unit/mutant/matcher/object_space/class_methods/parse_spec.rb +24 -0
  125. data/spec/unit/mutant/matcher/object_space/each_spec.rb +31 -0
  126. data/spec/unit/mutant/mutator/each_spec.rb +25 -0
  127. data/spec/unit/mutant/mutator/emit_new_spec.rb +51 -0
  128. data/spec/unit/mutant/mutator/emit_spec.rb +52 -0
  129. data/spec/unit/mutant/mutator/node/block/mutation_spec.rb +36 -0
  130. data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +47 -0
  131. data/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb +30 -0
  132. data/spec/unit/mutant/mutator/node/literal/array_spec.rb +30 -0
  133. data/spec/unit/mutant/mutator/node/literal/boolean/mutation_spec.rb +23 -0
  134. data/spec/unit/mutant/mutator/node/literal/empty_array_spec.rb +17 -0
  135. data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +17 -0
  136. data/spec/unit/mutant/mutator/node/literal/float_spec.rb +25 -0
  137. data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +34 -0
  138. data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +13 -0
  139. data/spec/unit/mutant/mutator/node/literal/range_spec.rb +35 -0
  140. data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +23 -0
  141. data/spec/unit/mutant/mutator/node/literal/string_spec.rb +17 -0
  142. data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +17 -0
  143. data/spec/unit/mutant/mutator/node/receiver_case/mutation_spec.rb +27 -0
  144. data/spec/unit/mutant/mutator/node/return/mutation_spec.rb +21 -0
  145. data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +78 -0
  146. data/spec/unit/mutant/mutator/self_spec.rb +7 -0
  147. data/spec/unit/mutant/subject/class_methods/new_spec.rb +13 -0
  148. data/spec/unit/mutant/subject/context_spec.rb +14 -0
  149. data/spec/unit/mutant/subject/each_spec.rb +35 -0
  150. data/spec/unit/mutant/subject/node_spec.rb +13 -0
  151. data/tasks/metrics/ci.rake +7 -0
  152. data/tasks/metrics/flay.rake +41 -0
  153. data/tasks/metrics/flog.rake +43 -0
  154. data/tasks/metrics/heckle.rake +216 -0
  155. data/tasks/metrics/metric_fu.rake +31 -0
  156. data/tasks/metrics/reek.rake +15 -0
  157. data/tasks/metrics/roodi.rake +15 -0
  158. data/tasks/metrics/yardstick.rake +23 -0
  159. data/tasks/spec.rake +45 -0
  160. data/tasks/yard.rake +9 -0
  161. data/test_app/.rspec +1 -0
  162. data/test_app/lib/test_app.rb +5 -0
  163. data/test_app/lib/test_app/literal.rb +32 -0
  164. data/test_app/spec/shared/command_method_behavior.rb +7 -0
  165. data/test_app/spec/shared/each_method_behaviour.rb +15 -0
  166. data/test_app/spec/shared/hash_method_behavior.rb +17 -0
  167. data/test_app/spec/shared/idempotent_method_behavior.rb +7 -0
  168. data/test_app/spec/shared/invertible_method_behaviour.rb +9 -0
  169. data/test_app/spec/shared/method_filter_parse_behavior.rb +16 -0
  170. data/test_app/spec/shared/method_match_behavior.rb +39 -0
  171. data/test_app/spec/shared/mutator_behavior.rb +44 -0
  172. data/test_app/spec/spec_helper.rb +7 -0
  173. data/test_app/spec/unit/test_app/literal/command_spec.rb +9 -0
  174. data/test_app/spec/unit/test_app/literal/string_spec.rb +9 -0
  175. metadata +346 -124
  176. data/.rvmrc +0 -1
  177. data/Readme.md +0 -13
  178. data/exe/mutate +0 -6
  179. data/lib/mutant/extensions.rb +0 -8
  180. data/lib/mutant/formatter.rb +0 -19
  181. data/lib/mutant/implementation.rb +0 -70
  182. data/lib/mutant/literal.rb +0 -147
  183. data/lib/mutant/method.rb +0 -31
  184. data/lib/mutant/mutatee.rb +0 -61
  185. data/lib/mutant/node.rb +0 -26
  186. data/lib/mutant/runners/rspec.rb +0 -34
  187. data/lib/mutant/version.rb +0 -3
  188. data/spec/functional/class_spec.rb +0 -46
  189. data/spec/functional/instance_method/array_spec.rb +0 -53
  190. data/spec/functional/instance_method/boolean_spec.rb +0 -101
  191. data/spec/functional/instance_method/call_spec.rb +0 -161
  192. data/spec/functional/instance_method/fixnum_spec.rb +0 -53
  193. data/spec/functional/instance_method/float_spec.rb +0 -53
  194. data/spec/functional/instance_method/hash_spec.rb +0 -53
  195. data/spec/functional/instance_method/if_spec.rb +0 -57
  196. data/spec/functional/instance_method/ivar_assign_spec.rb +0 -62
  197. data/spec/functional/instance_method/range_spec.rb +0 -53
  198. data/spec/functional/instance_method/regex_spec.rb +0 -55
  199. data/spec/functional/instance_method/string_spec.rb +0 -53
  200. data/spec/functional/instance_method/symbol_spec.rb +0 -53
  201. data/spec/functional/reporter/method_loaded_spec.rb +0 -62
  202. data/spec/functional/reporter/running_mutations_spec.rb +0 -60
  203. data/spec/functional/runners/rspec_spec.rb +0 -26
  204. data/spec/functional/singleton_method/array_spec.rb +0 -53
  205. data/spec/functional/singleton_method/boolean_spec.rb +0 -101
  206. data/spec/functional/singleton_method/call_spec.rb +0 -161
  207. data/spec/functional/singleton_method/fixnum_spec.rb +0 -53
  208. data/spec/functional/singleton_method/float_spec.rb +0 -53
  209. data/spec/functional/singleton_method/hash_spec.rb +0 -53
  210. data/spec/functional/singleton_method/if_spec.rb +0 -57
  211. data/spec/functional/singleton_method/ivar_assign_spec.rb +0 -60
  212. data/spec/functional/singleton_method/range_spec.rb +0 -53
  213. data/spec/functional/singleton_method/regex_spec.rb +0 -55
  214. data/spec/functional/singleton_method/string_spec.rb +0 -53
  215. data/spec/functional/singleton_method/symbol_spec.rb +0 -53
  216. data/spec/mutant/extensions_spec.rb +0 -13
  217. data/spec/mutant/implementation_spec.rb +0 -223
  218. data/spec/mutant/literal_spec.rb +0 -129
  219. data/spec/mutant/mutatee_spec.rb +0 -28
  220. data/spec/mutant/node_spec.rb +0 -41
  221. data/spec/mutant/random_spec.rb +0 -33
  222. data/spec/mutant/reporter_spec.rb +0 -17
  223. data/spec/mutant_spec.rb +0 -28
  224. data/spec/support/example_group_helpers.rb +0 -11
  225. data/spec/support/example_helpers.rb +0 -5
@@ -0,0 +1,42 @@
1
+ module Mutant
2
+ class Reporter
3
+ # Null reporter
4
+ Null = Class.new(self) do
5
+ # Report subject
6
+ #
7
+ # @param [Subject] subject
8
+ #
9
+ # @return [self]
10
+ #
11
+ # @api private
12
+ #
13
+ def subject(*)
14
+ self
15
+ end
16
+
17
+ # Report mutation
18
+ #
19
+ # @param [Mutation] mutation
20
+ #
21
+ # @return [self]
22
+ #
23
+ # @api private
24
+ #
25
+ def mutation(*)
26
+ self
27
+ end
28
+
29
+ # Report killer
30
+ #
31
+ # @param [Killer] killer
32
+ #
33
+ # @return [self]
34
+ #
35
+ # @api private
36
+ #
37
+ def killer(*)
38
+ self
39
+ end
40
+ end.new.freeze
41
+ end
42
+ end
@@ -0,0 +1,64 @@
1
+ module Mutant
2
+ class Reporter
3
+
4
+ # Stats gathered while reporter is running
5
+ class Stats
6
+
7
+ # Return subject count
8
+ #
9
+ # @return [Fixnum]
10
+ #
11
+ # @api private
12
+ #
13
+ attr_reader :subject
14
+
15
+ # Return mutation count
16
+ #
17
+ # @return [Fixnum]
18
+ #
19
+ # @api private
20
+ #
21
+ attr_reader :mutation
22
+
23
+ # Return kill count
24
+ #
25
+ # @return [Fixnum]
26
+ #
27
+ # @api private
28
+ #
29
+ attr_reader :kill
30
+
31
+ # Return mutation runtime
32
+ #
33
+ # @return [Float]
34
+ #
35
+ # @api private
36
+ #
37
+ attr_reader :time
38
+
39
+ def initialize
40
+ @start = Time.now
41
+ @subject = @mutation = @kill = @time = 0
42
+ end
43
+
44
+ def runtime
45
+ Time.now - @start
46
+ end
47
+
48
+ def subject
49
+ @subject +=1
50
+ end
51
+
52
+ def alive
53
+ @mutation - @kill
54
+ end
55
+
56
+ def killer(killer)
57
+ @mutation +=1
58
+ @kill +=1 unless killer.fail?
59
+ @time += killer.runtime
60
+ end
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,112 @@
1
+ module Mutant
2
+ # Runner that allows to mutate an entire project
3
+ class Runner
4
+ include Adamantium::Flat
5
+ extend MethodObject
6
+
7
+ # Return killers with errors
8
+ #
9
+ # @return [Enumerable<Killer>]
10
+ #
11
+ # @api private
12
+ #
13
+ attr_reader :errors
14
+
15
+ # Test for failure
16
+ #
17
+ # @return [true]
18
+ # returns true when there are left mutations
19
+ #
20
+ # @return [false]
21
+ # returns false othewise
22
+ #
23
+ # @api private
24
+ #
25
+ def fail?
26
+ !errors.empty?
27
+ end
28
+
29
+ # Return config
30
+ #
31
+ # @return [Mutant::Config]
32
+ #
33
+ # @api private
34
+ #
35
+ attr_reader :config
36
+
37
+ private
38
+
39
+ # Initialize object
40
+ #
41
+ # @param [Config] config
42
+ #
43
+ # @return [undefined]
44
+ #
45
+ # @api private
46
+ #
47
+ def initialize(config)
48
+ @config, @errors = config, []
49
+
50
+ reporter.config(config)
51
+
52
+ run
53
+
54
+ reporter.errors(@errors)
55
+ end
56
+
57
+ # Return reporter
58
+ #
59
+ # @return [Reporter]
60
+ #
61
+ # @api private
62
+ #
63
+ def reporter
64
+ config.reporter
65
+ end
66
+
67
+ # Run mutation killers on subjects
68
+ #
69
+ # @return [undefined]
70
+ #
71
+ # @api private
72
+ #
73
+ def run
74
+ config.matcher.each do |subject|
75
+ reporter.subject(subject)
76
+ run_subject(subject)
77
+ end
78
+ end
79
+
80
+ # Run mutation killers on subject
81
+ #
82
+ # @param [Subject] subject
83
+ #
84
+ # @return [undefined]
85
+ #
86
+ # @api private
87
+ #
88
+ def run_subject(subject)
89
+ subject.each do |mutation|
90
+ next unless config.filter.match?(mutation)
91
+ reporter.mutation(mutation)
92
+ kill(mutation)
93
+ end
94
+ end
95
+
96
+ # Run killer on mutation
97
+ #
98
+ # @param [Mutation] mutation
99
+ #
100
+ # @return [undefined]
101
+ #
102
+ # @api private
103
+ #
104
+ def kill(mutation)
105
+ killer = config.strategy.kill(mutation)
106
+ reporter.killer(killer)
107
+ if killer.fail?
108
+ @errors << killer
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,42 @@
1
+ module Mutant
2
+ class Strategy
3
+ include AbstractType
4
+
5
+ # Kill mutation
6
+ #
7
+ # @param [Mutation]
8
+ #
9
+ # @return [Killer]
10
+ #
11
+ # @api private
12
+ #
13
+ def self.kill(mutation)
14
+ killer.new(self, mutation)
15
+ end
16
+
17
+ # Return killer
18
+ #
19
+ # @return [Class:Killer]
20
+ #
21
+ # @api private
22
+ #
23
+ def self.killer
24
+ self::KILLER
25
+ end
26
+
27
+ # Static strategies
28
+ class Static < self
29
+
30
+ # Always fail to kill strategy
31
+ class Fail < self
32
+ KILLER = Killer::Static::Fail
33
+ end
34
+
35
+ # Always succeed to kill strategy
36
+ class Success < self
37
+ KILLER = Killer::Static::Success
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,59 @@
1
+ module Mutant
2
+ class Strategy
3
+
4
+ # Rspec strategy base class
5
+ class Rspec < self
6
+
7
+ KILLER = Killer::Forking.new(Killer::Rspec)
8
+
9
+ # DM2-style strategy
10
+ class DM2 < self
11
+
12
+ # Return filename pattern
13
+ #
14
+ # @return [String]
15
+ #
16
+ # @api private
17
+ #
18
+ def self.spec_files(mutation)
19
+ ExampleLookup.run(mutation)
20
+ end
21
+ end
22
+
23
+ # Run all unit specs per mutation
24
+ class Unit < self
25
+
26
+ # Return file name pattern for mutation
27
+ #
28
+ # @return [Mutation]
29
+ #
30
+ # @api private
31
+ #
32
+ def self.spec_files(mutation)
33
+ Dir['spec/unit/**/*_spec.rb']
34
+ end
35
+ end
36
+
37
+ # Run all integration specs per mutation
38
+ class Unit < self
39
+
40
+ # Return file name pattern for mutation
41
+ #
42
+ # @return [Mutation]
43
+ #
44
+ # @api private
45
+ #
46
+ def self.spec_files(mutation)
47
+ Dir['spec/integration/**/*_spec.rb']
48
+ end
49
+ end
50
+
51
+ # Run all specs per mutation
52
+ class Full < self
53
+ def self.spec_files(mutation)
54
+ Dir['spec/**/*_spec.rb']
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,122 @@
1
+ module Mutant
2
+ class Strategy
3
+ class Rspec
4
+
5
+ # Example lookup for rspec
6
+ class ExampleLookup
7
+ include Adamantium::Flat, Equalizer.new(:mutation)
8
+
9
+ # Perform example lookup
10
+ #
11
+ # @param [Mutation]
12
+ #
13
+ # @return [Enumerable<String>]
14
+ #
15
+ # @api private
16
+ #
17
+ def self.run(mutation)
18
+ new(mutation).spec_files
19
+ end
20
+
21
+ # Return mutation
22
+ #
23
+ # @return [Mutation]
24
+ #
25
+ # @api private
26
+ #
27
+ attr_reader :mutation
28
+
29
+ # Return spec files
30
+ #
31
+ # @return [Enumerable<String>]
32
+ #
33
+ # @api private
34
+ #
35
+ def spec_files
36
+ expression = glob_expression
37
+ files = Dir[expression]
38
+
39
+ if files.empty?
40
+ $stderr.puts("Spec file(s): #{expression.inspect} not found for #{mutation.identification}")
41
+ end
42
+
43
+ files
44
+ end
45
+ memoize :spec_files
46
+
47
+ private
48
+
49
+ # Return method matcher
50
+ #
51
+ # @return [Matcher]
52
+ #
53
+ # @api private
54
+ #
55
+ def matcher
56
+ mutation.subject.matcher
57
+ end
58
+
59
+ # Return spec file
60
+ #
61
+ # @return [String]
62
+ #
63
+ # @api private
64
+ #
65
+ def spec_file
66
+ matcher.method_name.to_s.
67
+ gsub(/\?\z/, '_predicate').
68
+ gsub(/\=\z/, '_writer').
69
+ gsub(/!\z/, '_bang') + '_spec.rb'
70
+ end
71
+ memoize :spec_file
72
+
73
+ # Return glob expression
74
+ #
75
+ # @return [String]
76
+ #
77
+ # @api private
78
+ #
79
+ def glob_expression
80
+ if mutation.subject.matcher.public?
81
+ "#{base_path}/#{spec_file}"
82
+ else
83
+ "#{base_path}/*_spec.rb"
84
+ end
85
+ end
86
+
87
+ # Return instance of singleton path appendo
88
+ #
89
+ # @return [String]
90
+ #
91
+ # @api private
92
+ #
93
+ def scope_append
94
+ matcher.kind_of?(Matcher::Method::Singleton) ? '/class_methods' : ''
95
+ end
96
+ memoize :scope_append
97
+
98
+ # Return base path
99
+ #
100
+ # @return [String]
101
+ #
102
+ # @api private
103
+ #
104
+ def base_path
105
+ "spec/unit/#{Inflector.underscore(mutation.subject.context.scope.name)}#{scope_append}"
106
+ end
107
+ memoize :base_path
108
+
109
+ # Initalize object
110
+ #
111
+ # @param [Mutation] mutation
112
+ #
113
+ # @api private
114
+ #
115
+ def initialize(mutation)
116
+ @mutation = mutation
117
+ end
118
+
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,115 @@
1
+ module Mutant
2
+ # Subject of a mutation
3
+ class Subject
4
+ include Adamantium::Flat, Enumerable, Equalizer.new(:context, :matcher, :node)
5
+
6
+ # Return context
7
+ #
8
+ # @return [Context]
9
+ #
10
+ # @api private
11
+ #
12
+ attr_reader :context
13
+
14
+ # Return matcher
15
+ #
16
+ # @return [Matcher]
17
+ #
18
+ # @api private
19
+ #
20
+ attr_reader :matcher
21
+
22
+ # Return AST node
23
+ #
24
+ # @return [Rubinius::AST::Node]
25
+ #
26
+ # @api private
27
+ #
28
+ attr_reader :node
29
+
30
+ # Enumerate possible mutations
31
+ #
32
+ # @return [self]
33
+ # returns self if block given
34
+ #
35
+ # @return [Enumerator<Mutation>]
36
+ # returns eumerator if no block given
37
+ #
38
+ # @api private
39
+ #
40
+ def each
41
+ return to_enum unless block_given?
42
+ Mutator.each(node) do |mutant|
43
+ yield Mutation.new(self, mutant)
44
+ end
45
+
46
+ self
47
+ end
48
+
49
+ # Return subject identicication
50
+ #
51
+ # @return [String]
52
+ #
53
+ # @api private
54
+ #
55
+ def identification
56
+ source_path = context.source_path
57
+ source_line = node.line
58
+ "#{matcher.identification}:#{source_path}:#{source_line}"
59
+ end
60
+ memoize :identification
61
+
62
+ # Return source representation of ast
63
+ #
64
+ # @return [Source]
65
+ #
66
+ # @api private
67
+ #
68
+ def source
69
+ ToSource.to_source(node)
70
+ end
71
+ memoize :source
72
+
73
+ # Return root AST for node
74
+ #
75
+ # @param [Rubinius::AST::Node] node
76
+ #
77
+ # @return [Rubinius::AST::Node]
78
+ #
79
+ # @api private
80
+ #
81
+ def root(node)
82
+ context.root(node)
83
+ end
84
+
85
+ # Return root AST node for original AST ndoe
86
+ #
87
+ # @return [Rubinius::AST::Node]
88
+ #
89
+ # @api private
90
+ #
91
+ def original_root
92
+ root(node)
93
+ end
94
+ memoize :original_root
95
+
96
+ private
97
+
98
+ # Initialize subject
99
+ #
100
+ # @param [Matcher] matcher
101
+ # the context of mutations
102
+ #
103
+ # @param [Rubinius::AST::Node] node
104
+ # the node to be mutated
105
+ #
106
+ # @return [unkown]
107
+ #
108
+ # @api private
109
+ #
110
+ def initialize(matcher, context, node)
111
+ @matcher, @context, @node = matcher, context, node
112
+ end
113
+
114
+ end
115
+ end