golly-utils 0.0.1 → 0.6.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 (54) hide show
  1. data/.corvid/Gemfile +28 -0
  2. data/.corvid/features.yml +4 -0
  3. data/.corvid/plugins.yml +4 -0
  4. data/.corvid/stats_cfg.rb +13 -0
  5. data/.corvid/todo_cfg.rb +15 -0
  6. data/.corvid/versions.yml +2 -0
  7. data/.simplecov +6 -3
  8. data/CHANGELOG.md +45 -2
  9. data/Gemfile +6 -3
  10. data/Gemfile.lock +34 -37
  11. data/Guardfile +10 -4
  12. data/RELEASE.md +2 -0
  13. data/Rakefile +1 -1
  14. data/golly-utils.gemspec +19 -10
  15. data/lib/golly-utils/attr_declarative.rb +120 -49
  16. data/lib/golly-utils/callbacks.rb +211 -19
  17. data/lib/golly-utils/child_process.rb +28 -8
  18. data/lib/golly-utils/delegator.rb +14 -3
  19. data/lib/golly-utils/ruby_ext/classes_and_types.rb +120 -0
  20. data/lib/golly-utils/ruby_ext/enumerable.rb +16 -0
  21. data/lib/golly-utils/ruby_ext/env_helpers.rb +17 -0
  22. data/lib/golly-utils/ruby_ext/kernel.rb +18 -0
  23. data/lib/golly-utils/ruby_ext/options.rb +28 -0
  24. data/lib/golly-utils/ruby_ext/pretty_error_messages.rb +1 -1
  25. data/lib/golly-utils/singleton.rb +130 -0
  26. data/lib/golly-utils/testing/dynamic_fixtures.rb +268 -0
  27. data/lib/golly-utils/testing/file_helpers.rb +117 -0
  28. data/lib/golly-utils/testing/helpers_base.rb +20 -0
  29. data/lib/golly-utils/testing/rspec/arrays.rb +85 -0
  30. data/lib/golly-utils/testing/rspec/base.rb +9 -0
  31. data/lib/golly-utils/testing/rspec/deferrable_specs.rb +111 -0
  32. data/lib/golly-utils/testing/rspec/files.rb +262 -0
  33. data/lib/golly-utils/{test/spec → testing/rspec}/within_time.rb +17 -7
  34. data/lib/golly-utils/version.rb +2 -1
  35. data/test/bootstrap/all.rb +8 -1
  36. data/test/bootstrap/spec.rb +1 -1
  37. data/test/bootstrap/unit.rb +1 -1
  38. data/test/spec/child_process_spec.rb +1 -1
  39. data/test/spec/testing/dynamic_fixtures_spec.rb +131 -0
  40. data/test/spec/testing/rspec/arrays_spec.rb +33 -0
  41. data/test/spec/testing/rspec/files_spec.rb +300 -0
  42. data/test/unit/attr_declarative_test.rb +79 -13
  43. data/test/unit/callbacks_test.rb +103 -5
  44. data/test/unit/delegator_test.rb +25 -1
  45. data/test/unit/ruby_ext/classes_and_types_test.rb +103 -0
  46. data/test/unit/ruby_ext/enumerable_test.rb +12 -0
  47. data/test/unit/ruby_ext/options_test.rb +29 -0
  48. data/test/unit/singleton_test.rb +59 -0
  49. metadata +100 -10
  50. data/Gemfile.corvid +0 -27
  51. data/lib/golly-utils/ruby_ext.rb +0 -2
  52. data/lib/golly-utils/ruby_ext/subclasses.rb +0 -17
  53. data/lib/golly-utils/test/spec/deferrable_specs.rb +0 -85
  54. data/test/unit/ruby_ext/subclasses_test.rb +0 -24
@@ -1,19 +1,28 @@
1
- module TestHelpers
1
+ require 'golly-utils/testing/rspec/base'
2
2
 
3
- # @example
4
- # within(5).seconds{ File.exists?(f).should == true }
5
- # @see WithinTime
6
- def within(timeout)
7
- WithinTime.new(timeout)
8
- end
3
+ module GollyUtils::Testing::Helpers
9
4
 
10
5
  # Re-runs a given block until it:
11
6
  #
12
7
  # * indicates success by returning `true`
13
8
  # * fails by not returning `true` within a given time period.
14
9
  #
10
+ # @example
11
+ # within(5).seconds{ 'Gemfile'.should exist_as_a_file }
12
+ #
13
+ # @param [Numeric] timeout The maximum number of time units (to be specified after a call to this) to wait for a
14
+ # condition to be met.
15
+ # @see WithinTime
16
+ def within(timeout)
17
+ WithinTime.new(timeout)
18
+ end
19
+
15
20
  # @see #within
16
21
  class WithinTime
22
+
23
+ # @param [Numeric] timeout The maximum number of time units (to be specified after a call to this) to wait for a
24
+ # condition to be met.
25
+ # @param [Numeric] sleep_time The number of seconds to wait after an unsuccessful attempt before trying again.
17
26
  def initialize(timeout, sleep_time=0.1)
18
27
  timeout= timeout.to_f
19
28
  raise unless timeout > 0
@@ -53,4 +62,5 @@ module TestHelpers
53
62
  end
54
63
  end
55
64
  end
65
+
56
66
  end
@@ -1,3 +1,4 @@
1
1
  module GollyUtils
2
- VERSION = "0.0.1"
2
+ # The version of the GollyUtils library.
3
+ VERSION = "0.6.0".freeze
3
4
  end
@@ -1,4 +1,11 @@
1
1
  # encoding: utf-8
2
2
  APP_ROOT = File.expand_path('../../..',__FILE__)
3
3
  require 'rubygems'
4
- require 'corvid/test/bootstrap/all'
4
+ require 'bundler/setup'
5
+ require 'corvid/builtin/test/bootstrap/all'
6
+
7
+ Bundler.require :default
8
+
9
+ # Load test helpers
10
+ Dir.glob("#{APP_ROOT}/test/helpers/**/*.rb") {|f| require f}
11
+
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
  $coverage_name = 'specs'
3
3
  require_relative 'all'
4
- require 'corvid/test/bootstrap/spec'
4
+ require 'corvid/builtin/test/bootstrap/spec'
5
5
 
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  $coverage_name = 'unit tests'
3
3
  require_relative 'all'
4
- require 'corvid/test/bootstrap/unit'
4
+ require 'corvid/builtin/test/bootstrap/unit'
@@ -2,7 +2,7 @@
2
2
  require_relative '../bootstrap/spec'
3
3
  require 'tmpdir'
4
4
  require 'golly-utils/child_process'
5
- require 'golly-utils/test/spec/within_time'
5
+ require 'golly-utils/testing/rspec/within_time'
6
6
 
7
7
  describe GollyUtils::ChildProcess do
8
8
  after :each do
