svn-command 0.0.3

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.
@@ -0,0 +1,3 @@
1
+ require 'test/unit'
2
+ require File.expand_path(File.dirname(__FILE__)+'/' + 'test_helpers/test_colorizer')
3
+ require File.expand_path(File.dirname(__FILE__)+'/' + 'test_helpers/assertions')
@@ -0,0 +1,56 @@
1
+ # Custom assertions
2
+ class Test::Unit::TestCase
3
+ def assert_user_error(error_message)
4
+ assert_tag({
5
+ :attributes => { :id => "errorExplanation" },
6
+ :descendant => {
7
+ :content => error_message
8
+ }
9
+ })
10
+ end
11
+
12
+ def assert_contains(container, expected_contents, failure_message = nil)
13
+ failure_message = build_message(failure_message, "Container <?> was expected to contain <?> but it didn't", container, expected_contents)
14
+ assert_block(failure_message) do
15
+ container.include?(expected_contents)
16
+ end
17
+ end
18
+
19
+ # Asserts that the block that is passed in causes the value of the specified variable (+variable+) to change.
20
+ # +variable+ should be a Proc that, when evaluated, returns the current value of the variable.
21
+ #
22
+ # Options:
23
+ # * If the optional +:from+ option is supplied, it also asserts that it had that initial value.
24
+ # * If the optional +:to+ option is supplied, it also asserts that it changed _to_ that value.
25
+ #
26
+ # So instead of doing this:
27
+ # assert_equal 1, Model.count
28
+ # do_something_that_should_cause_count_to_increase
29
+ # assert_equal 2, Model.count
30
+ # we can do this:
31
+ # assert_changed(lambda {ErrorType.count}, :from => 1, :to => 2) do
32
+ # do_something_that_should_cause_count_to_increase
33
+ # end
34
+ # Or, if we don't care what it's changing _from_ as long as it increases in value _by_ 1, we can write this:
35
+ # assert_changed(c = lambda {ErrorType.count}, :to => c.call+1) do
36
+ # do_something_that_should_cause_count_to_increase
37
+ # end
38
+ # instead of this:
39
+ # before = Model.count
40
+ # do_something_that_should_cause_count_to_increase
41
+ # assert_equal before + 1, Model.count
42
+ #
43
+ def assert_changed(variable, options = {}, &block)
44
+ expected_from = options.delete(:from) || variable.call
45
+
46
+ assert_equal expected_from, variable.call
47
+
48
+ failure_message = build_message(failure_message, "The variable was expected to change from <?> to <?> but it didn't", variable.call, options.delete(:to) || "something else")
49
+ assert_block(failure_message) do
50
+ before = variable.call
51
+ yield
52
+ expected_to = options.delete(:to) || variable.call
53
+ before != variable.call and variable.call == expected_to
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,106 @@
1
+ require 'rubygems'
2
+ require 'color' # Warning: Make sure you have the *right* color gem! gem install color --source require.errtheblog.com
3
+ module Test::Unit
4
+
5
+ class Error
6
+ # the 'E' that is displayed as the tests are run
7
+ def single_character_display
8
+ "E".red.bold
9
+ end
10
+
11
+ # the long message that is displayed after test is run
12
+ def long_display
13
+ backtrace = filter_backtrace(@exception.backtrace).join("\n ")
14
+ [
15
+ "Error".red.bold,
16
+ ":\n",
17
+ "#@test_name:".white,
18
+ "\n", "#{message}".red,
19
+ "\n #{backtrace}".gsub(/:(\d+):/,":#{'\1'.red}:")
20
+ ].join('')
21
+ end
22
+ end
23
+
24
+
25
+ class Failure
26
+ # the 'E' that is displayed as the tests are run
27
+ def single_character_display
28
+ "F".yellow.bold
29
+ end
30
+
31
+ # the long message that is displayed after test is run
32
+ def long_display
33
+ location_display = if(location.size == 1)
34
+ location[0].sub(/\A(.+:\d+).*/, ' [\\1]')
35
+ else
36
+ "\n [#{location.join("\n ")}]"
37
+ end
38
+ [
39
+ "Failure".yellow.bold,
40
+ ":\n","#@test_name".white,
41
+ "#{location_display}".gsub(/:(\d+)/, ":#{'\1'.yellow}"),
42
+ ":\n", "#@message".yellow
43
+ ].join('')
44
+ end
45
+ end
46
+
47
+ # it is necessary to do a class_eval for the TestRunner class
48
+ # through the AutoRunner class, since the require in the AutoRunner
49
+ # class will overwrite what we do here otherwise.
50
+ #
51
+ # We must do the same thing inside of the TestRunner class
52
+ # class_eval for the TestResult class. We Modify the
53
+ # TestRunnerMediator class after the require is called,
54
+ # which will then modify the TestResult class.
55
+ #
56
+ # test_finished is the function that will output the
57
+ # '.' period during the test runs
58
+ #
59
+ # the to_s for TestResult class returns the string
60
+ # for the final tallied results
61
+ class AutoRunner
62
+ RUNNERS[:console] = proc do |r|
63
+ require 'test/unit/ui/console/testrunner'
64
+ Test::Unit::UI::Console::TestRunner.class_eval %q{
65
+ def test_finished(name)
66
+ output_single('.'.green, 1) unless (@already_outputted)
67
+ nl(3)
68
+ @already_outputted = false
69
+ end
70
+
71
+ def create_mediator(suite)
72
+ require 'test/unit/ui/testrunnermediator'
73
+ Test::Unit::UI::TestRunnerMediator.class_eval %q{
74
+ def create_result
75
+ Test::Unit::TestResult.class_eval %q{
76
+ def to_s
77
+ rc = [
78
+ "#{run_count}".white.bold,
79
+ "tests".white
80
+ ].join(' ')
81
+ ac = [
82
+ "#{assertion_count}".white.bold,
83
+ "assertions".white
84
+ ].join(' ')
85
+ fc = [
86
+ "#{failure_count}".yellow.bold,
87
+ "failures".yellow
88
+ ].join(' ')
89
+ ec = [
90
+ "#{error_count}".red.bold,
91
+ "errors".red
92
+ ].join(' ')
93
+ [rc, ac, fc, ec].join(', ')
94
+ end
95
+ }
96
+ TestResult.new
97
+ end
98
+ }
99
+ return Test::Unit::UI::TestRunnerMediator.new(suite)
100
+ end
101
+ }
102
+ Test::Unit::UI::Console::TestRunner
103
+ end
104
+ end
105
+
106
+ end
@@ -0,0 +1,66 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'subversion_extensions'
3
+
4
+
5
+ class SubversionExtensionsTest < Test::Unit::TestCase
6
+ def setup
7
+ end
8
+
9
+ def test_status_lines_filter
10
+ input = <<End
11
+ M gemables/calculator/test/calculator_test.rb
12
+ X gemables/calculator/tasks/shared
13
+ ? gemables/calculator/lib/calculator_extensions.rb
14
+
15
+ Performing status on external item at 'plugins/flubber/tasks/shared'
16
+
17
+ Performing status on external item at 'applications/underlord/vendor/plugins/nifty'
18
+ X applications/underlord/vendor/plugins/nifty/tasks/shared
19
+ X applications/underlord/vendor/plugins/nifty/doc_include/template
20
+
21
+ Performing status on external item at 'applications/underlord/vendor/plugins/nifty/tasks/shared'
22
+ M applications/underlord/vendor/plugins/nifty/tasks/shared/base.rake
23
+ End
24
+ expected = <<End
25
+ M gemables/calculator/test/calculator_test.rb
26
+ ? gemables/calculator/lib/calculator_extensions.rb
27
+ M applications/underlord/vendor/plugins/nifty/tasks/shared/base.rake
28
+ End
29
+
30
+ assert_equal expected, out = Subversion::Extensions.status_lines_filter( input ), out.inspect
31
+ end
32
+
33
+ def test_update_lines_filter
34
+ input = <<End
35
+ U gemables/calculator/test/calculator_test.rb
36
+ U gemables/calculator/tasks/shared
37
+ U gemables/calculator/lib/calculator_extensions.rb
38
+
39
+ Fetching external item into 'plugins/flubber/tasks/shared'
40
+ U plugins/flubber/tasks/shared/blah.rb
41
+ External at revision 134143078
42
+ End
43
+ expected = <<End
44
+ U gemables/calculator/test/calculator_test.rb
45
+ U gemables/calculator/tasks/shared
46
+ U gemables/calculator/lib/calculator_extensions.rb
47
+ U plugins/flubber/tasks/shared/blah.rb
48
+ End
49
+
50
+ assert_equal expected, out = Subversion::Extensions.update_lines_filter( input ), out.inspect
51
+ end
52
+
53
+ def test_unadded_filter
54
+ input = <<End
55
+ M gemables/calculator/test/calculator_test.rb
56
+ X gemables/calculator/tasks/shared
57
+ ? gemables/calculator/lib/calculator_extensions.rb
58
+ End
59
+ expected = <<End
60
+ ? gemables/calculator/lib/calculator_extensions.rb
61
+ End
62
+
63
+ assert_equal expected, out = Subversion::Extensions.unadded_lines_filter( input ), out.inspect
64
+ assert_equal ['gemables/calculator/lib/calculator_extensions.rb'], out = Subversion::Extensions.unadded_filter( input ), out.inspect
65
+ end
66
+ end
@@ -0,0 +1,99 @@
1
+ $mock_subversion = true
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ class SubversionTest < Test::Unit::TestCase
5
+ def setup
6
+ Subversion.reset_executed
7
+ end
8
+
9
+ def test_add
10
+ Subversion.add('foo', 'bar', 'hello', 'world')
11
+ assert_equal 'svn add foo bar hello world', Subversion.executed.first
12
+ end
13
+
14
+ def test_ignore
15
+ Subversion.ignore('foo', 'some/path/foo')
16
+ assert_equal "svn propset svn:ignore 'foo' ./", Subversion.executed[1]
17
+ assert_equal "svn propset svn:ignore 'foo' some/path", Subversion.executed[3]
18
+ end
19
+
20
+ def test_externalize
21
+ Subversion.externalize('some/repo/path')
22
+ Subversion.externalize('some/repo/path', :as => 'foo')
23
+ Subversion.externalize('some/repo/path', :as => 'foo', :local_path => 'local/path')
24
+
25
+ assert_equal "svn propset svn:externals '#{'path'.ljust(29)} some/repo/path' ./", Subversion.executed[1]
26
+ assert_equal "svn propset svn:externals '#{'foo'.ljust(29)} some/repo/path' ./", Subversion.executed[3]
27
+ assert_equal "svn propset svn:externals '#{'foo'.ljust(29)} some/repo/path' local/path", Subversion.executed[5]
28
+ end
29
+
30
+ def test_remove
31
+ Subversion.remove 'foo', 'bar', 'hello/world'
32
+ assert_equal 'svn rm foo bar hello/world', Subversion.executed.first
33
+ end
34
+
35
+ def test_remove_without_delete
36
+ tmpdir = "tmp#{$$}"
37
+ entries = "#{tmpdir}/.svn/entries"
38
+ FileUtils.mkdir_p "#{tmpdir}/.svn", :mode => 0755
39
+ File.open entries, 'w' do |file|
40
+ file.write <<-EOS
41
+ <?xml version="1.0" encoding="utf-8"?>
42
+ <wc-entries
43
+ xmlns="svn:">
44
+ <entry
45
+ name="existing_file"
46
+ kind="file"/>
47
+ <entry
48
+ name="just_added_file"
49
+ schedule="add"
50
+ kind="file"/>
51
+ <entry
52
+ name="unchanging_file"
53
+ kind="file"/>
54
+ </wc-entries>
55
+ EOS
56
+ end
57
+ File.chmod(0444, entries)
58
+ FileUtils.touch ["#{tmpdir}/existing_file", "#{tmpdir}/just_added_file", "#{tmpdir}/unchanging_file"]
59
+
60
+ begin
61
+ doc = REXML::Document.new(IO.read(entries))
62
+ assert_not_nil REXML::XPath.first(doc, '//entry[@name="existing_file"]')
63
+ Subversion.remove_without_delete "#{tmpdir}/existing_file"
64
+ # the element should now be scheduled for delete
65
+ doc = REXML::Document.new(IO.read(entries))
66
+ assert_not_nil REXML::XPath.first(doc, '//entry[@name="existing_file"][@schedule="delete"]')
67
+
68
+ doc = REXML::Document.new(IO.read(entries))
69
+ assert_not_nil REXML::XPath.first(doc, '//entry[@name="just_added_file"][@schedule="add"]')
70
+ Subversion.remove_without_delete "#{tmpdir}/just_added_file"
71
+ doc = REXML::Document.new(IO.read(entries))
72
+ # the element should now be gone
73
+ assert_nil REXML::XPath.first(doc, '//entry[@name="just_added_file"]')
74
+ ensure
75
+ FileUtils.rm_r tmpdir
76
+ end
77
+ end
78
+
79
+ def test_revert
80
+ Subversion.revert 'foo', 'bar', 'hello/world'
81
+ assert_equal 'svn revert foo bar hello/world', Subversion.executed.first
82
+ end
83
+
84
+ def test_executable
85
+ Subversion.make_executable 'foo', 'bar', 'hello/world'
86
+ assert_equal "svn propset svn:executable '' foo", Subversion.executed[0]
87
+ assert_equal "svn propset svn:executable '' bar", Subversion.executed[1]
88
+ assert_equal "svn propset svn:executable '' hello/world", Subversion.executed[2]
89
+
90
+ Subversion.make_not_executable 'foo'
91
+ assert_equal "svn propdel svn:executable foo", Subversion.executed[3]
92
+ end
93
+
94
+ def test_status
95
+ Subversion.status 'foo'
96
+ assert_equal "svn status foo", Subversion.executed.first
97
+ end
98
+
99
+ end
@@ -0,0 +1,455 @@
1
+ $mock_subversion = true
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+ require_local '../lib/svn_command.rb'
4
+ require 'facets/core/string/to_re'
5
+ require 'yaml'
6
+
7
+
8
+
9
+ module Subversion
10
+ class BaseSvnCommandTest < Test::Unit::TestCase
11
+ def setup
12
+ Subversion.reset_executed
13
+ end
14
+ def test_dummy_test
15
+ # Because it tries to run this base class too!
16
+ end
17
+ end
18
+
19
+ class SvnCommandTest < BaseSvnCommandTest
20
+ def test_invalid_quotes_gives_informative_error
21
+ assert_exception(ArgumentError, lambda { |exception|
22
+ assert_equal "Unmatched single quote: '", exception.message
23
+ }) do
24
+ SvnCommand.execute("foo -m 'stuff''")
25
+ end
26
+ end
27
+ def test_unrecognized_option
28
+ output = capture_output($stderr) do
29
+ assert_exception(SystemExit, lambda { |exception|
30
+ }) do
31
+ SvnCommand.execute("status --blarg")
32
+ end
33
+ end
34
+ assert_match /Unknown option '--blarg'/, output
35
+ end
36
+ end
37
+
38
+ class ArgEscapingTest < BaseSvnCommandTest
39
+ def test_argument_escaping
40
+ SvnCommand.execute( args = %q{commit -m 'a message with lots of !&`$0 |()<> garbage'} )
41
+ assert_equal "svn #{args} --force-log", Subversion.executed.join
42
+ end
43
+ def test_asterisk
44
+ # Don't worry, this'll never happen, because the shell will expand the * *before* it gets to SvnCommand. But if you *did* sneak in an asterisk to SvnCommand.execute somehow, this is what would happen...
45
+ SvnCommand.execute("add dir/* --non-recursive")
46
+ assert_equal "svn add --non-recursive 'dir/*'", Subversion.executed.join
47
+ end
48
+ def test_multiline
49
+ SvnCommand.execute(args = "commit -m 'This is a
50
+ |multi-line
51
+ |message'".margin)
52
+ assert_equal "svn #{args} --force-log", Subversion.executed.join
53
+ end
54
+ end
55
+
56
+ #-----------------------------------------------------------------------------------------------------------------------------
57
+ # Built-in subcommands
58
+
59
+ # Test method_missing. Can we still call svn info, rm, etc. even if we haven't written subcommand modules for them?
60
+ class SubcommandPassThroughTest < BaseSvnCommandTest
61
+ def test_1
62
+ SvnCommand.execute("rm -q file1 file2 --force")
63
+ assert_equal "svn rm -q file1 file2 --force", Subversion.executed.join
64
+ end
65
+ def test_2
66
+ SvnCommand.execute("info -q file1 file2 --force")
67
+ assert_equal "svn info -q file1 file2 --force", Subversion.executed.join
68
+ end
69
+ end
70
+
71
+ class SvnAddTest < BaseSvnCommandTest
72
+ def test_1
73
+ end
74
+ def test_2
75
+ SvnCommand.execute('add "a b"')
76
+ assert_equal "svn add 'a b'", Subversion.executed.join
77
+ end
78
+ def test_3
79
+ SvnCommand.execute('add a b')
80
+ assert_equal "svn add a b", Subversion.executed.join
81
+ end
82
+ end
83
+
84
+ class SvnCommitTest < BaseSvnCommandTest
85
+ def test_1
86
+ SvnCommand.execute("commit -m 'just an ordinary commit message!'")
87
+ assert_equal "svn commit -m 'just an ordinary commit message!' --force-log", Subversion.executed.join
88
+ end
89
+ def test_lots_of_options
90
+ SvnCommand.execute("commit --non-recursive -q -m '' --targets some_file ")
91
+ assert_equal "svn commit --non-recursive -q -m '' --targets some_file --force-log", Subversion.executed.join
92
+ end
93
+ def test_that_complex_quoting_doesnt_confuse_it
94
+ original_message = "Can't decide how many \"'quotes'\" to use!"
95
+ SvnCommand.execute(%Q{commit -m "#{original_message.gsub('"', '\"')}"})
96
+
97
+ expected_escaped_part = %q{'Can'\\''t decide how many "'\\''quotes'\\''" to use!'}
98
+ assert_equal "svn commit -m #{expected_escaped_part} --force-log", Subversion.executed.join
99
+ assert_equal original_message, `echo #{expected_escaped_part}`.chomp # We should have gotten back exactly what we put in originally
100
+ end
101
+ end
102
+
103
+ class SvnDiffTest < BaseSvnCommandTest
104
+ def test_1
105
+ SvnCommand.execute("diff -r 123:125")
106
+ assert_equal [
107
+ "svn diff --diff-cmd colordiff ./ -r 123:125",
108
+ "svn status ./"
109
+ ], Subversion.executed
110
+ end
111
+ def test_2
112
+ #:fixme:
113
+ #capture_output { SvnCommand.execute("diff -r { 2006-07-01 }") }
114
+ #p Subversion.executed
115
+ # Currently does this, since it thinks the arity is 1: --diff-cmd colordiff 2006-07-01 } -r '{'
116
+ #assert_equal "svn diff --diff-cmd colordiff -r { 2006-07-01 }", Subversion.executed.join
117
+ end
118
+ end
119
+
120
+ class SvnHelpTest < BaseSvnCommandTest
121
+ def test_1
122
+ output = capture_output { SvnCommand.execute("help") }
123
+ assert_equal "svn help ", Subversion.executed.join
124
+ assert_match /wrapper/, output
125
+ end
126
+ end
127
+
128
+ class SvnLogTest < BaseSvnCommandTest
129
+ def test_1
130
+ capture_output { SvnCommand.execute("log") }
131
+ assert_equal "svn log ", Subversion.executed.join
132
+ end
133
+ end
134
+
135
+ class SvnStatusTest < BaseSvnCommandTest
136
+ # Duplicates a test in subversion_extensions_test.rb -- maybe can abbreviate this and leave the detailed filter tests to the other TestCase
137
+ def test_status_does_some_filtering
138
+ Subversion.stubs(:status).returns("
139
+ M gemables/calculator/test/calculator_test.rb
140
+ X gemables/calculator/tasks/shared
141
+ ? gemables/calculator/lib/calculator_extensions.rb
142
+
143
+ Performing status on external item at 'plugins/flubber/tasks/shared'
144
+
145
+ Performing status on external item at 'applications/underlord/vendor/plugins/nifty'
146
+ X applications/underlord/vendor/plugins/nifty/tasks/shared
147
+ X applications/underlord/vendor/plugins/nifty/lib/calculator
148
+ X applications/underlord/vendor/plugins/nifty/doc_include/template
149
+
150
+ Performing status on external item at 'applications/underlord/vendor/plugins/nifty/tasks/shared'
151
+ M applications/underlord/vendor/plugins/nifty/tasks/shared/base.rake
152
+ ")
153
+
154
+ expected = <<End
155
+ M gemables/calculator/test/calculator_test.rb
156
+ ? gemables/calculator/lib/calculator_extensions.rb
157
+ M applications/underlord/vendor/plugins/nifty/tasks/shared/base.rake
158
+ End
159
+
160
+ assert_equal expected, out = capture_output { Subversion::SvnCommand.execute('st') }
161
+ end
162
+
163
+ def test_status_accepts_arguments
164
+ SvnCommand.execute('st -u /path/to/file1 file2')
165
+ assert_equal "svn status -u /path/to/file1 file2", Subversion.executed.join
166
+
167
+ Subversion.reset_executed
168
+ SvnCommand.execute('st dir --no-ignore')
169
+ # It will reorder some of the args (it puts all pass-through options and their args at the *beginning*), but that's okay...
170
+ assert_equal "svn status --no-ignore dir", Subversion.executed.join
171
+
172
+ end
173
+ end #class SvnStatusTest
174
+
175
+ class SvnUpdateTest < BaseSvnCommandTest
176
+ def test_1
177
+ capture_output { SvnCommand.execute("up -q file1 file2 -r 17") }
178
+ assert_equal "svn update -q -r 17 file1 file2", Subversion.executed.join
179
+ end
180
+ end
181
+
182
+ #-----------------------------------------------------------------------------------------------------------------------------
183
+ # Custom subcommands
184
+
185
+ #-----------------------------------------------------------------------------------------------------------------------------
186
+ class SvnEachUnaddedTest < BaseSvnCommandTest
187
+ def setup
188
+ super
189
+ Subversion.stubs(:status).returns("
190
+ M gemables/calculator/test/calculator_test.rb
191
+ X gemables/calculator/tasks/shared
192
+ ? gemables/calculator/lib/calculator.rb
193
+ ")
194
+ FileUtils.mkdir_p('gemables/calculator/lib/')
195
+ File.open(@filename = 'gemables/calculator/lib/calculator.rb', 'w') do |file|
196
+ file.puts "line 1 of calculator.rb"
197
+ end
198
+ end
199
+ def teardown
200
+ file = 'gemables/calculator/lib/calculator.rb'
201
+ FileUtils.rm(file) if File.exist?(file)
202
+ FileUtils.rmdir('gemables/calculator/lib/')
203
+ FileUtils.rmdir('gemables/calculator/')
204
+ FileUtils.rmdir('gemables/')
205
+ end
206
+
207
+ def test_add
208
+ output = simulate_input('a') do
209
+ capture_output { SvnCommand.execute('each_unadded dir') }
210
+ end
211
+ assert_match /What do you want to do with .*calculator\.rb/, output
212
+ assert_match /Adding/, output
213
+ assert_equal "svn add gemables/calculator/lib/calculator.rb", Subversion.executed.join
214
+ end
215
+ def test_ignore
216
+ output = simulate_input('i') do
217
+ capture_output { SvnCommand.execute('each_unadded dir') }
218
+ end
219
+ assert_match /What do you want to do with .*calculator\.rb/, output
220
+ assert_match /Ignoring/, output
221
+ assert_equal [
222
+ "svn propget svn:ignore gemables/calculator/lib",
223
+ "svn propset svn:ignore 'calculator.rb' gemables/calculator/lib"
224
+ ], Subversion.executed
225
+ end
226
+ def test_preview_is_now_automatic
227
+ output = simulate_input(
228
+ #"p" + # Preview
229
+ "\n" # Blank line to do nothing (and exit loop)
230
+ ) do
231
+ capture_output { SvnCommand.execute('each_unadded dir') }
232
+ end
233
+ assert_match /What do you want to do with .*calculator\.rb/, output
234
+ assert_match "line 1 of calculator.rb".to_re, output
235
+ end
236
+ def test_delete
237
+ assert File.exist?( @filename )
238
+ output = simulate_input(
239
+ 'd' + # Delete
240
+ 'y' # Yes I'm sure
241
+ ) do
242
+ capture_output { SvnCommand.execute('each_unadded dir') }
243
+ end
244
+ assert_match /What do you want to do with .*calculator\.rb/, output
245
+ assert_match "Are you pretty much".to_re, output
246
+ assert_match /Deleting/, output
247
+ #print output
248
+ assert !File.exist?( @filename )
249
+ end
250
+ end #class
251
+
252
+ #-----------------------------------------------------------------------------------------------------------------------------
253
+ # Ignore
254
+ class SvnIgnoreTest < BaseSvnCommandTest
255
+ def test_svn_ignore_relative_to_wd
256
+ output = capture_output { SvnCommand.execute('ignore log') }
257
+ assert_equal '', output
258
+ assert_equal [
259
+ "svn propget svn:ignore ./",
260
+ "svn propset svn:ignore 'log' ./"
261
+ ], Subversion.executed
262
+ end
263
+ def test_svn_ignore_relative_to_other_path
264
+ output = capture_output { SvnCommand.execute('ignore log/*') }
265
+ assert_equal '', output
266
+ assert_equal [
267
+ "svn propget svn:ignore log",
268
+ "svn propset svn:ignore '*' log"
269
+ ], Subversion.executed
270
+ end
271
+ end
272
+
273
+ #-----------------------------------------------------------------------------------------------------------------------------
274
+ # Externals
275
+
276
+ # Since this doesn't work: Subversion::SvnCommand.any_instance.stubs(:system).returns(Proc.new {|a| p a; puts "Tried to call system(#{a})" })
277
+ class Subversion::SvnCommand
278
+ def system(*args)
279
+ Subversion::SvnCommand.executed_system << args.join(' ')
280
+ end
281
+ def self.executed_system
282
+ @@executed_system ||= []
283
+ end
284
+ def self.reset_executed_system(as = [])
285
+ @@executed_system = as
286
+ end
287
+ end
288
+
289
+ class SvnExternalsTest < BaseSvnCommandTest
290
+
291
+ # Causes .stub to break??
292
+ #def setup
293
+ #end
294
+ def set_up_stubs # This ought to just go in the normal "setup", but that caused weird errors. Ideas?
295
+ yaml = %q{
296
+ - !ruby/object:Subversion::ExternalsContainer
297
+ container_dir: /home/tyler/code/gemables/svn-command/test
298
+ entries: |+
299
+ shared http://code.qualitysmith.com/gemables/test_extensions/lib
300
+
301
+ - !ruby/object:Subversion::ExternalsContainer
302
+ container_dir: /home/tyler/code/gemables/svn-command/tasks
303
+ entries: |+
304
+ shared http://code.qualitysmith.com/gemables/shared_tasks/tasks
305
+
306
+ - !ruby/object:Subversion::ExternalsContainer
307
+ container_dir: /home/tyler/code/gemables/svn-command/doc_include
308
+ entries: |+
309
+ template http://code.qualitysmith.com/gemables/template/doc/template
310
+ }
311
+ external_containers = YAML.load yaml
312
+ Subversion.stubs(:externals_containers).returns(external_containers)
313
+ end
314
+
315
+ def test_svn_externalize
316
+ set_up_stubs
317
+ output = capture_output { SvnCommand.execute('externalize http://imaginethat.com/a/repo') }
318
+ assert_equal '', output
319
+ assert_equal [
320
+ "svn propget svn:externals ./",
321
+ "svn propset svn:externals 'repo http://imaginethat.com/a/repo' ./"
322
+ ], Subversion.executed
323
+ end
324
+
325
+
326
+ def test_svn_externals
327
+ set_up_stubs
328
+ output = capture_output { SvnCommand.execute('externals') }
329
+
330
+ assert_contains output, %q(
331
+ |/home/tyler/code/gemables/svn-command/test
332
+ | * shared http://code.qualitysmith.com/gemables/test_extensions/lib
333
+ |/home/tyler/code/gemables/svn-command/tasks
334
+ | * shared http://code.qualitysmith.com/gemables/shared_tasks/tasks
335
+ |/home/tyler/code/gemables/svn-command/doc_include
336
+ | * template http://code.qualitysmith.com/gemables/template/doc/template
337
+ ).margin
338
+ assert_equal [], Subversion.executed
339
+ end
340
+
341
+ def test_svn_externals_containers
342
+ set_up_stubs
343
+ output = capture_output { SvnCommand.execute('externals_containers') }
344
+
345
+ assert_contains output, %q(
346
+ |/home/tyler/code/gemables/svn-command/test
347
+ |/home/tyler/code/gemables/svn-command/tasks
348
+ |/home/tyler/code/gemables/svn-command/doc_include
349
+ ).margin
350
+ assert_equal [], Subversion.executed
351
+ end
352
+
353
+ def test_svn_edit_externals
354
+ set_up_stubs
355
+ output = simulate_input('yyy') do
356
+ capture_output { SvnCommand.execute('edit_externals') }
357
+ end
358
+ assert_match "No directory specified. Editing externals for *all*".to_re, output
359
+
360
+ assert_match /Do you want to edit svn:externals for this directory/, output
361
+ assert_equal [
362
+ "svn propedit svn:externals /home/tyler/code/gemables/svn-command/test",
363
+ "svn propedit svn:externals /home/tyler/code/gemables/svn-command/tasks",
364
+ "svn propedit svn:externals /home/tyler/code/gemables/svn-command/doc_include"
365
+ ], Subversion::SvnCommand.executed_system
366
+ end
367
+ end
368
+
369
+ #-----------------------------------------------------------------------------------------------------------------------------
370
+ # Commit messages
371
+
372
+ class SvnGetMessageTest < BaseSvnCommandTest
373
+ def test_1
374
+ Subversion.stubs(:status_against_server).returns("Status against revision: 56")
375
+ output = simulate_input('i') do
376
+ capture_output { SvnCommand.execute('get_message') }
377
+ end
378
+ assert_match "Message for r56 :".to_re, output
379
+ assert_equal ["svn propget --revprop svn:log -r head"], Subversion.executed
380
+ end
381
+ end
382
+
383
+ class SvnSetMessageTest < BaseSvnCommandTest
384
+ def test_1
385
+ Subversion.stubs(:status_against_server).returns("Status against revision: 56")
386
+ output = simulate_input('i') do
387
+ capture_output { SvnCommand.execute('set_message "this is my message"') }
388
+ end
389
+ assert_match "Message before changing:".to_re, output
390
+ assert_match "Message for r56 :".to_re, output
391
+ assert_equal [
392
+ "svn propget --revprop svn:log -r head",
393
+ "svn propset --revprop svn:log -r head 'this is my message'"
394
+ ], Subversion.executed
395
+ end
396
+ end
397
+
398
+ class SvnEditMessageTest < BaseSvnCommandTest
399
+ def test_1
400
+ Subversion.stubs(:status_against_server).returns("Status against revision: 56")
401
+ output = simulate_input('i') do
402
+ capture_output { SvnCommand.execute('edit_message') }
403
+ end
404
+ assert_equal ["svn propedit --revprop svn:log -r head"], Subversion.executed
405
+ end
406
+ end
407
+
408
+ #-----------------------------------------------------------------------------------------------------------------------------
409
+
410
+ class SvnViewCommitsTest < BaseSvnCommandTest
411
+ def test_parse_revision_ranges
412
+ assert_equal [134], SvnCommand.parse_revision_ranges(["134"])
413
+ assert_equal [134, 135, 136], SvnCommand.parse_revision_ranges(["134-136"])
414
+ assert_equal [134, 135, 136], SvnCommand.parse_revision_ranges(["134:136"])
415
+ assert_equal [134, 135, 136], SvnCommand.parse_revision_ranges(["134..136"])
416
+ assert_equal [134, 135, 136, 139], SvnCommand.parse_revision_ranges(["134-136", "139"])
417
+ end
418
+ def test_1
419
+ messages = Dictionary[
420
+ 14, "Committed a bunch of really important stuff.",
421
+ 15, "Fixed a typo.",
422
+ 30, "Injected a horrible defect."
423
+ ]
424
+ Subversion.stubs(:log).with("-r 14 -v ").returns(messages[14])
425
+ Subversion.stubs(:log).with("-r 15 -v ").returns(messages[15])
426
+ Subversion.stubs(:log).with("-r 30 -v ").returns(messages[30])
427
+ Subversion.stubs(:diff).returns(combined_diff = %q(
428
+ |Index: lib/svn_command.rb
429
+ |===================================================================
430
+ |--- lib/svn_command.rb (revision 2327)
431
+ |+++ lib/svn_command.rb (revision 2342)
432
+ |@@ -3,9 +3,11 @@
433
+ | require 'facets/more/command'
434
+ | require 'facets/core/string/margin'
435
+ | require 'facets/core/kernel/require_local'
436
+ |+require 'extensions/symbol'
437
+ | require 'pp'
438
+ | require 'termios'
439
+ | require 'stringio'
440
+ |+require 'escape' # http://www.a-k-r.org/escape/
441
+ ).margin)
442
+ output = capture_output { SvnCommand.execute('view-commits -r 14:15 30') }
443
+ assert_equal %Q(
444
+ |#{messages.values.join("\n")}
445
+ |#{combined_diff}
446
+ |
447
+ ).margin, output
448
+ end
449
+ end
450
+
451
+
452
+ #-----------------------------------------------------------------------------------------------------------------------------
453
+ end #module Subversion
454
+
455
+