rspec-approvals 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rspec-approvals.gemspec
4
+ gemspec
data/License.txt ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2011 Katrina Owen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # RSpec Approvals
2
+
3
+ Approvals are based on the idea of the *_golden master_*.
4
+
5
+ You take a snapshot of an object, and then compare all future
6
+ versions of the object to the snapshot.
7
+
8
+ See [ApprovalTests](http://www.approvaltests.com) for videos and additional documentation about the general concept.
9
+
10
+ The original Approvals libraries for Java and C# were developed by Llewellyn Falco.
11
+
12
+
13
+ ## Configuration
14
+
15
+ The default location for the output files is
16
+
17
+ spec/approvals
18
+
19
+ You can change this using the configuration option
20
+
21
+ RSpec.configure do |c|
22
+ c.approvals_path = 'some/other/path'
23
+ end
24
+
25
+
26
+ ## Usage
27
+
28
+ The basic format of the approval is modeled after RSpec's `it`:
29
+
30
+ approve "something" do
31
+ "this is the received contents"
32
+ end
33
+
34
+
35
+ The `:to_s` method on the object will be used to generate the output for
36
+ the `*.received.txt` file. For custom objects you will need to override
37
+ the `:to_s` to get helpful output, rather than the default:
38
+
39
+ #<Object:0x0000010105ea40>
40
+
41
+ The first time the specs are run, two files will be created:
42
+
43
+ full_description_of_something.received.txt
44
+ full_description_of_something.approved.txt
45
+
46
+
47
+ Since you have not yet approved anything, the `*.approved.txt` file is
48
+ empty.
49
+
50
+ The contents of the two files are compared, and the approval will fail at this point.
51
+
52
+ ### Approving a spec
53
+
54
+ If the contents of the received file is to your liking, you can approve
55
+ the file by overwriting the approved file with the received file.
56
+
57
+ For an example who's full description is `My Spec`:
58
+
59
+ mv my_spec.received.txt my_spec.approved.txt
60
+
61
+ When you rerun the spec, it should now pass.
62
+
63
+ ### Formatters
64
+
65
+ You can specify a custom formatter when you run the specs.
66
+
67
+ E.g.
68
+
69
+ rspec --require /path/to/lib/rspec/approvals/formatters/opendiff_formatter.rb \
70
+ -f RSpec::Approvals::Formatters::OpendiffFormatter spec/
71
+
72
+ The OpendiffFormatter automatically launches opendiff for each failed
73
+ approval. It falls back on the ProgressFormatter for all non-approval
74
+ specs.
75
+
76
+ That's pretty unweildy, so I'm looking at options to add shortcuts for
77
+ this.
78
+
79
+
80
+
81
+ Copyright (c) 2011 Katrina Owen, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,80 @@
1
+ require 'rspec/expectations/errors'
2
+
3
+ module RSpec
4
+ module Approvals
5
+
6
+ class ReceivedDiffersError < RSpec::Expectations::ExpectationNotMetError; end
7
+
8
+ class Approval
9
+
10
+ def self.normalize(s)
11
+ s.gsub(/[\W]/, ' ').strip.squeeze(" ").gsub(' ', '_').downcase
12
+ end
13
+
14
+ def self.base_path(s)
15
+ Approvals.path + normalize(s)
16
+ end
17
+
18
+ attr_reader :location
19
+
20
+ def initialize(example, received = '')
21
+ @path = Approval.base_path(example.full_description)
22
+
23
+ example.options[:approval] = true
24
+ example.options[:approval_diff_paths] = {
25
+ :received => received_path,
26
+ :approved => approved_path,
27
+ }
28
+
29
+ write(:approved, '') unless File.exists?(approved_path)
30
+ write(:received, received)
31
+ end
32
+
33
+ def approved_path
34
+ "#{@path}.approved.txt"
35
+ end
36
+
37
+ def received_path
38
+ "#{@path}.received.txt"
39
+ end
40
+
41
+ def write(suffix, contents)
42
+ File.open("#{@path}.#{suffix}.txt", 'w') do |f|
43
+ f.write contents
44
+ end
45
+ end
46
+
47
+ def failure_message
48
+ <<-FAILURE_MESSAGE
49
+
50
+ Approval Failure:
51
+
52
+ The received contents did not match the approved contents.
53
+
54
+ Inspect the differences in the following files:
55
+ #{received_path}
56
+ #{approved_path}
57
+
58
+ If you like what you see in the *.received.txt file, you can approve it
59
+ like so:
60
+
61
+ mv #{received_path} #{approved_path}
62
+
63
+
64
+ FAILURE_MESSAGE
65
+ end
66
+
67
+ def location=(backtrace)
68
+ @location = [backtrace.first.gsub(Dir.pwd, '.')]
69
+ end
70
+
71
+ def verify
72
+ if FileUtils.cmp(received_path, approved_path)
73
+ File.unlink(received_path)
74
+ else
75
+ raise RSpec::Approvals::ReceivedDiffersError, failure_message, location
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,23 @@
1
+ require 'rspec/expectations/errors'
2
+
3
+ module RSpec
4
+ module Approvals
5
+ module DSL
6
+
7
+ def approve(description)
8
+
9
+ specify(description) do
10
+ approval = Approval.new(example, yield)
11
+
12
+ # We may be able to set file_path and
13
+ # line_number on example in the approval
14
+ # see RSpec::Core::Metadata::LocationKeys
15
+ approval.location = caller
16
+
17
+ approval.verify
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ require 'rspec/core/formatters/progress_formatter'
2
+
3
+ module RSpec
4
+ module Approvals
5
+ module Formatters
6
+
7
+ class OpendiffFormatter < RSpec::Core::Formatters::ProgressFormatter
8
+ def dump_failures
9
+ super
10
+ failed_examples.each do |example|
11
+ if example.options[:approval]
12
+ paths = example.options[:approval_diff_paths]
13
+ system("opendiff #{paths[:received]} #{paths[:approved]} &")
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ module RSpec
2
+ module Approvals
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+
2
+ require "rspec/approvals/version"
3
+ require "rspec/approvals/approval"
4
+ require "rspec/approvals/dsl"
5
+ require 'rspec/approvals/formatters/opendiff_formatter'
6
+
7
+
8
+ module RSpec
9
+ RSpec.configure do |c|
10
+ c.extend RSpec::Approvals::DSL
11
+ c.add_setting :approvals_path, :default => 'spec/approvals'
12
+ end
13
+
14
+ module Approvals
15
+
16
+ class << self
17
+ def initialize_approvals_path
18
+ FileUtils.makedirs(RSpec.configuration.approvals_path) unless Dir.exists?(RSpec.configuration.approvals_path)
19
+ end
20
+
21
+ def path
22
+ RSpec.configuration.approvals_path + "/"
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ RSpec::Approvals.initialize_approvals_path
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rspec/approvals/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rspec-approvals"
7
+ s.version = RSpec::Approvals::VERSION
8
+ s.authors = ["Katrina Owen"]
9
+ s.email = ["katrina.owen@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Approval Tests for Ruby}
12
+ s.description = %q{An RSpec extension that adds support for approvals. Based on the idea of the Golden Master.}
13
+
14
+ s.rubyforge_project = "rspec-approvals"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'rspec', '~> 2.6'
22
+ end
@@ -0,0 +1,157 @@
1
+ require 'spec_helper'
2
+
3
+ describe Approvals::Approval do
4
+ let(:description) { 'spec/approvals/fairy_dust_and_unicorns' }
5
+ let(:example) { stub('example', :full_description => 'fairy dust and unicorns').as_null_object }
6
+
7
+ describe "#normalize" do
8
+ it "downcases" do
9
+ Approvals::Approval.normalize("KTHXBYE").should eq("kthxbye")
10
+ end
11
+
12
+ it "replaces spaces with underscores" do
13
+ Approvals::Approval.normalize("the spec").should eq("the_spec")
14
+ end
15
+
16
+ it "leaves numbers alone" do
17
+ Approvals::Approval.normalize('a 2009 party').should eq("a_2009_party")
18
+ end
19
+
20
+ it "deletes funky characters" do
21
+ Approvals::Approval.normalize('the !@\#$%^&*(){}+| name').should eq("the_name")
22
+ end
23
+
24
+ it "collapses spaces before replacing with underscores" do
25
+ Approvals::Approval.normalize('omf g').should eq('omf_g')
26
+ end
27
+
28
+ it "deletes all sorts of spaces" do
29
+ name = <<-FUNKY_NAME
30
+
31
+ The::Class \t \r\n \fname
32
+ FUNKY_NAME
33
+ Approvals::Approval.normalize(name).should eq('the_class_name')
34
+ end
35
+ end
36
+
37
+ it "knows the approved_path" do
38
+ approval = Approvals::Approval.new(example)
39
+ approval.approved_path.should eq("#{description}.approved.txt")
40
+ end
41
+
42
+ it "knows the received path" do
43
+ approval = Approvals::Approval.new(example)
44
+ approval.received_path.should eq("#{description}.received.txt")
45
+ end
46
+
47
+ it "can set a location" do
48
+ Dir.stub(:pwd => 'the/path')
49
+ approval = Approvals::Approval.new(example)
50
+ approval.location = ['the/path/to/my/heart:9372 <is through my stomach>', 'bla bla bla']
51
+ approval.location.should eq(['./to/my/heart:9372 <is through my stomach>'])
52
+ end
53
+
54
+ context "approvals" do
55
+ before :each do
56
+ @approved_file = "#{description}.approved.txt"
57
+ @received_file = "#{description}.received.txt"
58
+ end
59
+
60
+ after :each do
61
+ File.delete(@approved_file) if File.exists?(@approved_file)
62
+ File.delete(@received_file) if File.exists?(@received_file)
63
+ end
64
+
65
+ describe "on the filesystem" do
66
+
67
+ it "writes the approved file if it doesn't exist" do
68
+ File.delete(@approved_file) if File.exists?(@approved_file)
69
+
70
+ Approvals::Approval.new(example)
71
+
72
+ File.exists?(@approved_file).should be_true
73
+ File.read(@approved_file).should eq('')
74
+ end
75
+
76
+ it "doesn't overwrite an existing approved file" do
77
+ File.open(@approved_file, 'w') do |f|
78
+ f.write "this doesn't get deleted"
79
+ end
80
+
81
+ Approvals::Approval.new(example)
82
+
83
+ File.exists?(@approved_file).should be_true
84
+ File.read(@approved_file).should eq("this doesn't get deleted")
85
+ end
86
+
87
+ it "writes the received contents to file" do
88
+ approval = Approvals::Approval.new(example, 'oooh, shiney!')
89
+
90
+ File.exists?(@received_file).should be_true
91
+ File.read(@received_file).should eq("oooh, shiney!")
92
+ end
93
+ end
94
+
95
+ describe "verification" do
96
+
97
+ context "with a match" do
98
+ before :each do
99
+ @approval = Approvals::Approval.new(example, 'xyz')
100
+ @approval.write(:approved, 'xyz')
101
+ end
102
+
103
+ it "does not raise an error" do
104
+ lambda { @approval.verify }.should_not raise_error(RSpec::Approvals::ReceivedDiffersError)
105
+ end
106
+
107
+ it "does not leave a received file" do
108
+ lambda { @approval.verify }.call
109
+ File.exists?(@approval.received_path).should be_false
110
+ end
111
+ end
112
+
113
+ context "with a mismatch" do
114
+ before :each do
115
+ @approval = Approvals::Approval.new(example, 'xyz')
116
+ @approval.write(:approved, 'abc')
117
+ end
118
+
119
+ it "raises an error" do
120
+ lambda { @approval.verify }.should raise_error(RSpec::Approvals::ReceivedDiffersError)
121
+ end
122
+
123
+ it "leaves a received file" do
124
+ begin
125
+ @approval.verify
126
+ rescue RSpec::Approvals::ReceivedDiffersError => e
127
+ # we want to land here and then move on
128
+ end
129
+ File.exists?(@approval.received_path).should be_true
130
+ end
131
+ end
132
+ end
133
+
134
+ it "fails magnificently" do
135
+ approval = Approvals::Approval.new(example, 'xyz')
136
+ message = <<-FAILURE_MESSAGE
137
+
138
+ Approval Failure:
139
+
140
+ The received contents did not match the approved contents.
141
+
142
+ Inspect the differences in the following files:
143
+ #{approval.received_path}
144
+ #{approval.approved_path}
145
+
146
+ If you like what you see in the *.received.txt file, you can approve it
147
+ like so:
148
+
149
+ mv #{approval.received_path} #{approval.approved_path}
150
+
151
+
152
+ FAILURE_MESSAGE
153
+
154
+ approval.failure_message.should eq(message)
155
+ end
156
+ end
157
+ end
@@ -0,0 +1 @@
1
+ {:universe=>{:side=>:dark, :other_side=>:light}, :force=>true}
@@ -0,0 +1 @@
1
+ We have, I fear, confused power with greatness.
@@ -0,0 +1 @@
1
+ ["abc", 123, ["cheese", "burger", "ribs", "steak", "bacon"]]
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe Approvals do
4
+
5
+ it "defaults the output dir to spec/approvals" do
6
+ RSpec.configuration.approvals_path.should == 'spec/approvals'
7
+ end
8
+
9
+ describe "initializing approval directory" do
10
+ it "does nothing if directory exists" do
11
+ RSpec.configuration.stub(:approvals_path).and_return 'xyz'
12
+ Dir.stub(:exists?).and_return true
13
+ FileUtils.should_not_receive(:makedirs).with 'xyz'
14
+
15
+ Approvals.initialize_approvals_path
16
+ end
17
+
18
+ it "creates directory if it is missing" do
19
+ RSpec.configuration.stub(:approvals_path).and_return 'abc'
20
+ Dir.stub(:exists?).and_return false
21
+ FileUtils.should_receive(:makedirs).with('abc')
22
+
23
+ Approvals.initialize_approvals_path
24
+ end
25
+ end
26
+
27
+ it "needs to be able to run with :filtered => true"
28
+
29
+ approve "a string" do
30
+ "We have, I fear, confused power with greatness."
31
+ end
32
+
33
+ approve "a hash" do
34
+ {
35
+ :universe => {
36
+ :side => :dark,
37
+ :other_side => :light
38
+ },
39
+ :force => true
40
+ }
41
+ end
42
+
43
+ approve "an array" do
44
+ [
45
+ "abc",
46
+ 123,
47
+ %w(cheese burger ribs steak bacon)
48
+ ]
49
+ end
50
+
51
+ approve "a complex object" do
52
+ hello = Object.new
53
+ def hello.to_s
54
+ "Hello, World!"
55
+ end
56
+
57
+ def hello.inspect
58
+ "<HelloWorld id:#{object_id}>"
59
+ end
60
+
61
+ hello # => output matches hello.to_s
62
+ end
63
+
64
+ end
@@ -0,0 +1,2 @@
1
+ require 'rspec/approvals'
2
+ include RSpec
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-approvals
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Katrina Owen
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-07-11 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 6
31
+ version: "2.6"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: An RSpec extension that adds support for approvals. Based on the idea of the Golden Master.
35
+ email:
36
+ - katrina.owen@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - License.txt
47
+ - README.md
48
+ - Rakefile
49
+ - lib/rspec/approvals.rb
50
+ - lib/rspec/approvals/approval.rb
51
+ - lib/rspec/approvals/dsl.rb
52
+ - lib/rspec/approvals/formatters/opendiff_formatter.rb
53
+ - lib/rspec/approvals/version.rb
54
+ - rspec-approvals.gemspec
55
+ - spec/approval_spec.rb
56
+ - spec/approvals/rspec_approvals_a_complex_object.approved.txt
57
+ - spec/approvals/rspec_approvals_a_hash.approved.txt
58
+ - spec/approvals/rspec_approvals_a_string.approved.txt
59
+ - spec/approvals/rspec_approvals_an_array.approved.txt
60
+ - spec/approvals_spec.rb
61
+ - spec/spec_helper.rb
62
+ has_rdoc: true
63
+ homepage: ""
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 0
86
+ version: "0"
87
+ requirements: []
88
+
89
+ rubyforge_project: rspec-approvals
90
+ rubygems_version: 1.3.7
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: Approval Tests for Ruby
94
+ test_files: []
95
+