mutest-rspec 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/lib/mutest/integration/rspec.rb +149 -0
  4. metadata +103 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d815353a912cc998ffe6a9cb7bb3bf1f5a2e4634
4
+ data.tar.gz: 6130aab82b5a76037ef4a5b33129dac098cfecd1
5
+ SHA512:
6
+ metadata.gz: 63cd6c629d0ccdd37c48f44f626b8a2f7d3860c5a755f4152e4cdf2568d65b557b4288fe33de165f2358600f53b079164135ed228c3449c61b553862d2aaf59f
7
+ data.tar.gz: 3c23b9ed824243424b466c7758ffeed4ae52ef42c99e904974b8b12e8ab2b0a0e1d0ae0ea3775f7cca9d6089dc1ef4d314e1ce7b1761f13d482cc1ca605b74a8
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2012-2017 Markus Schirp
2
+ Copyright (c) 2017 John Backus
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,149 @@
1
+ require 'rspec/core'
2
+
3
+ module Mutest
4
+ class Integration
5
+ # Rspec integration
6
+ #
7
+ # This looks so complicated, because rspec:
8
+ #
9
+ # * Keeps its state global in RSpec.world and lots of other places
10
+ # * There is no API to "just run a subset of examples", the examples
11
+ # need to be selected in-place via mutating the `RSpec.filtered_examples`
12
+ # data structure
13
+ # * Does not maintain a unique identification for an example,
14
+ # aside the instances of `RSpec::Core::Example` objects itself.
15
+ # For that reason identifying examples by:
16
+ # * full description
17
+ # * location
18
+ # Is NOT enough. It would not be unique. So we add an "example index"
19
+ # for unique reference.
20
+ #
21
+ # :reek:TooManyConstants
22
+ class Rspec < self
23
+ ALL_EXPRESSION = Expression::Namespace::Recursive.new(scope_name: nil)
24
+ EXPRESSION_CANDIDATE = /\A([^ ]+)(?: )?/
25
+ LOCATION_DELIMITER = ':'.freeze
26
+ EXIT_SUCCESS = 0
27
+ CLI_OPTIONS = IceNine.deep_freeze(%w[spec --fail-fast])
28
+ TEST_ID_FORMAT = 'rspec:%<index>d:%<location>s/%<description>s'.freeze
29
+
30
+ private_constant(*constants(false))
31
+
32
+ # Initialize rspec integration
33
+ #
34
+ # @return [undefined]
35
+ def initialize(*)
36
+ super
37
+ @output = StringIO.new
38
+ @runner = RSpec::Core::Runner.new(RSpec::Core::ConfigurationOptions.new(CLI_OPTIONS))
39
+ @world = RSpec.world
40
+ end
41
+
42
+ # Setup rspec integration
43
+ #
44
+ # @return [self]
45
+ def setup
46
+ @runner.setup($stderr, @output)
47
+ self
48
+ end
49
+ memoize :setup
50
+
51
+ # Run a collection of tests
52
+ #
53
+ # @param [Enumerable<Mutest::Test>] tests
54
+ #
55
+ # @return [Result::Test]
56
+ #
57
+ # rubocop:disable MethodLength
58
+ def call(tests)
59
+ examples = tests.map(&all_tests_index.method(:fetch))
60
+ filter_examples(&examples.method(:include?))
61
+ start = Time.now
62
+ passed = @runner.run_specs(@world.ordered_example_groups).equal?(EXIT_SUCCESS)
63
+ @output.rewind
64
+ Result::Test.new(
65
+ output: @output.read,
66
+ passed: passed,
67
+ runtime: Time.now - start,
68
+ tests: tests
69
+ )
70
+ end
71
+
72
+ # Available tests
73
+ #
74
+ # @return [Enumerable<Test>]
75
+ def all_tests
76
+ all_tests_index.keys
77
+ end
78
+ memoize :all_tests
79
+
80
+ private
81
+
82
+ # Index of available tests
83
+ #
84
+ # @return [Hash<Test, RSpec::Core::Example]
85
+ def all_tests_index
86
+ all_examples.each_with_index.each_with_object({}) do |(example, example_index), index|
87
+ index[parse_example(example, example_index)] = example
88
+ end
89
+ end
90
+ memoize :all_tests_index
91
+
92
+ # Parse example into test
93
+ #
94
+ # @param [RSpec::Core::Example] example
95
+ # @param [Fixnum] index
96
+ #
97
+ # @return [Test]
98
+ def parse_example(example, index)
99
+ metadata = example.metadata
100
+
101
+ id = format(
102
+ TEST_ID_FORMAT,
103
+ index: index,
104
+ location: metadata.fetch(:location),
105
+ description: metadata.fetch(:full_description)
106
+ )
107
+
108
+ Test.new(
109
+ expression: parse_expression(metadata),
110
+ id: id
111
+ )
112
+ end
113
+
114
+ # Parse metadata into expression
115
+ #
116
+ # @param [RSpec::Core::Example::MetaData] metadata
117
+ #
118
+ # @return [Expression]
119
+ def parse_expression(metadata)
120
+ if metadata.key?(:mutest_expression)
121
+ expression_parser.(metadata.fetch(:mutest_expression))
122
+ else
123
+ match = EXPRESSION_CANDIDATE.match(metadata.fetch(:full_description))
124
+ expression_parser.try_parse(match.captures.first) || ALL_EXPRESSION
125
+ end
126
+ end
127
+
128
+ # Available rspec examples
129
+ #
130
+ # @return [Array<String, RSpec::Core::Example]
131
+ def all_examples
132
+ @world.example_groups.flat_map(&:descendants).flat_map(&:examples).select do |example|
133
+ example.metadata.fetch(:mutest, true)
134
+ end
135
+ end
136
+
137
+ # Filter examples
138
+ #
139
+ # @param [#call] predicate
140
+ #
141
+ # @return [undefined]
142
+ def filter_examples(&predicate)
143
+ @world.filtered_examples.each_value do |examples|
144
+ examples.keep_if(&predicate)
145
+ end
146
+ end
147
+ end # Rspec
148
+ end # Integration
149
+ end # Mutest
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mutest-rspec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Gollahon
8
+ - John Backus
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-01-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mutest
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 0.0.2
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 0.0.2
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec-core
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 3.4.0
35
+ - - "<"
36
+ - !ruby/object:Gem::Version
37
+ version: 3.6.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 3.4.0
45
+ - - "<"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.6.0
48
+ - !ruby/object:Gem::Dependency
49
+ name: bundler
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: 1.3.5
58
+ type: :development
59
+ prerelease: false
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - "~>"
63
+ - !ruby/object:Gem::Version
64
+ version: '1.3'
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 1.3.5
68
+ description: Rspec integration for mutest
69
+ email:
70
+ - johncbackus@gmail.com
71
+ - daniel.gollahon@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - LICENSE
76
+ files:
77
+ - LICENSE
78
+ - lib/mutest/integration/rspec.rb
79
+ homepage: https://github.com/backus/mutest
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.5.1
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Rspec integration for mutest
103
+ test_files: []