rspec-varys 0.0.3 → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9b5d6746ad0ced69ace33d7f785783a1a9289c3
4
- data.tar.gz: e5579d289843714febeddd99b882d95f79c94779
3
+ metadata.gz: cbc742320b2d49ca1b0ccfb05d60c189212820f4
4
+ data.tar.gz: d56e9a8c273902aedab09c984a1e7c17249dad03
5
5
  SHA512:
6
- metadata.gz: 4b25c426e5f447bb33d3d2216c0b593d0d1be37ab1be19223217b706a4a54a1d8dd796e779fea428c487a34443086e2da95178ae78e1d6613ea1dfb60ab99ddc
7
- data.tar.gz: e485f28b72288b5ecf2212e1c3f7bcfd115a32918838f6a8a1e9ac93ed6ae4046a3cd0c7a07b9de7ed15cfc9b22e2d53b96f9b9e99645a4fbb9a28e727b58c3d
6
+ metadata.gz: 1494635acd2c1106fe2309477866dcb3cb9782d4937144e1feaf0bf681cbb3197c051c6e56eb0fdf02cad15921a1afedb27c0b27db0cc5c2ce90c68718a0e81b
7
+ data.tar.gz: 79b1b8d13c8b9bf5fbd23fa14d48cfc9ebe4972f69fea4ec4ef184524ef7a6f4e4a05b411c748d5e86ae4320778d0d89927ea679f202adc9a42e5c3343b3d22c
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- gem 'pry-rescue'
data/bin/genspecs ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+
@@ -6,6 +6,7 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
6
6
  $:.unshift File.expand_path('../../lib', File.dirname(__FILE__))
7
7
 
8
8
  require "rspec/varys"
9
+ require "rspec/varys/rspec_generator"
9
10
 
10
11
  RSpec.configure do |config|
11
12
 
@@ -17,6 +18,7 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
17
18
 
18
19
  config.after(:suite) do
19
20
  RSpec::Varys.print_report
21
+ RSpec::Varys::RSpecGenerator.run
20
22
  end
21
23
  end
22
24
  """
@@ -54,24 +56,29 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
54
56
 
55
57
  When I run `rspec top_level_spec.rb`
56
58
  Then it should pass with:
57
- """
59
+ """ruby
58
60
  Specs have been generated based on mocks you aren't currently testing.
59
61
  """
60
- And the file "generated_specs/person_spec.rb" should contain:
62
+ And the file "varys.yaml" should contain:
63
+ """yaml
64
+ ---
65
+ :untested_stubs:
66
+ - :class_name: Person
67
+ :method: full_name
68
+ :returns: Dick Jones
61
69
  """
62
- describe Person do
63
70
 
64
- describe "#full_name" do
65
-
66
- it "returns the correct value" do
67
- pending
68
- confirm(subject).can receive(:full_name).and_return("Dick Jones")
69
- expect(subject.full_name).to eq("Dick Jones")
70
- end
71
+ And the file "generated_specs.rb" should contain:
72
+ """ruby
73
+ describe Person, "#full_name" do
71
74
 
75
+ it "returns something" do
76
+ expect(subject.full_name).to return("Dick Jones")
72
77
  end
73
78
 
74
79
  end
80
+
81
+
75
82
  """
76
83
 
77
84
 
@@ -108,36 +115,44 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
108
115
 
109
116
  When I run `rspec top_level_spec.rb`
110
117
  Then it should pass with:
111
- """
118
+ """ruby
112
119
  Specs have been generated based on mocks you aren't currently testing.
113
120
  """
114
- And the file "generated_specs/person_spec.rb" should contain:
121
+ And the file "varys.yaml" should contain:
122
+ """yaml
123
+ ---
124
+ :untested_stubs:
125
+ - :class_name: Person
126
+ :method: title
127
+ :returns: Vice President
128
+ - :class_name: Person
129
+ :method: full_name
130
+ :returns: Dick Jones
115
131
  """
116
- describe Person do
117
-
118
- describe "#title" do
119
132
 
120
- it "returns the correct value" do
121
- pending
122
- confirm(subject).can receive(:title).and_return("Vice President")
123
- expect(subject.title).to eq("Vice President")
124
- end
133
+ And the file "generated_specs.rb" should contain:
134
+ """ruby
135
+ describe Person, "#title" do
125
136
 
137
+ it "returns something" do
138
+ expect(subject.title).to return("Vice President")
126
139
  end
127
140
 
128
- describe "#full_name" do
141
+ end
129
142
 
130
- it "returns the correct value" do
131
- pending
132
- confirm(subject).can receive(:full_name).and_return("Dick Jones")
133
- expect(subject.full_name).to eq("Dick Jones")
134
- end
135
143
 
144
+ describe Person, "#full_name" do
145
+
146
+ it "returns something" do
147
+ expect(subject.full_name).to return("Dick Jones")
136
148
  end
137
149
 
138
150
  end
151
+
152
+
139
153
  """
140
154
 
155
+
141
156
  Scenario: For one matched and one unmatched expectation
142
157
  Given a file named "top_level_spec.rb" with:
143
158
  """ruby
@@ -148,8 +163,8 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
148
163
 
149
164
  it "starts with an introduction" do
150
165
  boss = Person.new('Dick', 'Jones')
151
- expect(boss).to receive(:full_name).and_return("Dick Jones")
152
- expect(boss).to receive(:title).and_return("Vice President")
166
+ allow(boss).to receive(:full_name).and_return("Dick Jones")
167
+ allow(boss).to receive(:title).and_return("Vice President")
153
168
  expect(boss.welcome).to eq "Welcome to OCP, I'm Vice President Dick Jones"
154
169
  end
155
170
 
@@ -162,7 +177,6 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
162
177
  describe "#full_name" do
163
178
 
164
179
  it "returns the correct value" do
165
- pending
166
180
  confirm(subject).can receive(:full_name).and_return("Dick Jones")
167
181
  # ...
168
182
  end
@@ -188,24 +202,16 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
188
202
 
189
203
  When I run `rspec top_level_spec.rb`
190
204
  Then it should pass with:
191
- """
205
+ """ruby
192
206
  Specs have been generated based on mocks you aren't currently testing.
193
207
  """
194
- And the file "generated_specs/person_spec.rb" should contain:
195
- """
196
- describe Person do
197
-
198
- describe "#title" do
199
-
200
- it "returns the correct value" do
201
- pending
202
- confirm(subject).can receive(:title).and_return("Vice President")
203
- expect(subject.title).to eq("Vice President")
204
- end
205
-
206
- end
207
-
208
- end
208
+ And the file "varys.yaml" should contain:
209
+ """yaml
210
+ ---
211
+ :untested_stubs:
212
+ - :class_name: Person
213
+ :method: title
214
+ :returns: Vice President
209
215
  """
210
216
 
211
217
  Scenario: For an expectation with parameters
@@ -221,7 +227,6 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
221
227
  describe "#full_name" do
222
228
 
223
229
  it "returns the correct value" do
224
- pending
225
230
  confirm(subject).can receive(:full_name).and_return("Dick Jones")
226
231
  expect(subject).to receive(:join_names).with("Dick", "Jones").and_return("Dick Jones")
227
232
  subject.full_name
@@ -254,22 +259,30 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
254
259
 
255
260
  When I run `rspec top_level_spec.rb`
256
261
  Then it should pass with:
257
- """
262
+ """ruby
258
263
  Specs have been generated based on mocks you aren't currently testing.
259
264
  """
260
- And the file "generated_specs/person_spec.rb" should contain:
265
+ And the file "varys.yaml" should contain:
266
+ """yaml
267
+ ---
268
+ :untested_stubs:
269
+ - :class_name: Person
270
+ :method: join_names
271
+ :returns: Dick Jones
272
+ :arguments:
273
+ - Dick
274
+ - Jones
261
275
  """
262
- describe Person do
263
276
 
264
- describe "#join_names" do
265
-
266
- it "returns the correct value" do
267
- pending
268
- confirm(subject).can receive(:join_names).with("Dick", "Jones").and_return("Dick Jones")
269
- expect(subject.join_names("Dick", "Jones")).to eq("Dick Jones")
270
- end
277
+ And the file "generated_specs.rb" should contain:
278
+ """ruby
279
+ describe Person, "#join_names" do
271
280
 
