rleber-textmate 0.9.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,91 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe TextMateBundleManager do
4
+ describe "locations" do
5
+
6
+ def run_locations
7
+ @location_list = capture(:stdout) { TextMateBundleManager.start(["locations"]) }.split("\n").map{|line| line.strip.split(/\s{2,}/)}
8
+ end
9
+
10
+ def locations_for_zone(zone)
11
+ @location_list.select {|l| l[0] == zone}.map{|l| l[1]}
12
+ end
13
+
14
+ context "with stubbed locations" do
15
+ before :each do
16
+ stub_github_user "foo"
17
+ stub_remote_locations
18
+ stub_local_locations
19
+ run_locations
20
+ end
21
+
22
+ it "lists locations beginning with column titles" do
23
+ @location_list.first.should == %w{Zone Short Name Location}
24
+ end
25
+
26
+ it "lists all the locations" do
27
+ @location_list.shift
28
+ @location_list.size.should == 9 # 4 "standard" overridden remote locations, plus 5 "standard" overridden local locations
29
+ end
30
+
31
+ it "lists all location information" do
32
+ @location_list[1].size.should == 4
33
+ end
34
+
35
+ it "lists local locations before remote ones" do
36
+ list = @location_list[1..-1].map {|l| l[0]}
37
+ compressed_list = []
38
+ last_element = nil
39
+ list.each do |l|
40
+ compressed_list << l if l != last_element
41
+ last_element = l
42
+ end
43
+ compressed_list.should == %w{Local Remote}
44
+ end
45
+
46
+ it "lists all local locations from highest to lowest precedence" do
47
+ locations_for_zone('Local').should == %w{user user_p system system_p app}
48
+ end
49
+
50
+ it "lists all remote locations from highest to lowest precedence" do
51
+ locations_for_zone('Remote').should == %w{personal github trunk review}
52
+ end
53
+
54
+ it "lists the correct location fields" do
55
+ @location_list[1].should == %w{Local user User User\ path}
56
+ end
57
+
58
+ it "always has 4 columns" do
59
+ @location_list.should always_have_n_columns(4)
60
+ end
61
+ end
62
+
63
+ context "when github_user is not defined" do
64
+ before :each do
65
+ stub_github_user nil
66
+ run_locations
67
+ end
68
+
69
+ it "does not include a personal github location" do
70
+ @location_list.map{|l| l[1]}.should_not include('personal')
71
+ end
72
+ end
73
+
74
+ context "when github_user is defined" do
75
+ before :each do
76
+ stub_github_user "foo"
77
+ run_locations
78
+ end
79
+
80
+ it "includes a personal github location" do
81
+ @location_list.map{|l| l[1]}.should include('personal')
82
+ end
83
+
84
+ it "sets github url to include 'foo'" do
85
+ l = @location_list.find {|l| l[1] == "personal" }
86
+ l.should_not be_nil
87
+ l[3].should match(/foo/)
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,394 @@
1
+ $TESTING=true
2
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'rspec'
5
+ require 'textmate'
6
+ require 'pp'
7
+ require 'mocha'
8
+
9
+ RSPEC_REMOTE_LOCATIONS = [
10
+ {:name => :'Personal', :short => :personal, :scm => :github, :path => 'Personal path'},
11
+ {:name => :'GitHub', :short => :github, :scm => :github, :path => 'Github path'},
12
+ {:name => :'Macromates Trunk', :short => :trunk, :scm => :svn, :path => 'Trunk path'},
13
+ {:name => :'Macromates Review', :short => :review, :scm => :svn, :path => 'Macromates Review path'},
14
+ ]
15
+
16
+ RSPEC_LOCAL_LOCATIONS = [
17
+ {:name => :User, :short=>:user, :path=>"User path"},
18
+ {:name => :'User Pristine', :short=>:user_p, :path=>"User Pristine path"},
19
+ {:name => :System, :short=>:system, :path=>'System path'},
20
+ {:name => :'System Pristine', :short=>:system_p, :path=>'System Pristine path'},
21
+ {:name => :Application, :short=>:app, :path=>"Application path"},
22
+ ]
23
+
24
+ RSPEC_REMOTE_BUNDLES = {
25
+ }
26
+
27
+
28
+ RSPEC_LOCAL_BUNDLES = {
29
+ :user => [
30
+ {:name=>"user_bundle1"},
31
+ {:name=>"user_bundle2"},
32
+ ]
33
+ }
34
+
35
+ class String
36
+ def blank?
37
+ !!(self =~ /^\s*$/)
38
+ end
39
+ end
40
+
41
+ # A hack:
42
+ # Disable Thor [WARNING] Attempted to create task "..." without usage or description
43
+ class Mocha::AnyInstanceMethod
44
+ alias original_define_new_method define_new_method
45
+ def define_new_method
46
+ if stubbee <= Thor
47
+ stubbee.class_eval(%{
48
+ no_tasks do
49
+ def #{method}(*args, &block)
50
+ self.class.any_instance.mocha.method_missing(:#{method}, *args, &block)
51
+ end
52
+ end
53
+ }, __FILE__, __LINE__)
54
+ else
55
+ original_define_new_method
56
+ end
57
+ end
58
+ end
59
+
60
+ # def stub_local_bundles(bundles=nil)
61
+ # stub_local_locations
62
+ # bundles ||= RSPEC_LOCAL_BUNDLES
63
+ #
64
+ # TextMateBundleManager.class_eval <<-END
65
+ # private
66
+ #
67
+ # def bundle_status_table
68
+ # @bundle_status_table ||= #{bundles.inspect}
69
+ # end
70
+ #
71
+ # def bundle_status(path)
72
+ # basename = File.basename(path, '.*')
73
+ # res = {}
74
+ # bundles = get_local_bundle_details(File.dirname(path))
75
+ # if bundles
76
+ # res = bundles.find {|b| File.basename(b[:name], '.*') == basename }
77
+ # res ||= {}
78
+ # end
79
+ # res
80
+ # end
81
+ #
82
+ # def get_local_bundle_details(path)
83
+ # l = find_local_location_by(:path, path)
84
+ # return [] unless l
85
+ # bundles = bundle_status_table[l[:short]]
86
+ # return [] unless bundles
87
+ # bundles
88
+ # end
89
+ #
90
+ # def get_local_bundles(path)
91
+ # get_local_bundle_details(path).map {|b| b[:name] + '.tmbundle'}
92
+ # end
93
+ # END
94
+ # end
95
+
96
+ RSpec.configure do |config|
97
+ config.mock_framework = :mocha
98
+
99
+ def capture(stream)
100
+ begin
101
+ stream = stream.to_s
102
+ eval "$#{stream} = StringIO.new"
103
+ yield
104
+ result = eval("$#{stream}").string
105
+ ensure
106
+ eval("$#{stream} = #{stream.upcase}")
107
+ end
108
+
109
+ result
110
+ end
111
+ alias :silence :capture
112
+
113
+ def stub_github_user(user)
114
+ TextMateBundleManager.any_instance.stubs(:current_github_user).returns(user)
115
+ end
116
+
117
+ def stub_local_locations(location_specs=nil)
118
+ location_specs ||= RSPEC_LOCAL_LOCATIONS
119
+ TextMateBundleManager.any_instance.stubs(:local_locations).returns(location_specs)
120
+ location_specs
121
+ end
122
+
123
+ def stub_remote_locations(location_specs=nil)
124
+ location_specs ||= RSPEC_REMOTE_LOCATIONS
125
+ TextMateBundleManager.any_instance.stubs(:remote_locations).returns(location_specs)
126
+ location_specs
127
+ end
128
+
129
+ def bundle_details_by_path(locations, bundles)
130
+ locations.inject({}) do |hsh, l|
131
+ location_bundles = bundles[l[:short]]
132
+ hsh[l[:path]] = location_bundles if location_bundles && location_bundles.size > 0
133
+ hsh
134
+ end
135
+ end
136
+
137
+ def bundle_status_table_for(locations, bundles)
138
+ bundle_status_table = {}
139
+ bundle_details_by_path(locations, bundles).each do |path, bundle_detail_array|
140
+ bundle_detail_array.each do |bundle_detail|
141
+ name = bundle_detail[:name]
142
+ name += '.tmbundle' unless name =~ /\./
143
+ bundle_status_table[File.join(path, name)] = bundle_detail
144
+ end
145
+ end
146
+ bundle_status_table
147
+ end
148
+
149
+ def bundle_names_by_path(locations, bundles)
150
+ bundle_names_table = {}
151
+ bundle_details_by_path(locations, bundles).each do |path, bundle_detail_array|
152
+ bundle_names_table[path] = bundle_detail_array.map do |b|
153
+ name = b[:name]
154
+ name += '.tmbundle' unless name =~ /\./
155
+ name
156
+ end
157
+ end
158
+ bundle_names_table
159
+ end
160
+
161
+ def stub_remote_bundles(locations=nil,bundles=nil)
162
+ locs = stub_remote_locations(locations)
163
+ bundles ||= RSPEC_REMOTE_BUNDLES
164
+
165
+ # A total hack, but the only way I can figure out to make this work...
166
+ TextMateBundleManager.class_eval <<-END
167
+ no_tasks do
168
+ def get_remote_bundles(path)
169
+ #{bundle_names_by_path(locs, bundles).inspect}[path] || []
170
+ end
171
+ END
172
+ end
173
+
174
+ def stub_local_bundles(locations=nil, bundles=nil)
175
+ locs = stub_local_locations(locations)
176
+ bundles ||= RSPEC_LOCAL_BUNDLES
177
+
178
+ # A total hack, but the only way I can figure out to make this work...
179
+ TextMateBundleManager.class_eval <<-END
180
+ no_tasks do
181
+ def get_local_bundles(path)
182
+ #{bundle_names_by_path(locs, bundles).inspect}[path] || []
183
+ end
184
+
185
+ def bundle_status(path)
186
+ #{bundle_status_table_for(locs, bundles).inspect}[path] || {}
187
+ end
188
+ end
189
+ END
190
+ end
191
+
192
+ module CustomMatchers
193
+
194
+ class ArrayRowMatcher
195
+ def initialize(expected)
196
+ @expected = expected
197
+ end
198
+
199
+ def matches?(actual)
200
+ matches_all?(actual)
201
+ end
202
+
203
+ def matches_all?(actual)
204
+ @actual = actual
205
+ failed = false
206
+ actual.each do |row|
207
+ return false unless matches_row?(row)
208
+ end
209
+ return true
210
+ end
211
+
212
+ def matches_row?(row)
213
+ raise "#{self}#matches_row? not implemented"
214
+ end
215
+
216
+ def format_row_groups(rows)
217
+ last_row = -1
218
+ row_groups = []
219
+ rows.each do |row|
220
+ if row == last_row + 1
221
+ if row_groups.size == 0 # Shouldn't happen, but why not?
222
+ row_groups << [row, row]
223
+ else
224
+ last_group = row_groups.pop
225
+ row_groups << [last_group.first, row]
226
+ end
227
+ else
228
+ row_groups << [row, row]
229
+ end
230
+ last_row = row
231
+ end
232
+ formatted_groups = row_groups.map do |group|
233
+ if group.first == group.last
234
+ group.first.to_s
235
+ else
236
+ "#{group.first}..#{group.last}"
237
+ end
238
+ end
239
+ formatted_rows = formatted_groups.join(',')
240
+ end
241
+
242
+ def classify_rows
243
+ bad_rows = []
244
+ good_rows = []
245
+ @actual.each_with_index do |row, i|
246
+ if matches_row?(row)
247
+ good_rows << i
248
+ else
249
+ bad_rows << i
250
+ end
251
+ end
252
+ [good_rows, bad_rows]
253
+ end
254
+ end
255
+
256
+ class AlwaysHasNColumns < ArrayRowMatcher
257
+
258
+ def column_counts
259
+ @actual.map {|row| row.size }
260
+ end
261
+
262
+ def max_columns
263
+ column_counts.max
264
+ end
265
+
266
+ def min_columns
267
+ column_counts.min
268
+ end
269
+
270
+ def matches_row?(row)
271
+ @expected == row.size
272
+ end
273
+
274
+ def failure_message_for_should
275
+ max = max_columns
276
+ min = min_columns
277
+ good_rows, bad_rows = classify_rows
278
+ if max == min
279
+ "expected table to have #{@expected} columns. It actually has #{min} columns. Row[0]=#{@actual[0].inspect}\n"
280
+ elsif bad_rows.size > 0
281
+ msg = "expected table to have #{@expected} columns. It actually has #{min}..#{max} columns.\n" \
282
+ "Bad rows: #{format_row_groups(bad_rows)}\n" \
283
+ "Row[#{bad_rows[0]}] is bad, for instance: #{@actual[bad_rows[0]].inspect}"
284
+ if good_rows.size > 0
285
+ good_rows_msg = "\nGood rows: #{format_row_groups(good_rows)}\n" \
286
+ "Row[#{good_rows[0]}] is good, for instance: #{@actual[good_rows[0]].inspect}"
287
+ else
288
+ good_rows_msg = "\nNo good rows"
289
+ end
290
+ msg << good_rows_msg
291
+ else
292
+ "expected table to have #{@expected} columns. It actually has #{min}..#{max} columns, but I can't find a bad row."
293
+ end
294
+ end
295
+
296
+ def failure_message_for_should_not
297
+ max = max_columns
298
+ min = min_columns
299
+ if max == min
300
+ "expected table not to have #{@expected} columns, but it does. Row[0]=#{@actual[0].inspect}\n"
301
+ else
302
+ "expected table not to have #{@expected} columns. It actually has #{min}..#{max} columns, which shouldn't have caused this example to fail."
303
+ end
304
+ end
305
+ end
306
+
307
+ def always_have_n_columns(expected)
308
+ AlwaysHasNColumns.new(expected)
309
+ end
310
+
311
+ class AlwaysMatcher < ArrayRowMatcher
312
+
313
+ def matches_row?(row)
314
+ row.match(@expected)
315
+ end
316
+
317
+ def failure_message_for_should
318
+ good_rows, bad_rows = classify_rows
319
+ msg = "expected rows of table to always match #{@expected.inspect}, but it doesn't."
320
+ if bad_rows.size > 0
321
+ msg << "\nBad rows: #{format_row_groups(bad_rows)}" \
322
+ "\nRow[#{bad_rows[0]}] is bad, for instance: #{@actual[bad_rows[0]].inspect}"
323
+ else
324
+ msg << "\nNo bad rows."
325
+ end
326
+ if good_rows.size > 0
327
+ msg << "\nGood rows: #{format_row_groups(good_rows)}" \
328
+ "\nRow[#{good_rows[0]}] is good, for instance: #{@actual[good_rows[0]].inspect}"
329
+ else
330
+ msg << "\nNo good rows"
331
+ end
332
+ msg
333
+ end
334
+
335
+ def failure_message_for_should_not
336
+ "expected rows of table to never match #{@expected.inspect}, but they do. Row[0]=#{@actual[0].inspect}"
337
+ end
338
+ end
339
+
340
+ def always_match(expected)
341
+ AlwaysMatcher.new(expected)
342
+ end
343
+
344
+ class AlwaysColumnMatcher < ArrayRowMatcher
345
+
346
+ def initialize(n, match)
347
+ super(match)
348
+ @n = n
349
+ end
350
+
351
+ def matches_row?(row)
352
+ # puts "Checking row: #{format_row(row)}"
353
+ row[@n].match(@expected)
354
+ end
355
+
356
+ def format_row(row)
357
+ res = []
358
+ row.each_with_index do |cell, i|
359
+ res << (i==@n ? "<<#{cell.inspect}>>" : cell.inspect)
360
+ end
361
+ "[#{res.join(',')}]"
362
+ end
363
+
364
+ def failure_message_for_should
365
+ good_rows, bad_rows = classify_rows
366
+ msg = "expected column #{@n} of table to always match #{@expected.inspect}, but it doesn't."
367
+ if bad_rows.size > 0
368
+ msg << "\nBad rows: #{format_row_groups(bad_rows)}" \
369
+ "\nRow[#{bad_rows[0]}] is bad, for instance: #{format_row(@actual[bad_rows[0]])}"
370
+ else
371
+ msg << "\nNo bad rows."
372
+ end
373
+ if good_rows.size > 0
374
+ msg << "\nGood rows: #{format_row_groups(good_rows)}" \
375
+ "\nRow[#{good_rows[0]}] is good, for instance: #{format_row(@actual[good_rows[0]])}"
376
+ else
377
+ msg << "\nNo good rows"
378
+ end
379
+ msg
380
+ end
381
+
382
+ def failure_message_for_should_not
383
+ "expected column #{@n} of table to never match #{@expected.inspect}, but they do. Row[0]=#{format_row(@actual[0])}"
384
+ end
385
+ end
386
+
387
+ def always_match_in_column(n, match)
388
+ AlwaysColumnMatcher.new(n, match)
389
+ end
390
+
391
+ end
392
+ config.include(CustomMatchers)
393
+
394
+ end