code_driven_development 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b09b6d5336aaa29537662229c0c204572ee2e81d
4
- data.tar.gz: 610a995a3c9012fbd5d6ff374b096793e6fbf259
3
+ metadata.gz: 546316dbe66b0a333a9dd89b55222bacd74e502b
4
+ data.tar.gz: 07c3576f12dc0b9667ed79145994e55c5dc344d3
5
5
  SHA512:
6
- metadata.gz: e83e416be1af608df38ae343b34e7c10dc6775a98f8b3290348eeb4bc4634a83c39beb0aaca10498697ba8761ef89672ff7985f021ee5ee6754b5522af94884d
7
- data.tar.gz: 900dd1f8ce764b77eec4126e39d66d5c5d2028696bd24a3cb7d6d7ef749f9d631408639bd0c30bb672413c481c724506398264343bbb7f43907f49bade1c3076
6
+ metadata.gz: 01bc5e3a0b27dcc595473b5bb8312f538c785c1e33efa341e12b7c85f25514ff83e11eded00b194031f6006298f3df764e8b2b316c59542db03e6b9f154af936
7
+ data.tar.gz: a023a61a8c1ecd86ae3c5e5e353902b53ce51da33e98af64ca36c759d993d9e2c1baddd6b366e3c8e6123aa1875fe7aeb48c3db98db47ccf6c1cb6ec4fe5029f
data/README.md CHANGED
@@ -13,9 +13,8 @@ class Bunker < ActiveRecord::Base
13
13
  end
14
14
 
15
15
  def alert_president
16
- alert_staff
17
16
  SecretService.stand_down
18
- President.alert
17
+ alert_staff || go_crazy
19
18
  end
20
19
  end
21
20
  ```
@@ -23,38 +22,55 @@ end
23
22
  And this is what CDD thinks of it:
24
23
 
25
24
  ``` ruby
26
-
27
25
  describe Bunker do
28
26
  it { should validate_secure_of :password }
29
27
  it { should validate_protected_of :location }
30
-
31
28
  describe "#alert_staff" do
32
29
  let(:obj) { described_class.new }
30
+ subject { obj.alert_staff }
33
31
  before do
34
32
  allow(Staff).to receive :alert_all
35
- obj.alert_staff
36
33
  end
37
34
  it "calls Staff.alert_all" do
35
+ subject
38
36
  expect(Staff).to have_received :alert_all
39
37
  end
40
38
  end
41
-
42
39
  describe "#alert_president" do
43
40
  let(:obj) { described_class.new }
41
+ subject { obj.alert_president }
44
42
  before do
45
- allow(obj).to receive :alert_staff
46
43
  allow(SecretService).to receive :stand_down
47
- allow(President).to receive :alert
48
- obj.alert_president
49
- end
50
- it "calls #alert_staff" do
51
- expect(obj).to have_received :alert_staff
52
44
  end
53
45
  it "calls SecretService.stand_down" do
46
+ subject
54
47
  expect(SecretService).to have_received :stand_down
55
48
  end
56
- it "calls President.alert" do
57
- expect(President).to have_received :alert
49
+ describe "#alert_staff is truthy" do
50
+ before do
51
+ allow(obj).to receive(:alert_staff).and_return('alert_staff')
52
+ allow(obj).to receive(:go_crazy)
53
+ end
54
+ it "returns #alert_staff" do
55
+ expect(subject).to eq 'alert_staff'
56
+ end
57
+ it "doesn't call #go_crazy" do
58
+ subject
59
+ expect(obj).not_to have_received :go_crazy
60
+ end
61
+ end
62
+ describe "#alert_staff is falsey" do
63
+ before do
64
+ allow(obj).to receive(:alert_staff).and_return(false)
65
+ allow(obj).to receive(:go_crazy).and_return('go_crazy')
66
+ end
67
+ it "returns #go_crazy" do
68
+ expect(subject).to eq 'go_crazy'
69
+ end
70
+ it "calls #alert_staff" do
71
+ subject
72
+ expect(obj).to have_received :alert_staff
73
+ end
58
74
  end
59
75
  end
60
76
  end
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../../lib')
2
+
1
3
  require "bundler/gem_tasks"
4
+ require 'cucumber/rake/task'
5
+
6
+ Cucumber::Rake::Task.new
7
+
8
+ task default: :cucumber
@@ -24,4 +24,6 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency "rspec"
26
26
  spec.add_development_dependency "pry"
27
+ spec.add_development_dependency "cucumber"
28
+ spec.add_development_dependency "aruba"
27
29
  end
@@ -0,0 +1,113 @@
1
+ Feature: Creates awesome specs
2
+ Scenario: creating shoulda_matchers
3
+ Given a file named "my_feature.rb" with:
4
+ """ruby
5
+ class Lolcat < ActiveRecord::Base
6
+ validate :cuteness, presence: true
7
+ end
8
+ """
9
+ When I run `cdd my_feature.rb`
10
+ Then the exit status should be 0
11
+ And the output should contain:
12
+ """ruby
13
+ describe Lolcat do
14
+ it { should validate_presence_of :cuteness }
15
+ end
16
+ """
17
+
18
+ Scenario: instance methods that call constants
19
+ Given a file named "my_feature.rb" with:
20
+ """ruby
21
+ class Lolcat
22
+ def i_call_things
23
+ CentralBureaucracy.file_report
24
+ end
25
+ end
26
+ """
27
+ When I run `cdd my_feature.rb`
28
+ Then the exit status should be 0
29
+ And the output should contain:
30
+ """ruby
31
+ describe "#i_call_things" do
32
+ let(:obj) { described_class.new }
33
+ subject { obj.i_call_things }
34
+ before do
35
+ allow(CentralBureaucracy).to receive :file_report
36
+ end
37
+ it "calls CentralBureaucracy.file_report" do
38
+ subject
39
+ expect(CentralBureaucracy).to have_received :file_report
40
+ end
41
+ end
42
+ """
43
+
44
+ Scenario: instance methods that call instance methods
45
+ Given a file named "my_feature.rb" with:
46
+ """ruby
47
+ class Lolcat
48
+ def i_call_instance_methods
49
+ meth
50
+ end
51
+ end
52
+ """
53
+ When I run `cdd my_feature.rb`
54
+ Then the exit status should be 0
55
+ And the output should contain:
56
+ """ruby
57
+ describe "#i_call_instance_methods" do
58
+ let(:obj) { described_class.new }
59
+ subject { obj.i_call_instance_methods }
60
+ before do
61
+ allow(obj).to receive :meth
62
+ end
63
+ it "calls #meth" do
64
+ subject
65
+ expect(obj).to have_received :meth
66
+ end
67
+ end
68
+ """
69
+
70
+ Scenario: boolean or
71
+ Given a file named "my_feature.rb" with:
72
+ """ruby
73
+ class Yolounicorn
74
+ def dilemma
75
+ should_i_stay || should_i_go
76
+ end
77
+ end
78
+ """
79
+ When I run `cdd my_feature.rb`
80
+ Then the exit status should be 0
81
+ And the output should contain:
82
+ """ruby
83
+ describe "#dilemma" do
84
+ let(:obj) { described_class.new }
85
+ subject { obj.dilemma }
86
+ describe "#should_i_stay is truthy" do
87
+ before do
88
+ allow(obj).to receive(:should_i_stay).and_return('should_i_stay')
89
+ allow(obj).to receive(:should_i_go)
90
+ end
91
+ it "returns #should_i_stay" do
92
+ expect(subject).to eq 'should_i_stay'
93
+ end
94
+ it "doesn't call #should_i_go" do
95
+ subject
96
+ expect(obj).not_to have_received :should_i_go
97
+ end
98
+ end
99
+ describe "#should_i_stay is falsey" do
100
+ before do
101
+ allow(obj).to receive(:should_i_stay).and_return(false)
102
+ allow(obj).to receive(:should_i_go).and_return('should_i_go')
103
+ end
104
+ it "returns #should_i_go" do
105
+ expect(subject).to eq 'should_i_go'
106
+ end
107
+ it "calls #should_i_stay" do
108
+ subject
109
+ expect(obj).to have_received :should_i_stay
110
+ end
111
+ end
112
+ end
113
+ """
@@ -0,0 +1 @@
1
+ require 'aruba/cucumber'
@@ -25,6 +25,7 @@ module CodeDrivenDevelopment
25
25
  Rule::InstanceMethod,
26
26
  Rule::ConstantMethodCall,
27
27
  Rule::InstanceMethodCall,
28
+ Rule::BooleanOr,
28
29
  default: Rule::Default
29
30
  )
30
31
  end
@@ -18,7 +18,7 @@ module CodeDrivenDevelopment
18
18
  private
19
19
 
20
20
  def current_indentation
21
- "\t" * @nesting
21
+ " " * @nesting * 2
22
22
  end
23
23
  end
24
24
  end
@@ -0,0 +1,61 @@
1
+ module CodeDrivenDevelopment
2
+ module Rule
3
+ class BooleanOr < AbstractRule
4
+ def capable?
5
+ code.sexp_type == :or &&
6
+ left.sexp_type == :call &&
7
+ right.sexp_type == :call
8
+ end
9
+
10
+ def test
11
+ left_is_true_context = TestComponent::Context.new(%Q("##{left_method_name} is truthy"))
12
+ right_is_true_context = TestComponent::Context.new(%Q("##{left_method_name} is falsey"))
13
+
14
+ left_is_true_context.befores << "allow(obj).to receive(:#{left_method_name}).and_return('#{left_method_name}')"
15
+ left_is_true_context.befores << "allow(obj).to receive(:#{right_method_name})"
16
+
17
+ left_is_true_context << TestComponent::Test.new("returns ##{left_method_name}", [
18
+ "expect(subject).to eq '#{left_method_name}'"
19
+ ])
20
+
21
+ left_is_true_context << TestComponent::Test.new("doesn't call ##{right_method_name}", [
22
+ "subject",
23
+ "expect(obj).not_to have_received :#{right_method_name}"
24
+ ])
25
+
26
+ right_is_true_context.befores << "allow(obj).to receive(:#{left_method_name}).and_return(false)"
27
+ right_is_true_context.befores << "allow(obj).to receive(:#{right_method_name}).and_return('#{right_method_name}')"
28
+
29
+ right_is_true_context << TestComponent::Test.new("returns ##{right_method_name}", [
30
+ "expect(subject).to eq '#{right_method_name}'"
31
+ ])
32
+
33
+ right_is_true_context << TestComponent::Test.new("calls ##{left_method_name}", [
34
+ "subject",
35
+ "expect(obj).to have_received :#{left_method_name}"
36
+ ])
37
+
38
+ test_context << left_is_true_context
39
+ test_context << right_is_true_context
40
+ end
41
+
42
+ private
43
+
44
+ def left
45
+ code[1]
46
+ end
47
+
48
+ def left_method_name
49
+ left[2]
50
+ end
51
+
52
+ def right
53
+ code[2]
54
+ end
55
+
56
+ def right_method_name
57
+ right[2]
58
+ end
59
+ end
60
+ end
61
+ end
@@ -9,7 +9,10 @@ module CodeDrivenDevelopment
9
9
 
10
10
  def test
11
11
  test_context.befores << "allow(#{receiver_value}).to receive :#{method_name}"
12
- body = ["expect(#{receiver_value}).to have_received :#{method_name}"]
12
+ body = [
13
+ "subject",
14
+ "expect(#{receiver_value}).to have_received :#{method_name}"
15
+ ]
13
16
  test_context << TestComponent::Test.new("calls #{receiver_value}.#{method_name}", body)
14
17
  end
15
18
 
@@ -11,7 +11,7 @@ module CodeDrivenDevelopment
11
11
  test_context << new_context
12
12
 
13
13
  # Do this last so that the method invocation is the last line in the before.
14
- new_context.befores << "obj.#{method_name}"
14
+ new_context.subject = "obj.#{method_name}"
15
15
  new_context.lets << TestComponent::Let.new(:obj, "described_class.new")
16
16
  end
17
17
 
@@ -9,7 +9,10 @@ module CodeDrivenDevelopment
9
9
 
10
10
  def test
11
11
  test_context.befores << "allow(#{receiver_value}).to receive :#{method_name}"
12
- body = ["expect(#{receiver_value}).to have_received :#{method_name}"]
12
+ body = [
13
+ "subject",
14
+ "expect(#{receiver_value}).to have_received :#{method_name}"
15
+ ]
13
16
  test_context << TestComponent::Test.new("calls ##{method_name}", body)
14
17
  end
15
18
 
@@ -1,24 +1,26 @@
1
1
  module CodeDrivenDevelopment
2
2
  module TestComponent
3
3
  class Context
4
- def initialize(description = nil, befores = [], tests = [], lets = [])
5
- @description, @befores, @tests, @lets = description, befores, tests, lets
4
+ def initialize(description = nil, befores = [], tests = [], lets = [], subject = nil)
5
+ @description, @befores, @tests, @lets, @subject = description, befores, tests, lets, subject
6
6
  end
7
7
 
8
8
  attr_reader :tests, :befores, :lets
9
- attr_accessor :description
9
+ attr_accessor :description, :subject
10
10
 
11
11
  def << child
12
12
  @tests << child
13
13
  end
14
14
 
15
15
  def indented_output io
16
- io << ""
17
16
  io << "describe #@description do"
18
17
  io.indented do
19
18
  lets.each do |let|
20
19
  let.indented_output(io)
21
20
  end
21
+ if subject
22
+ io << "subject { #{subject} }"
23
+ end
22
24
  if befores.any?
23
25
  io << "before do"
24
26
  io.indented do
@@ -1,3 +1,3 @@
1
1
  module CodeDrivenDevelopment
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -15,6 +15,7 @@ require "code_driven_development/rule/set"
15
15
  require "code_driven_development/rule/constant_method_call"
16
16
  require "code_driven_development/rule/instance_method_call"
17
17
  require "code_driven_development/rule/default"
18
+ require "code_driven_development/rule/boolean_or"
18
19
  require "code_driven_development/rule/class"
19
20
  require "code_driven_development/rule/validation"
20
21
  require "code_driven_development/rule/instance_method"
data/samples/president.rb CHANGED
@@ -7,8 +7,7 @@ class Bunker < ActiveRecord::Base
7
7
  end
8
8
 
9
9
  def alert_president
10
- alert_staff
11
10
  SecretService.stand_down
12
- President.alert
11
+ alert_staff || go_crazy
13
12
  end
14
13
  end
@@ -0,0 +1,54 @@
1
+ -
2
+ title: creates shoulda_matchers
3
+ input: |
4
+ class Lolcat < ActiveRecord::Base
5
+ validate :cuteness, presence: true
6
+ end
7
+ output: |
8
+ describe Lolcat do
9
+ it { should validate_presence_of :cuteness }
10
+ end
11
+ -
12
+ title: instance methods that call constants
13
+ input: |
14
+ class Lolcat
15
+ def i_call_things
16
+ CentralBureaucracy.file_report
17
+ end
18
+ end
19
+ output: |
20
+ describe Lolcat do
21
+
22
+ describe "#i_call_things" do
23
+ let(:obj) { described_class.new }
24
+ before do
25
+ allow(CentralBureaucracy).to receive :file_report
26
+ obj.i_call_things
27
+ end
28
+ it "calls CentralBureaucracy.file_report" do
29
+ expect(CentralBureaucracy).to have_received :file_report
30
+ end
31
+ end
32
+ end
33
+ -
34
+ title: instance methods that call instance methods
35
+ input: |
36
+ class Lolcat
37
+ def i_call_instance_methods
38
+ meth
39
+ end
40
+ end
41
+ output: |
42
+ describe Lolcat do
43
+
44
+ describe "#i_call_instance_methods" do
45
+ let(:obj) { described_class.new }
46
+ before do
47
+ allow(obj).to receive :meth
48
+ obj.i_call_instance_methods
49
+ end
50
+ it "calls #meth" do
51
+ expect(obj).to have_received :meth
52
+ end
53
+ end
54
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,5 @@
1
+ require 'yaml'
1
2
  require_relative '../lib/code_driven_development'
2
- require_relative 'support/have_consecutive_lines_matching_matcher'
3
3
 
4
4
  RSpec.configure do |config|
5
5
  config.expect_with :rspec do |c|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code_driven_development
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Finnie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-03 00:00:00.000000000 Z
11
+ date: 2014-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby_parser
@@ -80,6 +80,34 @@ dependencies:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: cucumber
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: aruba
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
83
111
  description: Automatically generate stubby tests from your implementation.
84
112
  email:
85
113
  - dan@danfinnie.com
@@ -96,10 +124,13 @@ files:
96
124
  - Rakefile
97
125
  - bin/cdd
98
126
  - code_driven_development.gemspec
127
+ - features/my_feature.feature
128
+ - features/support/aruba.rb
99
129
  - lib/code_driven_development.rb
100
130
  - lib/code_driven_development/code_driven_development.rb
101
131
  - lib/code_driven_development/indented_output.rb
102
132
  - lib/code_driven_development/rule/abstract_rule.rb
133
+ - lib/code_driven_development/rule/boolean_or.rb
103
134
  - lib/code_driven_development/rule/class.rb
104
135
  - lib/code_driven_development/rule/constant_method_call.rb
105
136
  - lib/code_driven_development/rule/default.rb
@@ -114,9 +145,8 @@ files:
114
145
  - lib/code_driven_development/test_component/test.rb
115
146
  - lib/code_driven_development/version.rb
116
147
  - samples/president.rb
117
- - spec/my_spec.rb
148
+ - spec/samples/lone_sample.yaml
118
149
  - spec/spec_helper.rb
119
- - spec/support/have_consecutive_lines_matching_matcher.rb
120
150
  homepage: https://github.com/danfinnie/code-driven-development
121
151
  licenses:
122
152
  - MIT
@@ -143,6 +173,7 @@ specification_version: 4
143
173
  summary: Ever see a test and think, "wow, this test cares a lot about the exact abstract
144
174
  syntax tree of the code?" CDD aims to generate tests like that.
145
175
  test_files:
146
- - spec/my_spec.rb
176
+ - features/my_feature.feature
177
+ - features/support/aruba.rb
178
+ - spec/samples/lone_sample.yaml
147
179
  - spec/spec_helper.rb
148
- - spec/support/have_consecutive_lines_matching_matcher.rb
data/spec/my_spec.rb DELETED
@@ -1,72 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe CodeDrivenDevelopment::CodeDrivenDevelopment do
4
- before do
5
- implementation = <<-EOT
6
- class Lolcat < ActiveRecord::Base
7
- validate :cuteness, presence: true
8
-
9
- def i_call_things
10
- CentralBureaucracy.file_report
11
- end
12
-
13
- def i_call_instance_methods
14
- meth
15
- end
16
-
17
- def weigh_options
18
- should_i_stay || should_i_go
19
- end
20
- end
21
- EOT
22
-
23
- @test = CodeDrivenDevelopment::CodeDrivenDevelopment.new(implementation).test_code
24
- end
25
-
26
- it "puts the model name in the describe description" do
27
- expect(@test).to match /^describe Lolcat do/
28
- end
29
-
30
- it "includes shoulda-matchers for simple validations" do
31
- expect(@test).to match /^\tit.*should.*validate_presence_of.*:cuteness/
32
- end
33
-
34
- it "stubs out method calls to constants" do
35
- expect(@test).to have_consecutive_lines_matching [
36
- /^\tdescribe.*"#i_call_things"/,
37
- /^\t\tbefore/,
38
- /^\t\t\tallow.CentralBureaucracy..to.*receive.*:file_report/,
39
- /^\t\t\tobj.i_call_things/,
40
- /^\t\tit.*calls Central.*do/,
41
- /^\t\t\texpect.CentralBureaucracy..to.*have_received.*:file_report/
42
- ]
43
- end
44
-
45
- it "stubs out instance method calls" do
46
- expect(@test).to have_consecutive_lines_matching [
47
- /^\tdescribe.*"#i_call_instance_methods"/,
48
- /^\t\tlet.:obj.*described_class.new/,
49
- /^\t\tbefore/,
50
- /^\t\t\tallow.obj..to.*receive.*:meth/,
51
- /^\t\t\tobj.i_call_instance_methods/,
52
- /^\t\tit.*calls #meth.*do/,
53
- /^\t\t\texpect.obj..to.*have_received.*:meth/
54
- ]
55
- end
56
-
57
- it "handles ORs with aplomb" do
58
- expect(@test).to have_consecutive_lines_matching [
59
- /^\tdescribe.*"#weigh_options"/,
60
- /^\t\tlet.:obj.*described_class.new/,
61
- /^\t\tbefore/,
62
- /^\t\t\tallow.obj..to.*receive.*:should_i_stay/,
63
- /^\t\t\tallow.obj..to.*receive.*:should_i_go/,
64
- /^\t\tcontext.*when.*should_i_stay.*truthy/,
65
- /^\t\tbefore do/,
66
- /^\t\t\t
67
- /^\t\t\tobj.weigh_options/,
68
- /^\t\tit.*calls #meth.*do/,
69
- /^\t\t\texpect.obj..to.*have_received.*:meth/
70
- ]
71
- end
72
- end
@@ -1,29 +0,0 @@
1
- RSpec::Matchers.define :have_consecutive_lines_matching do |*regexen|
2
- def compute_match(string, regexen)
3
- if regexen.empty?
4
- return [true]
5
- end
6
-
7
- regex = regexen.shift
8
- m = string.match(regex)
9
- if m
10
- remaining = m.post_match
11
- newline_i = remaining.index("\n")+1
12
- remaining = remaining[newline_i..-1]
13
- compute_match(remaining, regexen)
14
- else
15
- return [false, regex, string]
16
- end
17
- end
18
-
19
- match do |actual|
20
- compute_match(actual, regexen.flatten).shift
21
- end
22
-
23
- failure_message_for_should do |actual|
24
- _, failed_regex, failed_string = compute_match(actual, regexen.flatten)
25
- "expected #{failed_regex.inspect} to match #{failed_string.inspect}"
26
- end
27
-
28
- diffable
29
- end