281
+ it "returns something" do
282
+ expect(subject.join_names("Dick", "Jones")).to return("Dick Jones")
272
283
  end
273
284
 
274
285
  end
286
+
287
+
275
288
  """
data/features/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- *Everything should be built top-down, except the first time - Alan
1
+ *Everything should be built top-down, except the first time 1. Alan
2
2
  Perlis*
3
3
 
4
4
  RSpec-Varys automatically generates RSpec specs from your mocked methods each time your suite is run.
@@ -7,4 +7,27 @@ This enables you to build your program from the top-down (or outside-in if
7
7
  your prefer) without having to manually keep track of which mocks have
8
8
  been validated.
9
9
 
10
- Available on [Github](https://github.com/ritchiey/rspec-varys)
10
+ Installation instructions can be found [here](https://github.com/ritchiey/rspec-varys).
11
+
12
+ A typical workflow using rspec-varys looks like this. Note, I haven't
13
+ written "and run your specs again" at the end of each step, that's
14
+ implied.
15
+
16
+ - if you have no failing specs and you need some new functionality, write a new top-level spec.
17
+
18
+ - if your specs are failing because your **spec** calls a non-existent function,
19
+ write the code for that function. Feel free to call methods that
20
+ don't exist yet.
21
+
22
+ - if your specs are failing because your **code** calls a non-existent function
23
+ stub that function out in the spec using `allow`.
24
+
25
+ - if your specs pass but varys generates new specs for untested stubs,
26
+ copy the generated specs into the appropriate spec file.
27
+
28
+ - if varys warns you about unneeded specs, delete those specs and any
29
+ code that can be removed without making other specs fail.
30
+
31
+ - if your specs pass but there are pending specs, pick one and remove
32
+ the `pending` statement.
33
+
@@ -1 +1,3 @@
1
1
  require 'aruba/cucumber'
2
+
3
+
data/lib/rspec/varys.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "rspec/varys/version"
2
2
  require "fileutils"
3
+ require 'yaml'
3
4
 
4
5
  module RSpec
5
6
  module Varys
@@ -26,11 +27,25 @@ module RSpec
26
27
  {
27
28
  class_name: class_name,
28
29
  message: message,
29
- args: [],
30
- return_value: "Dick Jones"
30
+ args: args,
31
+ return_value: return_value
31
32
  }
32
33
  end
33
34
 
35
+ def args
36
+ customization = customizations.find{|c| c.instance_variable_get('@method_name') == :with}
37
+ (customization && customization.instance_variable_get('@args')) || []
38
+ end
39
+
40
+ def return_value
41
+ customization = customizations.find{|c| c.instance_variable_get('@method_name') == :and_return}
42
+ customization && customization.instance_variable_get('@args').first
43
+ end
44
+
45
+ def customizations
46
+ @ability.instance_variable_get('@recorded_customizations')
47
+ end
48
+
34
49
  def class_name
35
50
  @object.class.name
36
51
  end
@@ -121,7 +136,7 @@ module RSpec::Varys
121
136
  end
122
137
 
123
138
  def self.params(args)
124
- args.map{|a| serialize(a)}.join(", ")
139
+ args.map{|a| serialize(a)}.join(", ")
125
140
  end
126
141
 
127
142
  def self.parameters(spec)
@@ -133,20 +148,35 @@ module RSpec::Varys
133
148
  end
134
149
 
135
150
  def self.print_report
136
- dest_path = "generated_specs"
137
- FileUtils.mkdir_p dest_path
138
- generated_specs.each do |class_name, specs|
139
- File.open("#{dest_path}/#{underscore class_name}_spec.rb", 'w') do |file|
140
- file.write "describe #{class_name} do\n\n"
141
- specs.each do |spec|
142
- file.write(spec)
143
- end
144
- file.write "end"
145
- end
151
+ open_yaml_file do |yaml_file|
152
+ yaml_file.write YAML.dump(report)
146
153
  end
147
154
  puts "Specs have been generated based on mocks you aren't currently testing."
148
155
  end
149
156
 
157
+ def self.report
158
+ {
159
+ untested_stubs: unconfirmed_messages.map do |call|
160
+ {
161
+ class_name: call[:class_name],
162
+ method: call[:message].to_s,
163
+ returns: call[:return_value]
164
+ }.merge(arguments_if_any(call))
165
+ end
166
+ }
167
+ end
168
+
169
+ def self.arguments_if_any(call)
170
+ call[:args].length > 0 ? { arguments: call[:args] } : { }
171
+ end
172
+
173
+ def self.open_yaml_file
174
+ File.open("varys.yaml", 'w') do |io|
175
+ yield io
176
+ end
177
+ end
178
+
179
+
150
180
  def self.unconfirmed_messages
151
181
  recorded_messages - confirmed_messages
152
182
  end
@@ -0,0 +1,51 @@
1
+ class RSpec::Varys::RSpecGenerator
2
+
3
+ def self.run
4
+
5
+ specs = YAML.load(File.read "varys.yaml")
6
+
7
+ File.open('generated_specs.rb', 'w') do |file|
8
+ process_specs(specs, file)
9
+ end
10
+
11
+ end
12
+
13
+ def self.process_specs(specs, file)
14
+ specs[:untested_stubs].each do |spec|
15
+ file.puts <<-EOF
16
+ describe #{spec[:class_name]}, "##{spec[:method]}" do
17
+
18
+ it "returns something" do
19
+ expect(subject.#{spec[:method]}#{args_if_any(spec)}).to return(#{serialize spec[:returns]})
20
+ end
21
+
22
+ end
23
+
24
+
25
+ EOF
26
+ end
27
+ end
28
+
29
+ def self.args_if_any(call)
30
+ args = call[:arguments]
31
+ (args && args.length > 0) ? "(#{args.map{|a| serialize a}.join ', '})" : ""
32
+ end
33
+
34
+ # Attempt to recreate the source-code to represent this argument in the setup
35
+ # for our generated spec.
36
+ def self.serialize(arg)
37
+ if %w(Array Hash Float Fixnum String).include? arg.class.name
38
+ arg.pretty_inspect.chop
39
+ else
40
+ guess_constructor arg
41
+ end
42
+ end
43
+
44
+ # Don't recognise the type so we don't know how to recreate it
45
+ # in source code. So we'll take a guess at what might work and
46
+ # let the user fix it up if necessary.
47
+ def self.guess_constructor(arg)
48
+ "#{arg.class.name}.new(#{serialize(arg.to_s)})"
49
+ end
50
+
51
+ end
@@ -1,5 +1,5 @@
1
1
  module Rspec
2
2
  module Varys
3
- VERSION = "0.0.3"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -34,6 +34,7 @@ describe RSpec::Varys do
34
34
  { class_name: 'Object', message: :a_message, args: [:a_parameter], return_value: 42 }
35
35
  ])
36
36
  end
37
+
37
38
  end
38
39
 
39
40
  describe ".confirmed_messages" do
@@ -50,6 +51,17 @@ describe RSpec::Varys do
50
51
  }])
51
52
  end
52
53
 
54
+ it "parses parameters" do
55
+ described_class.reset
56
+ confirm(Person.new 'Dick', 'Jones').can receive(:full_name).with(:blah).and_return("Dick Jones")
57
+ expect(described_class.confirmed_messages).to match_array([{
58
+ class_name: 'Person',
59
+ message: :full_name,
60
+ args: [:blah],
61
+ return_value: "Dick Jones"
62
+ }])
63
+ end
64
+
53
65
  end
54
66
 
55
67
  it "records the messages sent to a spy" do
@@ -0,0 +1,4 @@
1
+
2
+ require 'pry'
3
+ Dir.glob(::File.expand_path('../support/*.rb', __FILE__)).each { |f| require_relative f }
4
+ Dir.glob(::File.expand_path('../../lib/*.rb', __FILE__)).each { |f| require_relative f }
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require_relative '../../lib/rspec/varys/rspec_generator'
3
+
4
+ describe RSpec::Varys::RSpecGenerator do
5
+
6
+ describe ".process_specs" do
7
+
8
+ context "given a file YAML file with one missing spec with arguments" do
9
+ let(:specs) {
10
+ YAML.load <<-SPECS
11
+ ---
12
+ :untested_stubs:
13
+ - :class_name: Person
14
+ :method: full_name
15
+ :arguments:
16
+ - Dick
17
+ - Jones
18
+ :returns: Dick Jones
19
+ SPECS
20
+ }
21
+
22
+ it "generates the spec" do
23
+ output = ""
24
+ StringIO.open(output, 'w') do |file|
25
+ described_class.process_specs(specs, file)
26
+ end
27
+ expect(output).to eq <<-EOF
28
+ describe Person, "#full_name" do
29
+
30
+ it "returns something" do
31
+ expect(subject.full_name("Dick", "Jones")).to return("Dick Jones")
32
+ end
33
+
34
+ end
35
+
36
+
37
+ EOF
38
+ end
39
+ end
40
+
41
+
42
+ context "given a file YAML file with one missing spec" do
43
+ let(:specs) {
44
+ YAML.load <<-SPECS
45
+ ---
46
+ :untested_stubs:
47
+ - :class_name: Person
48
+ :method: full_name
49
+ :returns: Dick Jones
50
+ SPECS
51
+ }
52
+
53
+ it "generates the spec" do
54
+ output = ""
55
+ StringIO.open(output, 'w') do |file|
56
+ described_class.process_specs(specs, file)
57
+ end
58
+ expect(output).to eq <<-EOF
59
+ describe Person, "#full_name" do
60
+
61
+ it "returns something" do
62
+ expect(subject.full_name).to return("Dick Jones")
63
+ end
64
+
65
+ end
66
+
67
+
68
+ EOF
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-varys
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ritchie Young
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-27 00:00:00.000000000 Z
11
+ date: 2015-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,7 +108,8 @@ description: Automatically track which assumptions you've made in the form or mo
108
108
  and stubs actually work.
109
109
  email:
110
110
  - ritchiey@gmail.com
111
- executables: []
111
+ executables:
112
+ - genspecs
112
113
  extensions: []
113
114
  extra_rdoc_files: []
114
115
  files:
@@ -119,13 +120,17 @@ files:
119
120
  - LICENSE.txt
120
121
  - README.md
121
122
  - Rakefile
123
+ - bin/genspecs
122
124
  - features/generating_specs.feature
123
125
  - features/readme.md
124
- - features/support/env.rb
126
+ - features/support/external.rb
125
127
  - lib/rspec/varys.rb
128
+ - lib/rspec/varys/rspec_generator.rb
126
129
  - lib/rspec/varys/version.rb
127
130
  - rspec-varys.gemspec
128
131
  - spec/rspec/varys_spec.rb
132
+ - spec/spec_helper.rb
133
+ - spec/varys/rspec_generator_spec.rb
129
134
  homepage: https://github.com/ritchiey/rspec-varys
130
135
  licenses:
131
136
  - MIT
@@ -153,6 +158,8 @@ summary: Generate RSpec specs from intelligence gathered from doubles and spies.
153
158
  test_files:
154
159
  - features/generating_specs.feature
155
160
  - features/readme.md
156
- - features/support/env.rb
161
+ - features/support/external.rb
157
162
  - spec/rspec/varys_spec.rb
163
+ - spec/spec_helper.rb
164
+ - spec/varys/rspec_generator_spec.rb
158
165
  has_rdoc: