clintegracon 0.6.1 → 0.7.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.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -2
  3. data/Gemfile.lock +23 -17
  4. data/Rakefile +5 -0
  5. data/clintegracon.gemspec +2 -3
  6. data/lib/CLIntegracon/adapter/bacon.rb +24 -11
  7. data/lib/CLIntegracon/diff.rb +21 -21
  8. data/lib/CLIntegracon/file_tree_spec.rb +78 -58
  9. data/lib/CLIntegracon/file_tree_spec_context.rb +101 -40
  10. data/lib/CLIntegracon/subject.rb +16 -16
  11. data/lib/CLIntegracon/version.rb +1 -1
  12. data/spec/bacon/execution_output.txt +40 -16
  13. data/spec/bacon/spec_helper.rb +10 -1
  14. data/spec/integration/coffeemaker_help/after/execution_output.txt +0 -1
  15. data/spec/integration/coffeemaker_no_milk/after/BlackEye.brewed-coffee.decanted +0 -0
  16. data/spec/integration/coffeemaker_no_milk/after/CaPheSuaDa.brewed-coffee.decanted +0 -0
  17. data/spec/integration/coffeemaker_no_milk/after/RedTux.brewed-coffee.decanted +0 -0
  18. data/spec/integration/coffeemaker_no_milk_sweetner_honey/after/Affogato.brewed-coffee +2 -0
  19. data/spec/integration/coffeemaker_no_milk_sweetner_honey/after/Affogato.brewed-coffee.decanted +0 -0
  20. data/spec/integration/coffeemaker_no_milk_sweetner_honey/after/BlackEye.brewed-coffee +2 -0
  21. data/spec/integration/coffeemaker_no_milk_sweetner_honey/after/BlackEye.brewed-coffee.decanted +0 -0
  22. data/spec/integration/coffeemaker_no_milk_sweetner_honey/after/Coffeemakerfile.yml +2 -0
  23. data/spec/integration/coffeemaker_no_milk_sweetner_honey/after/RedTux.brewed-coffee +2 -0
  24. data/spec/integration/coffeemaker_no_milk_sweetner_honey/after/RedTux.brewed-coffee.decanted +0 -0
  25. data/spec/integration/coffeemaker_no_milk_sweetner_honey/after/execution_output.txt +3 -0
  26. data/spec/integration/coffeemaker_no_milk_sweetner_honey/before/Coffeemakerfile.yml +2 -0
  27. metadata +34 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e7ea45e09d41cdf32e54a9f202b3ef12249cb234
4
- data.tar.gz: 572433ceeea7dbdac41d2408c501f59ecfdda7cd
3
+ metadata.gz: 8783eed598a5361fc795faf244dbd22fe60a35f1
4
+ data.tar.gz: a030a86de14cb5a5a4a9e686b5943a6a1c8fb864
5
5
  SHA512:
6
- metadata.gz: 5800a93a5b745f89a39a65e5c4d2d7dab91ea49f77636d13f69b82976933d24966108305cbf7d19f12a8da4d39ce19b00c26dda6e818412b2d64ee2d16bc9e93
7
- data.tar.gz: 3afc19fc729fea9dfa3327a0941cec7b98c8be85cb1dc521f8f7966f4f09d31f8692af2bdef73398545f76a690ceafac3de67777709ab30c1ba07f152901d46f
6
+ metadata.gz: 6fca68914e6029a04788fb6c99e37abaa8c392fc541f86219a213c6594ae86c848d05e193199179071b66ac90f79a88de8716993510b3592bf6cb27ed3c1b139
7
+ data.tar.gz: 3db0cd2ef3d3dcc8ab501db629bf0121d8587fcb44a765a6c8be18b6cb0488862c543dee168d02750ed8241baf564b52b3beaf8ca41620817ef8865520b4de14
data/.travis.yml CHANGED
@@ -1,7 +1,10 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.8.7
4
- - 2.1.1
3
+ # OS X 10.9.5-10.10.0 (2.0.0-p481)
4
+ - 2.0.0-p481
5
+ # OS X 10.9.3-10.9.4
6
+ - 2.0.0-p451
7
+
5
8
 
6
9
  #addons:
7
10
  # code_climate:
data/Gemfile.lock CHANGED
@@ -1,45 +1,52 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- clintegracon (0.6.1)
4
+ clintegracon (0.7.0)
5
5
  colored (~> 1.2)
6
6
  diffy
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activesupport (3.2.20)
12
- i18n (~> 0.6, >= 0.6.4)
13
- multi_json (~> 1.0)
11
+ activesupport (4.2.1)
12
+ i18n (~> 0.7)
13
+ json (~> 1.7, >= 1.7.7)
14
+ minitest (~> 5.1)
15
+ thread_safe (~> 0.3, >= 0.3.4)
16
+ tzinfo (~> 1.1)
14
17
  bacon (1.2.0)
15
- claide (0.7.0)
18
+ claide (0.8.1)
16
19
  coderay (1.1.0)
17
20
  colored (1.2)
18
- diffy (3.0.6)
19
- i18n (0.6.11)
20
- inch (0.5.0)
21
+ diffy (3.0.7)
22
+ i18n (0.7.0)
23
+ inch (0.6.1)
21
24
  pry
22
25
  sparkr (>= 0.2.0)
23
26
  term-ansicolor
24
- yard (~> 0.8.7)
27
+ yard (~> 0.8.7.5)
28
+ json (1.8.2)
25
29
  metaclass (0.0.4)
26
30
  method_source (0.8.2)
27
- mocha (1.0.0)
31
+ minitest (5.6.1)
32
+ mocha (1.1.0)
28
33
  metaclass (~> 0.0.1)
29
34
  mocha-on-bacon (0.2.2)
30
35
  mocha (>= 0.13.0)
31
- multi_json (1.10.1)
32
36
  pry (0.10.1)
33
37
  coderay (~> 1.1.0)
34
38
  method_source (~> 0.8.1)
35
39
  slop (~> 3.4)
36
- rake (10.1.1)
40
+ rake (10.4.2)
37
41
  slop (3.6.0)
38
42
  sparkr (0.4.1)
39
43
  term-ansicolor (1.3.0)
40
44
  tins (~> 1.0)
41
- tins (1.3.3)
42
- yard (0.8.7.4)
45
+ thread_safe (0.3.5)
46
+ tins (1.5.1)
47
+ tzinfo (1.2.2)
48
+ thread_safe (~> 0.1)
49
+ yard (0.8.7.6)
43
50
 
44
51
  PLATFORMS
45
52
  ruby
@@ -48,9 +55,8 @@ DEPENDENCIES
48
55
  activesupport (>= 3.1)
49
56
  bacon
50
57
  bundler (~> 1.3)
51
- claide
58
+ claide (~> 0.8)
52
59
  clintegracon!
53
60
  inch
54
- mocha (~> 1.0.0)
55
61
  mocha-on-bacon
56
- rake (~> 10.1.0)
62
+ rake
data/Rakefile CHANGED
@@ -39,6 +39,11 @@ begin
39
39
  ].join " | "
40
40
  end
41
41
 
42
+ desc 'Approve the bacon integration execution output as acceptable'
43
+ task :rebuild_bacon_integration do
44
+ `bundle exec rake spec:bacon_integration_runner > spec/bacon/execution_output.txt`
45
+ end
46
+
42
47
  desc 'Run all integration specs'
43
48
  task :integration => [
44
49
  'spec:bacon_integration'
data/clintegracon.gemspec CHANGED
@@ -23,11 +23,10 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_development_dependency "bundler", "~> 1.3"
26
- spec.add_development_dependency "rake", '~> 10.1.0' # Ruby 1.8.7
26
+ spec.add_development_dependency "rake"
27
27
  spec.add_development_dependency "bacon"
28
- spec.add_development_dependency "mocha", "~> 1.0.0" # Ruby 1.8.7
29
28
  spec.add_development_dependency "mocha-on-bacon"
30
- spec.add_development_dependency "claide" # Example CLI
29
+ spec.add_development_dependency "claide", "~> 0.8" # Example CLI
31
30
  spec.add_development_dependency "inch"
32
31
  spec.add_development_dependency 'activesupport', '>= 3.1'
33
32
 
@@ -48,11 +48,11 @@ module CLIntegracon::Adapter::Bacon
48
48
 
49
49
  # Works like `behaves_like`, but takes arguments for the shared example
50
50
  #
51
- # @param [String] name
52
- # name of the shared context.
51
+ # @param [String] name
52
+ # name of the shared context.
53
53
  #
54
- # @param [...] args
55
- # params to pass to the shared context
54
+ # @param [...] args
55
+ # params to pass to the shared context
56
56
  #
57
57
  def behaves_like_a(name, *args)
58
58
  instance_exec(*args, &Bacon::Shared[name])
@@ -69,17 +69,26 @@ module CLIntegracon::Adapter::Bacon
69
69
  # @param [String] spec_dir
70
70
  # the concrete directory of the spec, see {file_spec}.
71
71
  #
72
- # @param [String] args
73
- # the additional arguments to pass on launch to {CLIntegracon::Subject}.
72
+ # @param [String] head_args
73
+ # the arguments to pass before the +default_args+ on launch to {CLIntegracon::Subject}.
74
+ #
75
+ # @param [String] tail_args
76
+ # the arguments to pass after the +default_args+ on launch to {CLIntegracon::Subject}.
77
+ #
78
+ # @param [String] based_on
79
+ # Allows to specify an optional base spec, whose after directory will be used
80
+ # as before directory. You have to ensure that the specs are defined in order,
81
+ # so that the base spec was executed before.
74
82
  #
75
83
  # @return [String]
76
84
  # name of the set of shared expectations
77
85
  #
78
- def cli_spec(spec_dir, *args)
79
- file_spec spec_dir do
80
- output = subject.launch(*args)
86
+ def cli_spec(spec_dir, head_args=nil, tail_args=nil, based_on: nil)
87
+ file_spec(spec_dir, based_on: based_on) do
88
+ output = subject.launch(head_args, tail_args)
81
89
  status = $?
82
90
 
91
+ args = [head_args, tail_args].compact
83
92
  it "$ #{subject.name} #{args.join(' ')}" do
84
93
  status.should.satisfy("Binary failed\n\n#{output}") do
85
94
  status.success?
@@ -102,6 +111,10 @@ module CLIntegracon::Adapter::Bacon
102
111
  # the concrete directory of the spec to be passed to
103
112
  # {FileTreeSpecContext.spec}
104
113
  #
114
+ # @param [String] based_on
115
+ # Allows to specify an optional base spec, whose after directory will be used
116
+ # as before directory.
117
+ #
105
118
  # @param [Block<() -> ()>] block
106
119
  # the block which will be executed after the before state is laid out in the
107
120
  # temporary directory, which normally will make modifications to file system,
@@ -110,13 +123,13 @@ module CLIntegracon::Adapter::Bacon
110
123
  # @return [String]
111
124
  # name of the set of shared expectations
112
125
  #
113
- def file_spec(spec_dir, &block)
126
+ def file_spec(spec_dir, based_on: nil, &block)
114
127
  raise ArgumentError.new("Spec directory is missing!") if spec_dir.nil?
115
128
 
116
129
  shared_name = spec_dir
117
130
 
118
131
  shared shared_name do
119
- file_tree_spec_context.spec(spec_dir).run do |spec|
132
+ file_tree_spec_context.spec(spec_dir, based_on: based_on).run do |spec|
120
133
  instance_eval &block
121
134
 
122
135
  formatter = spec.formatter.lazy
@@ -20,45 +20,45 @@ module CLIntegracon
20
20
 
21
21
  # @return [Proc<(Pathname)->(to_s)>]
22
22
  # the proc, which transforms the files in a better comparable form
23
- attr_accessor :preparator
23
+ attr_accessor :preprocessor
24
24
 
25
25
  # Init a new diff
26
26
  #
27
- # @param [Pathname] expected
28
- # the expected file
27
+ # @param [Pathname] expected
28
+ # the expected file
29
29
  #
30
- # @param [Pathname] produced
31
- # the produced file
30
+ # @param [Pathname] produced
31
+ # the produced file
32
32
  #
33
- # @param [Pathname] relative_path
34
- # the relative path to the expected file
33
+ # @param [Pathname] relative_path
34
+ # the relative path to the expected file
35
35
  #
36
- # @param [Block<(Pathname)->(to_s)>] preparator
37
- # the block, which transforms the files in a better comparable form
36
+ # @param [Block<(Pathname)->(to_s)>] preprocessor
37
+ # the block, which preprocess the files in a better comparable form
38
38
  #
39
- def initialize(expected, produced, relative_path=nil, &preparator)
39
+ def initialize(expected, produced, relative_path=nil, &preprocessor)
40
40
  @expected = expected
41
41
  @produced = produced
42
42
  @relative_path = relative_path
43
- preparator ||= Proc.new { |x| x } #id
44
- self.preparator = preparator
43
+ preprocessor ||= Proc.new { |x| x } #id
44
+ self.preprocessor = preprocessor
45
45
  end
46
46
 
47
- def prepared_expected
48
- @prepared_expected ||= preparator.call(expected)
47
+ def preprocessed_expected
48
+ @preprocessed_expected ||= preprocessor.call(expected)
49
49
  end
50
50
 
51
- def prepared_produced
52
- @prepared_produced ||= preparator.call(produced)
51
+ def preprocessed_produced
52
+ @preprocessed_produced ||= preprocessor.call(produced)
53
53
  end
54
54
 
55
- # Check if the prepared inputs are files or need to be dumped first to
55
+ # Check if the preprocessed inputs are files or need to be dumped first to
56
56
  # temporary files to be compared.
57
57
  #
58
58
  # @return [Bool]
59
59
  #
60
60
  def compares_files?
61
- prepared_expected.is_a? Pathname
61
+ preprocessed_expected.is_a? Pathname
62
62
  end
63
63
 
64
64
  # Check if the produced output equals the expected
@@ -68,9 +68,9 @@ module CLIntegracon
68
68
  #
69
69
  def is_equal?
70
70
  @is_equal ||= if compares_files?
71
- FileUtils.compare_file(prepared_expected, prepared_produced)
71
+ FileUtils.compare_file(preprocessed_expected, preprocessed_produced)
72
72
  else
73
- prepared_expected == prepared_produced
73
+ preprocessed_expected == preprocessed_produced
74
74
  end
75
75
  end
76
76
 
@@ -86,7 +86,7 @@ module CLIntegracon
86
86
  :source => compares_files? ? 'files' : 'strings',
87
87
  :context => 3
88
88
  }.merge options
89
- Diffy::Diff.new(prepared_expected.to_s, prepared_produced.to_s, options).each &block
89
+ Diffy::Diff.new(preprocessed_expected.to_s, preprocessed_produced.to_s, options).each &block
90
90
  end
91
91
 
92
92
  end
@@ -3,6 +3,14 @@ require 'CLIntegracon/diff'
3
3
  require 'CLIntegracon/formatter'
4
4
 
5
5
  module CLIntegracon
6
+ # FileTreeSpec represents a single specification, which is mirrored
7
+ # on the file system in the spec directory by a direct children.
8
+ # It contains a before directory (#before_path) and an after
9
+ # directory (#after_path) or if it is initialized with a #base_spec,
10
+ # the before directory of this spec is used. The before directory
11
+ # contents in the #spec_path of the child spec, can contain further
12
+ # files, which overwrite, if given, the inherited contents.
13
+ #
6
14
  class FileTreeSpec
7
15
 
8
16
  # @return [FileTreeSpecContext]
@@ -37,26 +45,49 @@ module CLIntegracon
37
45
  context.temp_path + spec_folder
38
46
  end
39
47
 
48
+ # @return [String|NilClass]
49
+ # The name of an optional #base_spec.
50
+ attr_reader :base_spec_name
51
+
52
+ # Return whether this spec is based on another spec.
53
+ #
54
+ # @return [Bool]
55
+ #
56
+ def has_base?
57
+ !base_spec_name.nil?
58
+ end
59
+
60
+ # @return [FileTreeSpec|NilClass]
61
+ # The spec on whose #after_path will be used as #before_path
62
+ # for this spec.
63
+ def base_spec
64
+ has_base? ? context.spec(base_spec_name) : nil
65
+ end
66
+
40
67
  # Init a spec with a given context
41
68
  #
42
- # @param [FileTreeSpecContext] context
43
- # The context, which configures path and file behaviors
69
+ # @param [FileTreeSpecContext] context
70
+ # The context, which configures path and file behaviors
44
71
  #
45
- # @param [String] spec_folder
46
- # The concrete spec folder
72
+ # @param [String] spec_folder
73
+ # The concrete spec folder
47
74
  #
48
- def initialize(context, spec_folder)
75
+ # @param [String] based_on
76
+ # @see #base_spec_name
77
+ #
78
+ def initialize(context, spec_folder, based_on: nil)
49
79
  @context = context
50
80
  @spec_folder = spec_folder
81
+ @base_spec_name = based_on
51
82
  end
52
83
 
53
84
  # Run this spec
54
85
  #
55
- # @param [Block<(FileTreeSpec)->()>] block
56
- # The block, which will be executed after chdir into the created temporary
57
- # directory. In this block you will likely run your modifications to the
58
- # file system and use the received FileTreeSpec instance to make asserts
59
- # with the test framework of your choice.
86
+ # @param [Block<(FileTreeSpec)->()>] block
87
+ # The block, which will be executed after chdir into the created temporary
88
+ # directory. In this block you will likely run your modifications to the
89
+ # file system and use the received FileTreeSpec instance to make asserts
90
+ # with the test framework of your choice.
60
91
  #
61
92
  def run(&block)
62
93
  prepare!
@@ -71,9 +102,9 @@ module CLIntegracon
71
102
  # Compares the expected and produced directory by using the rules
72
103
  # defined in the context
73
104
  #
74
- # @param [Block<(Diff)->()>] diff_block
75
- # The block, where you will likely define a test for each file to compare.
76
- # It will receive a Diff of each of the expected and produced files.
105
+ # @param [Block<(Diff)->()>] diff_block
106
+ # The block, where you will likely define a test for each file to compare.
107
+ # It will receive a Diff of each of the expected and produced files.
77
108
  #
78
109
  def compare(&diff_block)
79
110
  transform_paths!
@@ -82,12 +113,10 @@ module CLIntegracon
82
113
  expected = after_path + relative_path
83
114
 
84
115
  next unless expected.file?
116
+ next if context.ignores?(relative_path)
85
117
 
86
- block = special_behavior_for_path relative_path
87
- next if block == context.class.nop
88
-
89
- diff = diff_files(expected, relative_path)
90
- diff.preparator = block unless block.nil?
118
+ block = context.preprocessors_for(relative_path).first
119
+ diff = diff_files(expected, relative_path, &block)
91
120
 
92
121
  diff_block.call diff
93
122
  end
@@ -100,9 +129,9 @@ module CLIntegracon
100
129
  # test case for each file, which wasn't expected at all. So you can
101
130
  # keep your test cases consistent.
102
131
  #
103
- # @param [Block<(Array)->()>] diff_block
104
- # The block, where you will likely define a test that no unexpected files exists.
105
- # It will receive an Array.
132
+ # @param [Block<(Array)->()>] diff_block
133
+ # The block, where you will likely define a test that no unexpected files exists.
134
+ # It will receive an Array.
106
135
  #
107
136
  def check_unexpected_files(&block)
108
137
  expected_files = glob_all after_path
@@ -110,10 +139,10 @@ module CLIntegracon
110
139
  unexpected_files = produced_files - expected_files
111
140
 
112
141
  # Select only files
113
- unexpected_files.reject! { |path| !path.file? }
142
+ unexpected_files.select! { |path| path.file? }
114
143
 
115
144
  # Filter ignored paths
116
- unexpected_files.reject! { |path| special_behavior_for_path(path) == context.class.nop }
145
+ unexpected_files.reject! { |path| context.ignores?(path) }
117
146
 
118
147
  block.call unexpected_files
119
148
  end
@@ -141,18 +170,25 @@ module CLIntegracon
141
170
  # directory.
142
171
  #
143
172
  def copy_files!
144
- source = before_path
145
173
  destination = temp_path
146
- FileUtils.cp_r("#{source}/.", destination)
174
+
175
+ if has_base?
176
+ FileUtils.cp_r("#{base_spec.after_path}/.", destination)
177
+ end
178
+
179
+ begin
180
+ FileUtils.cp_r("#{before_path}/.", destination)
181
+ rescue Errno::ENOENT => e
182
+ raise e unless has_base?
183
+ end
147
184
  end
148
185
 
149
186
  # Applies the in the context configured transformations.
150
187
  #
151
188
  def transform_paths!
152
- context.transform_paths.each do |path, block|
153
- Dir.glob(path) do |produced_path|
154
- produced = Pathname(produced_path)
155
- block.call(produced)
189
+ glob_all.each do |path|
190
+ context.transformers_for(path).each do |transformer|
191
+ transformer.call(path)
156
192
  end
157
193
  end
158
194
  end
@@ -160,53 +196,37 @@ module CLIntegracon
160
196
  # Searches recursively for all files and take care for including hidden files
161
197
  # if this is configured in the context.
162
198
  #
163
- # @param [String] path
164
- # The relative or absolute path to search in (optional)
199
+ # @param [String] path
200
+ # The relative or absolute path to search in (optional)
165
201
  #
166
202
  # @return [Array<Pathname>]
167
203
  #
168
204
  def glob_all(path=nil)
169
205
  Dir.chdir path || '.' do
170
- Dir.glob("**/*", context.include_hidden_files? ? File::FNM_DOTMATCH : 0).sort.map { |path|
171
- Pathname(path)
172
- }
173
- end
174
- end
175
-
176
- # Find the special behavior for a given path
177
- #
178
- # @return [Block<(Pathname) -> to_s>]
179
- # This block takes the Pathname and transforms the file in a better comparable
180
- # state. If it returns nil, the file is ignored.
181
- #
182
- def special_behavior_for_path(path)
183
- context.special_paths.each do |key, block|
184
- matched = if key.is_a?(Regexp)
185
- path.to_s.match(key)
186
- else
187
- File.fnmatch(key, path)
206
+ Dir.glob("**/*", context.include_hidden_files? ? File::FNM_DOTMATCH : 0).sort.map do |p|
207
+ Pathname(p)
188
208
  end
189
- next unless matched
190
- return block
191
209
  end
192
- return nil
193
210
  end
194
211
 
195
212
  # Compares two files to check if they are identical and produces a clear diff
196
213
  # to highlight the differences.
197
214
  #
198
- # @param [Pathname] expected
199
- # The file in the after directory
215
+ # @param [Pathname] expected
216
+ # The file in the after directory
217
+ #
218
+ # @param [Pathname] relative_path
219
+ # The file in the temp directory
200
220
  #
201
- # @param [Pathname] relative_path
202
- # The file in the temp directory
221
+ # @param [Block<(Pathname)->(to_s)>] block
222
+ # the block, which transforms the files in a better comparable form
203
223
  #
204
224
  # @return [Diff]
205
225
  # An object holding a diff
206
226
  #
207
- def diff_files(expected, relative_path)
227
+ def diff_files(expected, relative_path, &block)
208
228
  produced = temp_path + relative_path
209
- Diff.new(expected, produced, relative_path)
229
+ Diff.new(expected, produced, relative_path, &block)
210
230
  end
211
231
 
212
232
  end
@@ -29,13 +29,17 @@ module CLIntegracon
29
29
  #
30
30
  attr_accessor :temp_path
31
31
 
32
- # @return [Hash<String,Block>]
33
- # the special paths of files, which need to be transformed in a better comparable form
32
+ # @return [Hash<String|Regexp,Block>]
33
+ # the paths of files, which need to be transformed in a better comparable form
34
34
  attr_accessor :transform_paths
35
35
 
36
- # @return [Hash<String,Block>]
37
- # the special paths of files, where an individual file diff handling is needed
38
- attr_accessor :special_paths
36
+ # @return [Hash<String|Regexp,Block>]
37
+ # the paths of files, where an individual file diff handling is needed
38
+ attr_accessor :preprocess_paths
39
+
40
+ # @return [Array<String|Regexp>]
41
+ # the paths of files to exclude from comparison
42
+ attr_accessor :ignore_paths
39
43
 
40
44
  # @return [Bool]
41
45
  # whether to include hidden files, when searching directories (true by default)
@@ -49,12 +53,12 @@ module CLIntegracon
49
53
 
50
54
  # "Designated" initializer
51
55
  #
52
- # @param [Hash<Symbol,String>] properties
53
- # The configuration parameter (optional):
54
- # :spec_path => see self.spec_path
55
- # :before_dir => see self.before_dir
56
- # :after_dir => see self.after_dir
57
- # :temp_path => see self.temp_path
56
+ # @param [Hash<Symbol,String>] properties
57
+ # The configuration parameter (optional):
58
+ # :spec_path => see self.spec_path
59
+ # :before_dir => see self.before_dir
60
+ # :after_dir => see self.after_dir
61
+ # :temp_path => see self.temp_path
58
62
  #
59
63
  def initialize(properties={})
60
64
  self.spec_path = properties[:spec_path] || '.'
@@ -62,24 +66,12 @@ module CLIntegracon
62
66
  self.before_dir = properties[:before_dir] || 'before'
63
67
  self.after_dir = properties[:after_dir] || 'after'
64
68
  self.transform_paths = {}
65
- self.special_paths = {}
69
+ self.preprocess_paths = {}
70
+ self.ignore_paths = []
66
71
  self.include_hidden_files = true
67
72
  end
68
73
 
69
74
 
70
- #-----------------------------------------------------------------------------#
71
-
72
- # @!group Helper
73
-
74
- # This value is used for ignored paths
75
- #
76
- # @return [Proc]
77
- # Does nothing
78
- def self.nop
79
- @nop ||= Proc.new {}
80
- end
81
-
82
-
83
75
  #-----------------------------------------------------------------------------#
84
76
 
85
77
  # @!group Setter
@@ -109,11 +101,12 @@ module CLIntegracon
109
101
 
110
102
  # @!group DSL-like Setter
111
103
 
112
- # Registers a block for special handling certain files, matched with globs.
104
+ # Registers a block to transform certain files, matched with globs or
105
+ # regular expressions.
113
106
  # Multiple transformers can match a single file.
114
107
  #
115
108
  # @param [String...] file_paths
116
- # The file path(s) of the files, which were created/changed and need transformation
109
+ # The path(s), which need to be transformed in a better comparable form
117
110
  #
118
111
  # @param [Block<(Pathname) -> ()>] block
119
112
  # The block, which takes each of the matched files, transforms it if needed
@@ -127,31 +120,70 @@ module CLIntegracon
127
120
  end
128
121
  end
129
122
 
130
- # Registers a block for special handling certain files, matched with globs.
123
+ # Registers a block to preprocess certain files, matched with globs or
124
+ # regular expressions.
131
125
  # Registered file paths will be excluded from default comparison by `diff`.
132
- # Multiple special handlers can match a single file.
126
+ # A file is preprocessed with the first matching preprocessor.
133
127
  #
134
128
  # @param [String|Regexp...] file_paths
135
- # The file path(s) of the files, which were created/changed and need special comparison
129
+ # The path(s)s, where an individual file diff handling is needed
136
130
  #
137
131
  # @param [Block<(Pathname) -> (String)>] block
138
132
  # The block, which takes each of the matched files, transforms it if needed
139
133
  # in a better comparable form.
140
134
  #
141
- def has_special_handling_for(*file_paths, &block)
135
+ def preprocess(*file_paths, &block)
142
136
  file_paths.each do |file_path|
143
- self.special_paths[file_path] = block
137
+ self.preprocess_paths[file_path] = block
144
138
  end
145
139
  end
146
140
 
147
141
  # Copies the before subdirectory of the given tests folder in the temporary
148
142
  # directory.
149
143
  #
150
- # @param [String|RegExp...] file_path
151
- # the file path of the files, which were changed and need special comparison
144
+ # @param [String|RegExp...] file_paths
145
+ # the file path(s) of the files to exclude from comparison
146
+ #
147
+ def ignores(*file_paths)
148
+ self.ignore_paths += file_paths
149
+ end
150
+
151
+
152
+ #-----------------------------------------------------------------------------#
153
+
154
+ # @!group Path accessors
155
+
156
+ # Returns a list of transformers to apply for a given file path.
157
+ #
158
+ # @param [Pathname] file_path
159
+ # The file path to match
160
+ #
161
+ # @return [Array<Block<(Pathname) -> ()>>]
162
+ #
163
+ def transformers_for(file_path)
164
+ select_matching_file_patterns(transform_paths, file_path).values
165
+ end
166
+
167
+ # Returns a list of preprocessors to apply for a given file path.
168
+ #
169
+ # @param [Pathname] file_path
170
+ # The file path to match
171
+ #
172
+ # @return [Array<Block<(Pathname) -> (String)>>]
173
+ #
174
+ def preprocessors_for(file_path)
175
+ select_matching_file_patterns(preprocess_paths, file_path).values
176
+ end
177
+
178
+ # Checks whether a given file path is to ignore.
179
+ #
180
+ # @param [Pathname] file_path
181
+ # The file path to match
182
+ #
183
+ # @return [Bool]
152
184
  #
153
- def ignores(*file_path)
154
- has_special_handling_for *file_path, &self.class.nop
185
+ def ignores?(file_path)
186
+ !select_matching_file_patterns(ignore_paths, file_path).empty?
155
187
  end
156
188
 
157
189
 
@@ -168,13 +200,42 @@ module CLIntegracon
168
200
 
169
201
  # Get a specific spec with given folder to run it
170
202
  #
171
- # @param [String] folder
172
- # The name of the folder of the tests
203
+ # @param [String] folder
204
+ # The name of the folder of the tests
205
+ #
206
+ # @param [String] based_on
207
+ # @see FileTreeSpec#base_spec_name
173
208
  #
174
209
  # @return [FileTreeSpec]
175
210
  #
176
- def spec(spec_folder)
177
- FileTreeSpec.new(self, spec_folder)
211
+ def spec(spec_folder, based_on: nil)
212
+ FileTreeSpec.new(self, spec_folder, based_on: based_on)
213
+ end
214
+
215
+ #-----------------------------------------------------------------------------#
216
+
217
+ private
218
+
219
+ # @!group Helpers
220
+
221
+ # Select elements in an enumerable which match the given path.
222
+ #
223
+ # @param [Enumerable<String|RegExp>] patterns
224
+ # The patterns to check
225
+ #
226
+ # @param [Pathname] path
227
+ # The file to match
228
+ #
229
+ # @return [Enumerable<String|RegExp>]
230
+ #
231
+ def select_matching_file_patterns(patterns, path)
232
+ patterns.select do |pattern|
233
+ if pattern.is_a?(Regexp)
234
+ path.to_s.match(pattern)
235
+ else
236
+ File.fnmatch(pattern, path)
237
+ end
238
+ end
178
239
  end
179
240
 
180
241
  end
@@ -42,11 +42,11 @@ module CLIntegracon
42
42
 
43
43
  # "Designated" initializer
44
44
  #
45
- # @param [String] name
46
- # The name of the binary
45
+ # @param [String] name
46
+ # The name of the binary
47
47
  #
48
- # @param [String] executable
49
- # The executable subject statement (optional)
48
+ # @param [String] executable
49
+ # The executable subject statement (optional)
50
50
  #
51
51
  def initialize(name='subject', executable=nil)
52
52
  self.name = name
@@ -65,11 +65,11 @@ module CLIntegracon
65
65
  # Define a pattern, whose occurrences in the output should be replaced by a
66
66
  # given placeholder.
67
67
  #
68
- # @param [Regexp|String] pattern
69
- # The pattern
68
+ # @param [Regexp|String] pattern
69
+ # The pattern
70
70
  #
71
- # @param [String] replacement
72
- # The replacement
71
+ # @param [String] replacement
72
+ # The replacement
73
73
  #
74
74
  def replace_pattern(pattern, replacement)
75
75
  self.replace_patterns[replacement] = pattern
@@ -78,11 +78,11 @@ module CLIntegracon
78
78
  # Define a path, whose occurrences in the output should be replaced by
79
79
  # either its basename or a given placeholder.
80
80
  #
81
- # @param [String] path
82
- # The path
81
+ # @param [String] path
82
+ # The path
83
83
  #
84
- # @param [String] name
85
- # The name of the path, or the basename of the given path
84
+ # @param [String] name
85
+ # The name of the path, or the basename of the given path
86
86
  #
87
87
  def replace_path(path, name=nil)
88
88
  name ||= File.basename path
@@ -92,11 +92,11 @@ module CLIntegracon
92
92
  # Define a path in the user directory, whose occurrences in the output
93
93
  # should be replaced by either its basename or a given placeholder.
94
94
  #
95
- # @param [String] path
96
- # The path
95
+ # @param [String] path
96
+ # The path
97
97
  #
98
- # @param [String] name
99
- # The name of the path, or the given path
98
+ # @param [String] name
99
+ # The name of the path, or the given path
100
100
  #
101
101
  def replace_user_path(path, name=nil)
102
102
  name ||= "$HOME/#{path}"
@@ -1,3 +1,3 @@
1
1
  module CLIntegracon
2
- VERSION = "0.6.1"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -4,9 +4,12 @@ CLIntegracon::Adapter::Bacon
4
4
  without milk
5
5
  - $ coffee-maker --no-milk
6
6
  - BlackEye.brewed-coffee
7
+ - BlackEye.brewed-coffee.decanted
7
8
  - CaPheSuaDa.brewed-coffee [FAILED]
9
+ - CaPheSuaDa.brewed-coffee.decanted
8
10
  - Coffeemakerfile.yml
9
11
  - RedTux.brewed-coffee
12
+ - RedTux.brewed-coffee.decanted
10
13
  - execution_output.txt
11
14
  - should not produce unexpected files [FAILED]
12
15
  with honey as sweetner
@@ -16,6 +19,17 @@ CLIntegracon::Adapter::Bacon
16
19
  - Coffeemakerfile.yml
17
20
  - RedTux.brewed-coffee [FAILED]
18
21
  - execution_output.txt
22
+ - should not produce unexpected files [FAILED]
23
+ without milk and honey as sweetner
24
+ - $ coffee-maker --no-milk --sweetner=honey
25
+ - Affogato.brewed-coffee
26
+ - Affogato.brewed-coffee.decanted
27
+ - BlackEye.brewed-coffee
28
+ - BlackEye.brewed-coffee.decanted
29
+ - Coffeemakerfile.yml
30
+ - RedTux.brewed-coffee
31
+ - RedTux.brewed-coffee.decanted
32
+ - execution_output.txt
19
33
  - should not produce unexpected files
20
34
  Get help
21
35
  - $ coffee-maker --help
@@ -28,17 +42,18 @@ Bacon::Error: File comparison error `CaPheSuaDa.brewed-coffee` for coffeemaker_n
28
42
  - @origin = "Việt Nam"
29
43
  --- END ------------------------------------------------------------------------
30
44
 
31
- spec/bacon/spec_helper.rb:45
32
- spec/bacon/spec_helper.rb:44
33
- spec/bacon/spec_helper.rb:42
45
+ spec/bacon/spec_helper.rb:49
46
+ spec/bacon/spec_helper.rb:48
47
+ spec/bacon/spec_helper.rb:46
34
48
  spec/bacon/spec_helper.rb:17
35
49
  spec/bacon/spec_helper.rb:15
36
50
 
37
51
  Bacon::Error: Unexpected files for coffeemaker_no_milk:
38
52
  * Affogato.brewed-coffee
39
- spec/bacon/spec_helper.rb:45
40
- spec/bacon/spec_helper.rb:44
41
- spec/bacon/spec_helper.rb:42
53
+ * Affogato.brewed-coffee.decanted
54
+ spec/bacon/spec_helper.rb:49
55
+ spec/bacon/spec_helper.rb:48
56
+ spec/bacon/spec_helper.rb:46
42
57
  spec/bacon/spec_helper.rb:17
43
58
  spec/bacon/spec_helper.rb:15
44
59
 
@@ -49,17 +64,17 @@ Bacon::Error: File comparison error `Affogato.brewed-coffee` for coffeemaker_swe
49
64
  @sweetner = honey
50
65
  --- END ------------------------------------------------------------------------
51
66
 
52
- spec/bacon/spec_helper.rb:49
53
- spec/bacon/spec_helper.rb:48
54
- spec/bacon/spec_helper.rb:42
67
+ spec/bacon/spec_helper.rb:53
68
+ spec/bacon/spec_helper.rb:52
69
+ spec/bacon/spec_helper.rb:46
55
70
  spec/bacon/spec_helper.rb:17
56
71
  spec/bacon/spec_helper.rb:15
57
72
 
58
73
  Bacon::Error: Missing file for coffeemaker_sweetner_honey:
59
74
  * BlackEye.brewed-coffee
60
- spec/bacon/spec_helper.rb:49
61
- spec/bacon/spec_helper.rb:48
62
- spec/bacon/spec_helper.rb:42
75
+ spec/bacon/spec_helper.rb:53
76
+ spec/bacon/spec_helper.rb:52
77
+ spec/bacon/spec_helper.rb:46
63
78
  spec/bacon/spec_helper.rb:17
64
79
  spec/bacon/spec_helper.rb:15
65
80
 
@@ -71,10 +86,19 @@ Bacon::Error: File comparison error `RedTux.brewed-coffee` for coffeemaker_sweet
71
86
  + @sweetner = honey
72
87
  --- END ------------------------------------------------------------------------
73
88
 
74
- spec/bacon/spec_helper.rb:49
75
- spec/bacon/spec_helper.rb:48
76
- spec/bacon/spec_helper.rb:42
89
+ spec/bacon/spec_helper.rb:53
90
+ spec/bacon/spec_helper.rb:52
91
+ spec/bacon/spec_helper.rb:46
92
+ spec/bacon/spec_helper.rb:17
93
+ spec/bacon/spec_helper.rb:15
94
+
95
+ Bacon::Error: Unexpected files for coffeemaker_sweetner_honey:
96
+ * Affogato.brewed-coffee.decanted
97
+ * RedTux.brewed-coffee.decanted
98
+ spec/bacon/spec_helper.rb:53
99
+ spec/bacon/spec_helper.rb:52
100
+ spec/bacon/spec_helper.rb:46
77
101
  spec/bacon/spec_helper.rb:17
78
102
  spec/bacon/spec_helper.rb:15
79
103
 
80
- 17 specifications (27 requirements), 5 failures, 0 errors
104
+ 30 specifications (51 requirements), 6 failures, 0 errors
@@ -34,7 +34,11 @@ describe CLIntegracon::Adapter::Bacon do
34
34
  c.ignores '.DS_Store'
35
35
  c.ignores '.gitkeep'
36
36
 
37
- c.has_special_handling_for 'CaPheSuaDa.brewed-coffee' do |path|
37
+ c.transform_produced /\.brewed-coffee/ do |path|
38
+ FileUtils.touch("#{path}.decanted")
39
+ end
40
+
41
+ c.preprocess 'CaPheSuaDa.brewed-coffee' do |path|
38
42
  File.read(path)
39
43
  end
40
44
  end
@@ -49,6 +53,11 @@ describe CLIntegracon::Adapter::Bacon do
49
53
  behaves_like cli_spec('coffeemaker_sweetner_honey', '--sweetner=honey')
50
54
  end
51
55
 
56
+ describe 'without milk and honey as sweetner' do
57
+ behaves_like cli_spec('coffeemaker_no_milk_sweetner_honey', '--no-milk --sweetner=honey',
58
+ based_on: 'coffeemaker_sweetner_honey')
59
+ end
60
+
52
61
  end
53
62
 
54
63
  describe 'Get help' do
@@ -9,7 +9,6 @@ Options:
9
9
 
10
10
  --no-milk Don’t add milk
11
11
  --sweetner=[sugar|honey] Use one of the available sweetners
12
- --completion-script Print the auto-completion script
13
12
  --version Show the version of the tool
14
13
  --verbose Show more debugging information
15
14
  --no-ansi Show output without ANSI codes
@@ -0,0 +1,2 @@
1
+ class Affogato < BrewedCoffee
2
+ @sweetner = honey
@@ -0,0 +1,2 @@
1
+ class BlackEye < BrewedCoffee
2
+ @sweetner = honey
@@ -0,0 +1,2 @@
1
+ class RedTux < BrewedCoffee
2
+ @sweetner = sugar
@@ -0,0 +1,3 @@
1
+ COFFEE_MAKER_FILE=Coffeemakerfile.yml PROJECT_DIR=ROOT bundle exec ruby ROOT/spec/fixtures/bin/coffeemaker.rb --no-milk --sweetner=honey --verbose --no-ansi 2>&1
2
+ * Brewing BlackEye
3
+ * Enjoy!
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clintegracon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marius Rackwitz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-02 00:00:00.000000000 Z
11
+ date: 2015-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 10.1.0
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 10.1.0
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bacon
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: mocha
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 1.0.0
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 1.0.0
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: mocha-on-bacon
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -84,16 +70,16 @@ dependencies:
84
70
  name: claide
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
- - - ">="
73
+ - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: '0'
75
+ version: '0.8'
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
- - - ">="
80
+ - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: '0'
82
+ version: '0.8'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: inch
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -182,11 +168,23 @@ files:
182
168
  - spec/integration/coffeemaker_help/after/execution_output.txt
183
169
  - spec/integration/coffeemaker_help/before/.gitkeep
184
170
  - spec/integration/coffeemaker_no_milk/after/BlackEye.brewed-coffee
171
+ - spec/integration/coffeemaker_no_milk/after/BlackEye.brewed-coffee.decanted
185
172
  - spec/integration/coffeemaker_no_milk/after/CaPheSuaDa.brewed-coffee
173
+ - spec/integration/coffeemaker_no_milk/after/CaPheSuaDa.brewed-coffee.decanted
186
174
  - spec/integration/coffeemaker_no_milk/after/Coffeemakerfile.yml
187
175
  - spec/integration/coffeemaker_no_milk/after/RedTux.brewed-coffee
176
+ - spec/integration/coffeemaker_no_milk/after/RedTux.brewed-coffee.decanted
188
177
  - spec/integration/coffeemaker_no_milk/after/execution_output.txt
189
178
  - spec/integration/coffeemaker_no_milk/before/Coffeemakerfile.yml
179
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/Affogato.brewed-coffee
180
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/Affogato.brewed-coffee.decanted
181
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/BlackEye.brewed-coffee
182
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/BlackEye.brewed-coffee.decanted
183
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/Coffeemakerfile.yml
184
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/RedTux.brewed-coffee
185
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/RedTux.brewed-coffee.decanted
186
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/execution_output.txt
187
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/before/Coffeemakerfile.yml
190
188
  - spec/integration/coffeemaker_sweetner_honey/after/Affogato.brewed-coffee
191
189
  - spec/integration/coffeemaker_sweetner_honey/after/BlackEye.brewed-coffee
192
190
  - spec/integration/coffeemaker_sweetner_honey/after/Coffeemakerfile.yml
@@ -229,11 +227,23 @@ test_files:
229
227
  - spec/integration/coffeemaker_help/after/execution_output.txt
230
228
  - spec/integration/coffeemaker_help/before/.gitkeep
231
229
  - spec/integration/coffeemaker_no_milk/after/BlackEye.brewed-coffee
230
+ - spec/integration/coffeemaker_no_milk/after/BlackEye.brewed-coffee.decanted
232
231
  - spec/integration/coffeemaker_no_milk/after/CaPheSuaDa.brewed-coffee
232
+ - spec/integration/coffeemaker_no_milk/after/CaPheSuaDa.brewed-coffee.decanted
233
233
  - spec/integration/coffeemaker_no_milk/after/Coffeemakerfile.yml
234
234
  - spec/integration/coffeemaker_no_milk/after/RedTux.brewed-coffee
235
+ - spec/integration/coffeemaker_no_milk/after/RedTux.brewed-coffee.decanted
235
236
  - spec/integration/coffeemaker_no_milk/after/execution_output.txt
236
237
  - spec/integration/coffeemaker_no_milk/before/Coffeemakerfile.yml
238
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/Affogato.brewed-coffee
239
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/Affogato.brewed-coffee.decanted
240
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/BlackEye.brewed-coffee
241
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/BlackEye.brewed-coffee.decanted
242
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/Coffeemakerfile.yml
243
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/RedTux.brewed-coffee
244
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/RedTux.brewed-coffee.decanted
245
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/after/execution_output.txt
246
+ - spec/integration/coffeemaker_no_milk_sweetner_honey/before/Coffeemakerfile.yml
237
247
  - spec/integration/coffeemaker_sweetner_honey/after/Affogato.brewed-coffee
238
248
  - spec/integration/coffeemaker_sweetner_honey/after/BlackEye.brewed-coffee
239
249
  - spec/integration/coffeemaker_sweetner_honey/after/Coffeemakerfile.yml