@@ -0,0 +1,131 @@
1
+ # encoding: utf-8
2
+ require_relative '../../bootstrap/spec'
3
+ require 'golly-utils/testing/dynamic_fixtures'
4
+ require 'golly-utils/testing/rspec/files'
5
+
6
+ describe GollyUtils::Testing::DynamicFixtures do
7
+ include described_class
8
+
9
+ $gu_dynfix_a_count= 0
10
+ def_fixture :a do
11
+ $gu_dynfix_a_count += 1
12
+ Dir.mkdir 'aa'
13
+ File.write 'aa/abc', '123'
14
+ File.write 'a_parent', 'good'
15
+ end
16
+
17
+ def_fixture :b, dir_name: 'bbb' do
18
+ File.write 'basename', File.basename(Dir.pwd)
19
+ end
20
+
21
+
22
+ def_fixture :c, cd_into: 'ccc' do
23
+ Dir.mkdir 'ccc'
24
+ File.write 'ccc/blah', '333'
25
+ File.write 'parent', 'good'
26
+ end
27
+
28
+ def_fixture(:lazy){ $gu_dynfix_lazy= 'called' }
29
+
30
+ #---------------------------------------------------------------------------------------------------------------------
31
+
32
+ describe '#def_fixture' do
33
+ it("creates fixtures on-demand, not when defined"){
34
+ $gu_dynfix_lazy.should be_nil
35
+ }
36
+
37
+ it("creates fixtures only once"){
38
+ inside_dynamic_fixture(:a){}
39
+ inside_dynamic_fixture(:a){}
40
+ $gu_dynfix_a_count.should == 1
41
+ }
42
+
43
+ it("creates the fixture in a directory naming according to the :dir_name option"){
44
+ inside_dynamic_fixture(:b){
45
+ 'basename'.should be_file_with_content 'bbb'
46
+ }
47
+ }
48
+ end
49
+
50
+ describe '#inside_dynamic_fixture' do
51
+ it("provides a clean copy of the fixture"){
52
+ inside_dynamic_fixture(:b){ File.delete 'basename' }
53
+ inside_dynamic_fixture(:b){ 'basename'.should exist_as_file }
54
+ }
55
+
56
+ it("cds into a fixture subdirectory specified by :cd_into"){
57
+ inside_dynamic_fixture(:c){
58
+ File.basename(Dir.pwd).should == 'ccc'
59
+ 'blah'.should exist_as_file
60
+ }
61
+ }
62
+
63
+ it("provides the full fixture when :cd_into specified"){
64
+ inside_dynamic_fixture(:c){
65
+ '../parent'.should exist_as_file
66
+ }
67
+ }
68
+ end
69
+
70
+ #---------------------------------------------------------------------------------------------------------------------
71
+
72
+ shared_examples :cd_with_aa do
73
+ it("runs examples in the specified fixture subdirectory"){
74
+ 'abc'.should exist_as_file
75
+ }
76
+ it("provides the full fixture"){
77
+ '../a_parent'.should exist_as_file
78
+ }
79
+ end
80
+
81
+ describe '#run_each_in_dynamic_fixture' do
82
+
83
+ context "when only fixture name specified" do
84
+ run_each_in_dynamic_fixture :a
85
+ def test
86
+ 'aa/abc'.should exist_as_file
87
+ File.delete 'aa/abc'
88
+ end
89
+ it("provides each example a clean copy of the fixture (1/2)"){ test }
90
+ it("provides each example a clean copy of the fixture (2/2)"){ test }
91
+ end
92
+
93
+ context "when :cd_into specified" do
94
+ run_each_in_dynamic_fixture :a, cd_into: 'aa'
95
+ include_examples :cd_with_aa
96
+ end
97
+ end
98
+
99
+ #---------------------------------------------------------------------------------------------------------------------
100
+
101
+ describe '#run_all_in_dynamic_fixture' do
102
+
103
+ context "when only fixture name specified" do
104
+ run_all_in_dynamic_fixture(:a){
105
+ File.write 'init.called', '1'
106
+ $ffs= 0
107
+ }
108
+ def test
109
+ 'aa/abc'.should exist_as_file
110
+ if $ffs == 0
111
+ # Test 1
112
+ 'dirty'.should_not exist_as_file
113
+ File.write 'dirty', '1'
114
+ $ffs += 1
115
+ else
116
+ # Test 2
117
+ 'dirty'.should exist_as_file
118
+ end
119
+ end
120
+ it("reuses the same fixture for all examples (1/2)"){ test }
121
+ it("reuses the same fixture for all examples (2/2)"){ test }
122
+ it("calls the init block given"){ 'init.called'.should exist_as_file }
123
+ end
124
+
125
+ context "when :cd_into specified" do
126
+ run_all_in_dynamic_fixture :a, cd_into: 'aa'
127
+ include_examples :cd_with_aa
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ require_relative '../../../bootstrap/spec'
3
+ require 'golly-utils/testing/rspec/arrays'
4
+
5
+ describe 'RSpec array matchers' do
6
+
7
+ context '#equal_array' do
8
+ it("should pass when arrays match exactly"){
9
+ %w[a b c].should equal_array %w[a b c]
10
+ }
11
+
12
+ it("should fail when arrays differ"){
13
+ [
14
+ %w[x b c],
15
+ %w[b c],
16
+ %w[a b],
17
+ %w[a b c x],
18
+ ].each do |v|
19
+ expect{ %w[a b c].should equal_array v }.to raise_error /Missing|Unexpected/
20
+ end
21
+ }
22
+
23
+ it("should require matching amounts of duplicate elements"){
24
+ %w[a a b].should equal_array %w[a a b]
25
+ expect{ %w[a b].should equal_array %w[a a b] }.to raise_error /freq/
26
+ expect{ %w[a b b].should equal_array %w[a a b] }.to raise_error /freq/
27
+ }
28
+
29
+ it("should require arrays to be ordered the same"){
30
+ expect{ %w[a b].should equal_array %w[b a] }.to raise_error /order/
31
+ }
32
+ end
33
+ end
@@ -0,0 +1,300 @@
1
+ # encoding: utf-8
2
+ require_relative '../../../bootstrap/spec'
3
+ require 'golly-utils/testing/rspec/files'
4
+
5
+ TMP_TEST_FILE= '.rubbish.tmp'
6
+
7
+ describe 'RSpec helpers' do
8
+ describe '#run_each_in_empty_dir' do
9
+
10
+ context "with no args" do
11
+ run_each_in_empty_dir
12
+ def test
13
+ get_files.should be_empty
14
+ File.write 'hehe', 'hehe'
15
+ get_files.should_not be_empty
16
+ end
17
+ it("should provide each example with an empty directory (1/2)"){ test }
18
+ it("should provide each example with an empty directory (2/2)"){ test }
19
+ end
20
+
21
+ context "with name" do
22
+ run_each_in_empty_dir 'good'
23
+ it("should provide a directory with the specified name"){
24
+ File.basename(Dir.pwd).should == 'good'
25
+ }
26
+ end
27
+ end
28
+
29
+ describe '#run_all_in_empty_dir' do
30
+ context 'without block' do
31
+ run_all_in_empty_dir
32
+ def test
33
+ if $run_all_in_empty_dir__no_block.nil?
34
+ File.write 'hehe1', 'hehe'
35
+ $run_all_in_empty_dir__no_block= true
36
+ end
37
+ get_files.should == %w[hehe1]
38
+ end
39
+ it("should provide and reuse an empty directory for all examples (1/2)"){ test }
40
+ it("should provide and reuse an empty directory for all examples (2/2)"){ test }
41
+
42
+ end
43
+
44
+ context 'with block' do
45
+ run_all_in_empty_dir do
46
+ File.write 'hehe1', 'hehe'
47
+ end
48
+ def test
49
+ if $run_all_in_empty_dir__block.nil?
50
+ File.write 'hehe2', 'hehe'
51
+ $run_all_in_empty_dir__block= true
52
+ end
53
+ get_files.should == %w[hehe1 hehe2]
54
+ end
55
+ it("should provide and reuse an empty directory for all examples (1/2)"){ test }
56
+ it("should provide and reuse an empty directory for all examples (2/2)"){ test }
57
+ end
58
+
59
+ context "with name" do
60
+ run_all_in_empty_dir 'good'
61
+ it("should provide a directory with the specified name"){
62
+ File.basename(Dir.pwd).should == 'good'
63
+ }
64
+ end
65
+ end
66
+
67
+ describe '#inside_empty_dir' do
68
+ shared_examples "tmp_dir stack" do
69
+ it("should not affect the tmp_dir stack after leaving block"){
70
+ before= (@tmp_dir_stack || []).dup
71
+ old_pwd= Dir.pwd
72
+ inside_empty_dir {
73
+ Dir.pwd.should_not == old_pwd
74
+ get_files().should be_empty
75
+ }
76
+ @tmp_dir_stack.should == before
77
+ }
78
+ end
79
+
80
+ include_examples "tmp_dir stack"
81
+ it("should return the block result"){
82
+ inside_empty_dir{666}.should == 666
83
+ }
84
+
85
+ context 'within run_each_in_empty_dir' do
86
+ run_each_in_empty_dir
87
+ include_examples "tmp_dir stack"
88
+ end
89
+ context 'within run_all_in_empty_dir' do
90
+ run_all_in_empty_dir
91
+ include_examples "tmp_dir stack"
92
+ end
93
+ end
94
+
95
+ describe '#in_tmp_dir?' do
96
+ it("should be false when not in tmp dir"){ in_tmp_dir?.should == false }
97
+ context 'with run_each_in_empty_dir' do
98
+ run_each_in_empty_dir
99
+ it("should be true"){ in_tmp_dir?.should == true }
100
+ end
101
+ context 'with run_all_in_empty_dir' do
102
+ run_all_in_empty_dir
103
+ it("should be true"){ in_tmp_dir?.should == true }
104
+ end
105
+ end
106
+
107
+ describe '#run_each_in_empty_dir_unless_in_one_already' do
108
+ run_each_in_empty_dir_unless_in_one_already
109
+
110
+ context 'when not in an empty dir' do
111
+ def test
112
+ get_files.should be_empty
113
+ unless $golly_07301028
114
+ $golly_07301028= Dir.pwd
115
+ else
116
+ Dir.pwd.should_not == $golly_07301028 # Assert we've been given a different dir
117
+ end
118
+ end
119
+ it("should provide and an empty directory for all examples (1/2)"){ test }
120
+ it("should provide and an empty directory for all examples (2/2)"){ test }
121
+ end
122
+
123
+ context 'with run_all_in_empty_dir' do
124
+ run_all_in_empty_dir
125
+ def test
126
+ get_files.should be_empty
127
+ unless $golly_07301031
128
+ $golly_07301031= Dir.pwd
129
+ else
130
+ Dir.pwd.should == $golly_07301031 # Assert we're in the same dir
131
+ end
132
+ end
133
+ it("should reuse same directory for all examples (1/2)"){ test }
134
+ it("should reuse same directory for all examples (2/2)"){ test }
135
+ end
136
+ end
137
+
138
+ describe '#get_dirs' do
139
+ run_each_in_empty_dir
140
+ it("should return subdirectories without . and ..") {
141
+ get_dirs.should be_empty
142
+ Dir.mkdir 'b'
143
+ Dir.mkdir 'a'
144
+ Dir.mkdir 'a/123'
145
+ get_dirs.should == %w[a a/123 b]
146
+ }
147
+ it("should ignore files") {
148
+ File.write 'asd', 'asd'
149
+ get_dirs.should be_empty
150
+ }
151
+ it("should include directories starting with .") {
152
+ Dir.mkdir '.hehe'
153
+ Dir.mkdir 'm'
154
+ Dir.mkdir 'm/.hi'
155
+ get_dirs.should == %w[.hehe m m/.hi]
156
+ }
157
+ it("should jump into the provided directory") {
158
+ Dir.mkdir 'a'
159
+ Dir.mkdir 'b'
160
+ Dir.mkdir 'a/123'
161
+ get_dirs('a').should == %w[123]
162
+ }
163
+ end
164
+
165
+ end
166
+
167
+ describe 'RSpec matchers' do
168
+ describe '#exist_as_file' do
169
+ run_each_in_empty_dir
170
+
171
+ it("should pass when a file exists"){
172
+ File.write TMP_TEST_FILE, 'blah'
173
+ TMP_TEST_FILE.should exist_as_file
174
+ }
175
+
176
+ it("should fail when a file doesnt exist"){
177
+ expect{
178
+ TMP_TEST_FILE.should exist_as_file
179
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
180
+ }
181
+
182
+ it("should fail when a file is a directory"){
183
+ Dir.mkdir TMP_TEST_FILE
184
+ expect{
185
+ TMP_TEST_FILE.should exist_as_file
186
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
187
+ }
188
+ end
189
+
190
+ describe '#exist_as_dir' do
191
+ run_each_in_empty_dir
192
+
193
+ it("should pass when a dir exists"){
194
+ Dir.mkdir TMP_TEST_FILE
195
+ TMP_TEST_FILE.should exist_as_dir
196
+ }
197
+
198
+ it("should fail when a dir doesnt exist"){
199
+ expect{
200
+ TMP_TEST_FILE.should exist_as_dir
201
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
202
+ }
203
+
204
+ it("should fail when a dir is a file"){
205
+ File.write TMP_TEST_FILE, 'blah'
206
+ expect{
207
+ TMP_TEST_FILE.should exist_as_dir
208
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
209
+ }
210
+ end
211
+
212
+ describe '#be_file_with_contents' do
213
+ run_all_in_empty_dir {
214
+ File.write 'f1', 'abc123'
215
+ }
216
+
217
+ def expect_failure(*args)
218
+ expect{
219
+ TMP_TEST_FILE.should *args
220
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
221
+ end
222
+
223
+ it("should pass if file contents match string"){
224
+ File.write TMP_TEST_FILE, "hehe\n"
225
+ TMP_TEST_FILE.should be_file_with_contents "hehe\n"
226
+ }
227
+ it("should pass if file contents match regex"){
228
+ File.write TMP_TEST_FILE, "omg man"
229
+ TMP_TEST_FILE.should be_file_with_contents /^omg/
230
+ }
231
+ it("should pass if file contents match all given expections"){
232
+ File.write TMP_TEST_FILE, 'omg man 123'
233
+ TMP_TEST_FILE.should be_file_with_contents(/^omg/).and(/123/)
234
+ }
235
+ it("should fail if file contents dont match regex"){
236
+ File.write TMP_TEST_FILE, 'omg man 123'
237
+ expect_failure be_file_with_contents /mann/
238
+ }
239
+ it("should fail if file contents dont match string"){
240
+ File.write TMP_TEST_FILE, 'omg man 123'
241
+ expect_failure be_file_with_contents 'what'
242
+ }
243
+ it("should fail if file contents fail one of multiple expections"){
244
+ File.write TMP_TEST_FILE, 'omg man 123'
245
+ expect_failure be_file_with_contents(/^omg/).and(/1234/)
246
+ expect_failure be_file_with_contents(/^omgx/).and(/123/)
247
+ }
248
+ it("should fail if file doesn't exist"){
249
+ File.delete TMP_TEST_FILE if File.exists? TMP_TEST_FILE
250
+ expect_failure be_file_with_contents //
251
+ }
252
+ it("should normalise file content"){
253
+ File.write TMP_TEST_FILE, "hehe"
254
+ TMP_TEST_FILE.should be_file_with_contents("HEHE").when_normalised_with(&:upcase)
255
+ }
256
+ it("should normalise expectations"){
257
+ File.write TMP_TEST_FILE, "HEHE"
258
+ TMP_TEST_FILE.should be_file_with_contents("hehe").when_normalised_with(&:upcase)
259
+ }
260
+ it("should not try to normalise regex"){
261
+ File.write TMP_TEST_FILE, "hehe"
262
+ TMP_TEST_FILE.should be_file_with_contents(/EH/).when_normalised_with(&:upcase)
263
+ }
264
+ it("should change the meaning of and() when specifying normalisation"){
265
+ File.write TMP_TEST_FILE, "hehe\n"
266
+ TMP_TEST_FILE.should be_file_with_contents('HEHE').when_normalised_with(&:upcase).and(&:chomp)
267
+ }
268
+ it("should fail if file contents match arg provided by and_not()"){
269
+ File.write TMP_TEST_FILE, "abc123\n"
270
+ TMP_TEST_FILE.should be_file_with_contents(/abc/).and_not /wtf/,/man/
271
+ expect_failure be_file_with_contents(/abc/).and_not /123/
272
+ }
273
+ it("should fail if file contents match anything provided by and_not()"){
274
+ File.write TMP_TEST_FILE, "abc123\n"
275
+ expect_failure be_file_with_contents(/abc/).and_not /123/,/man/
276
+ expect_failure be_file_with_contents(/abc/).and_not /wtf/,/123/
277
+ }
278
+
279
+ context "failure message" do
280
+ before(:all){ File.write 'f1', 'abc123' }
281
+
282
+ it("failure msg describes what's missing"){
283
+ expect{ 'f1'.should be_file_with_contents /456/ }.to raise_error /would have/
284
+ expect{ 'f1'.should be_file_with_contents /456/ }.to raise_error /Expected:.*456/
285
+ }
286
+ it("failure msg excludes what's matching"){
287
+ expect{ 'f1'.should be_file_with_contents /[a-z]/,/456/ }.to raise_error /\A[^z]+\z/
288
+ }
289
+ it("failure msg describes what wasn't expected to match"){
290
+ expect{ 'f1'.should be_file_with_contents(/abc/).and_not /123/ }.to raise_error /would not have/
291
+ expect{ 'f1'.should be_file_with_contents(/abc/).and_not /123/ }.to raise_error /Unexpected:.*123/
292
+ }
293
+ it("negative failure msg describes what's matching"){
294
+ expect{ 'f1'.should_not be_file_with_contents /123/ }.to raise_error /would not have/
295
+ expect{ 'f1'.should_not be_file_with_contents /123/ }.to raise_error /Unexpected:.*123/
296
+ }
297
+ end
298
+
299
+ end
300
+ end