approvals 0.0.22 → 0.0.24

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: 6f444a0aa1c3b1b8adeade0729913ffd0bc77af0
4
- data.tar.gz: fcb304998044a0f34fdcf339d3bac514e6175529
3
+ metadata.gz: 18211b4ae23de30297af8004404da5497abc99b9
4
+ data.tar.gz: 8f4ed09ce1ad7a43719049363969dc3dcd3a5158
5
5
  SHA512:
6
- metadata.gz: 0425fc7fab8349a9d762e8f134feebeba3d49c632f2bc3e4dc09df1b35041526acf86a6eda2f98b44b6443c968c2e32778741d984e73632124195f98c666f1ee
7
- data.tar.gz: 503eef74aa5ed03cf9591ca43dc771bfc5fde4c5fb2d57bd1823ea7dfab4cbcbd95bebeba4cd1cb448b8fea32bf8bc4909b206fa1934b7eab2c8906170729dfd
6
+ metadata.gz: 0d093bc47d069b7a70562e71cbcc5588b38cf37a5a8320f1e7df33b2834d27da8644633ccfafd9ac6e09f796257bd2ab8d1e6895c122d4d0183d44d95e394d08
7
+ data.tar.gz: 64faeb4c33be84e307bc9e27e05476fbf0cb979c702a1480d1885c54d4bd984f832074fe6f2cda179f67b648a8a85475f1e0adfe25a40450c8d5eaeb64d2da54
data/.gitignore CHANGED
@@ -5,3 +5,5 @@ pkg/*
5
5
  *.received.txt
6
6
  .approvals
7
7
  tmp/
8
+
9
+ ext/Rakefile
@@ -5,6 +5,11 @@ rvm:
5
5
  - 2.0.0
6
6
  - 2.1.0
7
7
  - ruby-head
8
- - rbx-2
8
+ - rbx
9
+ matrix:
10
+ allow_failures:
11
+ - rvm: rbx
12
+ before_install:
13
+ - gem update bundler
9
14
  script: bundle exec rspec spec
10
15
  cache: bundler
data/README.md CHANGED
@@ -23,8 +23,8 @@ which Llewellyn Falco is interviewed about approvals.
23
23
  ## Configuration
24
24
 
25
25
  ```ruby
26
- Approvals.configure do |c|
27
- c.approvals_path = 'output/goes/here/'
26
+ Approvals.configure do |config|
27
+ config.approvals_path = 'output/goes/here/'
28
28
  end
29
29
  ```
30
30
 
@@ -42,18 +42,43 @@ Approvals.verify(your_subject, :format => :json)
42
42
 
43
43
  This will raise an `ApprovalError` in the case of a failure.
44
44
 
45
- The default writer uses the `:to_s` method on the subject will be used to generate the output for
46
- the `received` file. For custom complex objects you will need to override
47
- `:to_s` to get helpful output, rather than the default:
48
-
49
- #<Object:0x0000010105ea40> # or whatever the object id is
50
-
51
45
  The first time the approval is run, a file will be created with the contents of the subject of your approval:
52
46
 
53
47
  the_name_of_the_approval.received.txt # or .json, .html, .xml as appropriate
54
48
 
55
49
  Since you have not yet approved anything, the `*.approved` file does not exist, and the comparison will fail.
56
50
 
51
+ ### Customizing formatted output
52
+
53
+ The default writer uses the `:to_s` method on the subject to generate the output for the received file.
54
+ For custom complex objects you will need to provide a custom writer to get helpful output, rather than the default:
55
+
56
+ #<Object:0x0000010105ea40> # or whatever the object id is
57
+
58
+ Create a custom writer class somewhere accessible to your test:
59
+
60
+ ```
61
+ class MyCustomWriter < Approvals::Writers::TextWriter
62
+ def format(data)
63
+ # Custom data formatting here
64
+ end
65
+
66
+ def filter(data)
67
+ # Custom data filtering here
68
+ end
69
+ end
70
+ ```
71
+
72
+ In your test, use a string to reference your custom class:
73
+
74
+ ```
75
+ it "verifies a complex object" do
76
+ Approvals.verify hello, :format => "MyCustomWriter"
77
+ end
78
+ ```
79
+
80
+ Define and use different custom writers as needed!
81
+
57
82
  ## CLI
58
83
 
59
84
  The gem comes with a command-line tool that makes it easier to manage the
@@ -115,17 +140,17 @@ spec/fixtures/approvals/
115
140
  You can override this:
116
141
 
117
142
  ```ruby
118
- RSpec.configure do |c|
119
- c.approvals_path = 'some/other/path'
143
+ RSpec.configure do |config|
144
+ config.approvals_path = 'some/other/path'
120
145
  end
121
146
  ```
122
147
 
123
148
  The basic format of the approval is modeled after RSpec's `it`:
124
149
 
125
150
  ```ruby
126
- it "works" do
151
+ it 'works' do
127
152
  verify do
128
- "this is the the thing you want to verify"
153
+ 'this is the the thing you want to verify'
129
154
  end
130
155
  end
131
156
  ```
@@ -135,21 +160,21 @@ end
135
160
  When using RSpec, the namer is set for you, using the example's `full_description`.
136
161
 
137
162
  ```ruby
138
- Approvals.verify(thing, :name => "the name of your test")
163
+ Approvals.verify(thing, :name => 'the name of your test')
139
164
  ```
140
165
 
141
166
  ### Formatting
142
167
 
143
168
  You can pass a format for your output before it gets written to the file.
144
- At the moment, only text, xml, html, and json are supported.
169
+ At the moment, only text, xml, html, and json are supported, while text is the default.
145
170
 
146
171
  Simply add a `:format => :text`, `:format => :xml`, `:format => :html`, or `:format => :json` option to the example:
147
172
 
148
173
  ```ruby
149
- page = "<html><head></head><body><h1>ZOMG</h1></body></html>"
174
+ page = '<html><head></head><body><h1>ZOMG</h1></body></html>'
150
175
  Approvals.verify page, :format => :html
151
176
 
152
- data = "{\"beverage\":\"coffee\"}"
177
+ data = '{\'beverage\':\'coffee\'}'
153
178
  Approvals.verify data, :format => :json
154
179
  ```
155
180
 
@@ -157,19 +182,27 @@ In RSpec, it looks like this:
157
182
 
158
183
  ```ruby
159
184
  verify :format => :html do
160
- "<html><head></head><body><h1>ZOMG</h1></body></html>"
185
+ '<html><head></head><body><h1>ZOMG</h1></body></html>'
161
186
  end
162
187
 
163
188
  verify :format => :json do
164
- "{\"beverage\":\"coffee\"}"
189
+ '{\'beverage\':\'coffee\'}'
190
+ end
191
+ ```
192
+
193
+ If you like you could also change the default format globally with:
194
+
195
+ ```ruby
196
+ RSpec.configure do |config|
197
+ config.approvals_default_format = :json # or :xml, :html
165
198
  end
166
199
  ```
167
200
 
168
201
  ### Exclude dynamically changed values from json
169
202
 
170
203
  ```ruby
171
- Approvals.configure do |c|
172
- c.excluded_json_keys = {
204
+ Approvals.configure do |config|
205
+ config.excluded_json_keys = {
173
206
  :id =>/(\A|_)id$/,
174
207
  :date => /_at$/
175
208
  }
@@ -9,9 +9,9 @@ Gem::Specification.new do |s|
9
9
  s.licenses = ['MIT']
10
10
  s.authors = ["Katrina Owen"]
11
11
  s.email = ["katrina.owen@gmail.com"]
12
- s.homepage = ""
12
+ s.homepage = "https://github.com/kytrinyx/approvals"
13
13
  s.summary = %q{Approval Tests for Ruby}
14
- s.description = %q{Approval Tests for Ruby}
14
+ s.description = %q{A library to make it easier to do golden-master style testing in Ruby}
15
15
 
16
16
  s.rubyforge_project = "approvals"
17
17
 
@@ -19,9 +19,11 @@ Gem::Specification.new do |s|
19
19
  s.test_files = `git ls-files -- {spec}/*`.split("\n")
20
20
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
21
  s.require_paths = ["lib"]
22
+ s.extensions << 'ext/mkrf_conf.rb'
22
23
 
23
24
  s.add_development_dependency 'rspec', '~> 3.1'
24
- s.add_development_dependency 'json', '~> 1.8'
25
25
  s.add_dependency 'thor', '~> 0.18'
26
26
  s.add_dependency 'nokogiri', '~> 1.6'
27
+ # We also depend on the json gem, but the version we need is
28
+ # Ruby-version-specific. See `ext/mkrf_conf.rb`.
27
29
  end
@@ -0,0 +1,22 @@
1
+ require 'rubygems/dependency_installer'
2
+
3
+ # This is how we can depend on a different version of the same gem for
4
+ # different Ruby versions.
5
+ # See https://en.wikibooks.org/wiki/Ruby_Programming/RubyGems
6
+
7
+ installer = Gem::DependencyInstaller.new
8
+
9
+ begin
10
+ if RUBY_VERSION >= '2.0'
11
+ installer.install 'json', '~> 2.0'
12
+ else
13
+ installer.install 'json', '~> 1.8'
14
+ end
15
+ rescue
16
+ exit(1)
17
+ end
18
+
19
+ # Write fake Rakefile for rake since Makefile isn't used
20
+ File.open(File.join(File.dirname(__FILE__), 'Rakefile'), 'w') do |f|
21
+ f.write("task :default\n")
22
+ end
@@ -13,6 +13,7 @@ require 'approvals/executable'
13
13
  require 'approvals/reporters'
14
14
  require 'approvals/filter'
15
15
  require 'approvals/writer'
16
+ require 'approvals/verifier'
16
17
  require 'approvals/namers/default_namer'
17
18
 
18
19
  module Approvals
@@ -19,9 +19,9 @@ module Approvals
19
19
  # Add a Proc that tests if subject is a kind of format
20
20
  IDENTITIES = {
21
21
  hash: Proc.new(){|subject|subject.respond_to? :each_pair},
22
- array: Proc.new(){|subject|subject.respond_to? :each_with_index},
22
+ array: Proc.new(){|subject|subject.respond_to? :each_with_index},
23
23
  }
24
-
24
+
25
25
  def identify_format
26
26
  IDENTITIES.each_pair do |format, id_test|
27
27
  return format if id_test.call(subject)
@@ -34,6 +34,10 @@ module Approvals
34
34
  @writer ||= Writer.for(@format)
35
35
  end
36
36
 
37
+ def verifier
38
+ @verifier ||= Verifier.for(@format)
39
+ end
40
+
37
41
  def verify
38
42
  unless File.exist?(namer.output_dir)
39
43
  FileUtils.mkdir_p(namer.output_dir)
@@ -63,6 +67,10 @@ module Approvals
63
67
  BINARY_FORMATS = [:binary]
64
68
 
65
69
  def received_matches?
70
+ return verifier
71
+ .new(received_path, approved_path)
72
+ .verify if verifier
73
+
66
74
  if BINARY_FORMATS.include?(@format) # Read without ERB
67
75
  IO.read(received_path).chomp == IO.read(approved_path).chomp
68
76
  else
@@ -16,18 +16,18 @@ module Approvals
16
16
  end
17
17
 
18
18
  def censored value, key=nil
19
- case value
20
- when Array
21
- value.map { |item| censored(item) }
22
- when Hash
23
- Hash[value.map { |inner_key, inner_value| [inner_key, censored(inner_value, inner_key)] }]
19
+ if value.nil?
20
+ nil
21
+ elsif key && placeholder_for(key)
22
+ "<#{placeholder_for(key)}>"
24
23
  else
25
- if value.nil?
26
- nil
27
- elsif key && placeholder_for(key)
28
- "<#{placeholder_for(key)}>"
29
- else
30
- value
24
+ case value
25
+ when Array
26
+ value.map { |item| censored(item) }
27
+ when Hash
28
+ Hash[value.map { |inner_key, inner_value| [inner_key, censored(inner_value, inner_key)] }]
29
+ else
30
+ value
31
31
  end
32
32
  end
33
33
  end
@@ -0,0 +1,15 @@
1
+ require 'approvals/verifiers/json_verifier'
2
+
3
+ module Approvals
4
+ module Verifier
5
+ REGISTRY = {
6
+ json: Verifiers::JsonVerifier,
7
+ }
8
+
9
+ class << self
10
+ def for(format)
11
+ REGISTRY[format]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Approvals
2
+ module Verifiers
3
+ class JsonVerifier
4
+ def initialize(received_path, approved_path)
5
+ self.received_path = received_path
6
+ self.approved_path = approved_path
7
+ end
8
+
9
+ def verify
10
+ approved == received
11
+ end
12
+
13
+ private
14
+
15
+ attr_accessor :approved_path, :received_path
16
+
17
+ def approved
18
+ JSON.parse(File.read(approved_path))
19
+ end
20
+
21
+ def received
22
+ JSON.parse(File.read(received_path))
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module Approvals
2
- VERSION = '0.0.22'
2
+ VERSION = '0.0.24'
3
3
  end
@@ -16,15 +16,21 @@ module Approvals
16
16
  html: Writers::HtmlWriter.new,
17
17
  hash: Writers::HashWriter.new,
18
18
  array: Writers::ArrayWriter.new,
19
+ txt: Writers::TextWriter.new,
19
20
  }
20
21
 
21
22
 
22
23
  class << self
23
24
  def for(format)
24
- if REGISTRY.include?(format)
25
- REGISTRY[format]
26
- else
27
- TextWriter.new
25
+ begin
26
+ REGISTRY[format] || Object.const_get(format).new
27
+ rescue NameError => e
28
+ error = ApprovalError.new(
29
+ "Approval Error: #{ e }. Please define a custom writer as outlined"\
30
+ " in README section 'Customizing formatted output': "\
31
+ "https://github.com/kytrinyx/approvals#customizing-formatted-output"
32
+ )
33
+ raise error
28
34
  end
29
35
  end
30
36
  end
@@ -51,6 +51,32 @@ describe Approvals do
51
51
  Approvals.verify hello, :namer => namer
52
52
  end
53
53
 
54
+ context "custom writer" do
55
+ let(:hello) { Object.new }
56
+
57
+ class MyCustomWriter < Approvals::Writers::TextWriter
58
+ def format(data)
59
+ filter(data)
60
+ end
61
+
62
+ def filter(data)
63
+ data.to_s.chars.reject {|c| c =~ /[a-zA-Z0-9]/}
64
+ end
65
+ end
66
+
67
+ it "verifies a complex object" do
68
+ Approvals.verify hello, :namer => namer, :format => "MyCustomWriter"
69
+ end
70
+
71
+ it "raises an error with an uninitialized custom writer class" do
72
+ expect{
73
+ Approvals.verify hello, :namer => namer, :format => "UninitializedWriter"
74
+ }.to raise_error.with_message(
75
+ /Please define a custom writer as outlined in README section 'Customizing formatted output':/
76
+ )
77
+ end
78
+ end
79
+
54
80
  it "verifies html" do
55
81
  html = <<-HTML
56
82
  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"><html><head><title>Approval</title></head><body><h1>An Approval</h1><p>It has a paragraph</p></body></html>
@@ -79,6 +105,11 @@ describe Approvals do
79
105
  Approvals.verify json, :format => :json, :namer => namer
80
106
  end
81
107
 
108
+ it "ignores whitespace differences in json" do
109
+ hash = { foo: {} }
110
+
111
+ Approvals.verify hash, :format => :json, :namer => namer
112
+ end
82
113
 
83
114
  it "verifies json and is newline agnostic" do
84
115
  json = '{"pet":{"species":"turtle","color":"green","name":"Anthony"}}'
@@ -74,6 +74,40 @@ describe Approvals::Filter do
74
74
  })
75
75
  end
76
76
 
77
+ it "filters array keys" do
78
+ filter = Approvals::Filter.new({foolist: /^foolist$/})
79
+ input = {
80
+ foo: 'bar124',
81
+ foolist: [{foo: 'bar 145', bar: 'foo'}, 'foobar'],
82
+ nonfoo: 'bar',
83
+ }
84
+
85
+ output = filter.apply(input)
86
+
87
+ expect(output).to eq({
88
+ foo: 'bar124',
89
+ foolist: '<foolist>',
90
+ nonfoo: 'bar',
91
+ })
92
+ end
93
+
94
+ it "filters hash keys" do
95
+ filter = Approvals::Filter.new({foohash: /^foohash$/})
96
+ input = {
97
+ foo: 'bar124',
98
+ foohash: {foo: 'bar 145', barlist: ['foo', 'bar']},
99
+ nonfoo: 'bar',
100
+ }
101
+
102
+ output = filter.apply(input)
103
+
104
+ expect(output).to eq({
105
+ foo: 'bar124',
106
+ foohash: '<foohash>',
107
+ nonfoo: 'bar',
108
+ })
109
+ end
110
+
77
111
  it "takes the last applicable filter" do
78
112
  filter = Approvals::Filter.new({foo: /^foo/, bar: /bar$/})
79
113
  input = {
@@ -0,0 +1,3 @@
1
+ {
2
+ "foo": "2017-01-01 00:00:00 +0100"
3
+ }
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Approvals::Verifiers::JsonVerifier do
4
+ subject(:instance) do
5
+ described_class.new(received_path, approved_path)
6
+ end
7
+
8
+ context "with same json content but different formatting" do
9
+ let(:received_path) do
10
+ "./spec/fixtures/json_approval_with_different_whitespace/received.json"
11
+ end
12
+ let(:approved_path) do
13
+ "./spec/fixtures/json_approval_with_different_whitespace/approved.json"
14
+ end
15
+
16
+ it "passes verification" do
17
+ expect(instance.verify).to be_truthy
18
+ end
19
+ end
20
+
21
+ context "with different json content" do
22
+ let(:received_path) do
23
+ "./spec/fixtures/json_approval_with_different_whitespace/received_different_content.json"
24
+ end
25
+ let(:approved_path) do
26
+ "./spec/fixtures/json_approval_with_different_whitespace/approved.json"
27
+ end
28
+
29
+ it "does not passe verification" do
30
+ expect(instance.verify).to be_falsy
31
+ end
32
+ end
33
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: approvals
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.22
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katrina Owen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-22 00:00:00.000000000 Z
11
+ date: 2018-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.1'
27
- - !ruby/object:Gem::Dependency
28
- name: json
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.8'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.8'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: thor
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,12 +52,13 @@ dependencies:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
54
  version: '1.6'
69
- description: Approval Tests for Ruby
55
+ description: A library to make it easier to do golden-master style testing in Ruby
70
56
  email:
71
57
  - katrina.owen@gmail.com
72
58
  executables:
73
59
  - approvals
74
- extensions: []
60
+ extensions:
61
+ - ext/mkrf_conf.rb
75
62
  extra_rdoc_files: []
76
63
  files:
77
64
  - ".gitignore"
@@ -83,6 +70,7 @@ files:
83
70
  - Rakefile
84
71
  - approvals.gemspec
85
72
  - bin/approvals
73
+ - ext/mkrf_conf.rb
86
74
  - lib/approvals.rb
87
75
  - lib/approvals/approval.rb
88
76
  - lib/approvals/cli.rb
@@ -112,6 +100,8 @@ files:
112
100
  - lib/approvals/rspec.rb
113
101
  - lib/approvals/scrubber.rb
114
102
  - lib/approvals/system_command.rb
103
+ - lib/approvals/verifier.rb
104
+ - lib/approvals/verifiers/json_verifier.rb
115
105
  - lib/approvals/version.rb
116
106
  - lib/approvals/writer.rb
117
107
  - lib/approvals/writers/array_writer.rb
@@ -127,6 +117,8 @@ files:
127
117
  - spec/executable_spec.rb
128
118
  - spec/extensions/rspec_approvals_spec.rb
129
119
  - spec/filter_spec.rb
120
+ - spec/fixtures/approvals/approvals_custom_writer_verifies_a_complex_object.approved.txt
121
+ - spec/fixtures/approvals/approvals_ignores_whitespace_differences_in_json.approved.json
130
122
  - spec/fixtures/approvals/approvals_passes_approved_files_through_erb.approved.txt
131
123
  - spec/fixtures/approvals/approvals_passes_the_received_files_through_erb.approved.txt
132
124
  - spec/fixtures/approvals/approvals_supports_excluded_keys_option_also_supports_an_array_of_hashes.approved.json
@@ -143,6 +135,7 @@ files:
143
135
  - spec/fixtures/approvals/approvals_verifies_html.approved.html
144
136
  - spec/fixtures/approvals/approvals_verifies_json.approved.json
145
137
  - spec/fixtures/approvals/approvals_verifies_json_and_is_newline_agnostic.approved.json
138
+ - spec/fixtures/approvals/approvals_verifies_json_with_a_time_object.approved.json
146
139
  - spec/fixtures/approvals/approvals_verifies_xml.approved.xml
147
140
  - spec/fixtures/approvals/verifications_a_string.approved.txt
148
141
  - spec/fixtures/approvals/verifies_a_complex_object.approved.txt
@@ -163,6 +156,9 @@ files:
163
156
  - spec/fixtures/approvals/verifies_html.approved.html
164
157
  - spec/fixtures/approvals/verifies_json.approved.json
165
158
  - spec/fixtures/approvals/verifies_xml.approved.xml
159
+ - spec/fixtures/json_approval_with_different_whitespace/approved.json
160
+ - spec/fixtures/json_approval_with_different_whitespace/received.json
161
+ - spec/fixtures/json_approval_with_different_whitespace/received_different_content.json
166
162
  - spec/fixtures/one.png
167
163
  - spec/fixtures/one.txt
168
164
  - spec/fixtures/two.png
@@ -180,7 +176,8 @@ files:
180
176
  - spec/scrubber_spec.rb
181
177
  - spec/spec_helper.rb
182
178
  - spec/system_command_spec.rb
183
- homepage: ''
179
+ - spec/verifiers/json_verifier_spec.rb
180
+ homepage: https://github.com/kytrinyx/approvals
184
181
  licenses:
185
182
  - MIT
186
183
  metadata: {}
@@ -200,9 +197,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
197
  version: '0'
201
198
  requirements: []
202
199
  rubyforge_project: approvals
203
- rubygems_version: 2.2.2
200
+ rubygems_version: 2.5.2
204
201
  signing_key:
205
202
  specification_version: 4
206
203
  summary: Approval Tests for Ruby
207
204
  test_files: []
208
- has_rdoc: