ggem 1.7.0 → 1.8.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.
@@ -0,0 +1,1012 @@
1
+ require 'assert'
2
+ require 'ggem/cli'
3
+
4
+ require 'ggem/cli/clirb'
5
+ require 'ggem/cli/commands'
6
+ require 'ggem/gem'
7
+ require 'ggem/gemspec'
8
+ require 'ggem/git_repo'
9
+ require 'much-plugin'
10
+
11
+ class GGem::CLI
12
+
13
+ class UnitTests < Assert::Context
14
+ desc "GGem::CLI"
15
+ setup do
16
+ @cli_class = GGem::CLI
17
+ end
18
+ subject{ @cli_class }
19
+
20
+ should have_imeths :run
21
+
22
+ should "build and run an instance of itself using `run`" do
23
+ cli_spy = CLISpy.new
24
+ Assert.stub(subject, :new).with{ cli_spy }
25
+
26
+ args = [Factory.string]
27
+ subject.run(args)
28
+ assert_equal args, cli_spy.run_called_with
29
+ end
30
+
31
+ should "know its commands" do
32
+ assert_equal 6, COMMANDS.size
33
+
34
+ assert_instance_of InvalidCommand, COMMANDS[Factory.string]
35
+
36
+ assert_instance_of GenerateCommand, COMMANDS['generate']
37
+ assert_instance_of BuildCommand, COMMANDS['build']
38
+ assert_instance_of InstallCommand, COMMANDS['install']
39
+ assert_instance_of PushCommand, COMMANDS['push']
40
+ assert_instance_of TagCommand, COMMANDS['tag']
41
+ assert_instance_of ReleaseCommand, COMMANDS['release']
42
+
43
+ assert_same COMMANDS['generate'], COMMANDS['g']
44
+ assert_same COMMANDS['build'], COMMANDS['b']
45
+ assert_same COMMANDS['install'], COMMANDS['i']
46
+ assert_same COMMANDS['push'], COMMANDS['p']
47
+ assert_same COMMANDS['tag'], COMMANDS['t']
48
+ assert_same COMMANDS['release'], COMMANDS['r']
49
+ end
50
+
51
+ end
52
+
53
+ class InitTests < UnitTests
54
+ desc "when init"
55
+ setup do
56
+ @kernel_spy = KernelSpy.new
57
+ @stdout = IOSpy.new
58
+ @stderr = IOSpy.new
59
+
60
+ @cli = @cli_class.new(@kernel_spy, @stdout, @stderr)
61
+ end
62
+ subject{ @cli }
63
+
64
+ should have_imeths :run
65
+
66
+ end
67
+
68
+ class RunSetupTests < InitTests
69
+ setup do
70
+ @command_name = Factory.string
71
+ @argv = [@command_name, Factory.string]
72
+
73
+ @command_class = Class.new
74
+ @command_spy = CommandSpy.new
75
+ Assert.stub(@command_class, :new){ @command_spy }
76
+ COMMANDS.add(@command_class, @command_name)
77
+
78
+ @invalid_command = InvalidCommand.new(@command_name)
79
+ end
80
+ teardown do
81
+ COMMANDS.remove(@command_name)
82
+ end
83
+
84
+ end
85
+
86
+ class RunTests < RunSetupTests
87
+ desc "and run"
88
+ setup do
89
+ @cli.run(@argv)
90
+ end
91
+
92
+ should "have run the command" do
93
+ assert_true @command_spy.run_called
94
+ end
95
+
96
+ should "have successfully exited" do
97
+ assert_equal 0, @kernel_spy.exit_status
98
+ end
99
+
100
+ end
101
+
102
+ class RunWithNoArgsTests < RunSetupTests
103
+ desc "and run with no args"
104
+ setup do
105
+ @cli.run([])
106
+ end
107
+
108
+ should "output the invalid command's help" do
109
+ assert_equal @invalid_command.help, @stdout.read
110
+ assert_empty @stderr.read
111
+ end
112
+
113
+ should "have successfully exited" do
114
+ assert_equal 0, @kernel_spy.exit_status
115
+ end
116
+
117
+ end
118
+
119
+ class RunWithInvalidCommandTests < RunSetupTests
120
+ desc "and run with an invalid command"
121
+ setup do
122
+ @name = Factory.string
123
+ @argv.unshift(@name)
124
+ @cli.run(@argv)
125
+ end
126
+
127
+ should "output that it is invalid and output the invalid command's help" do
128
+ exp = "'#{@name}' is not a command.\n\n"
129
+ assert_equal exp, @stderr.read
130
+ assert_equal @invalid_command.help, @stdout.read
131
+ end
132
+
133
+ should "have unsuccessfully exited" do
134
+ assert_equal 1, @kernel_spy.exit_status
135
+ end
136
+
137
+ end
138
+
139
+ class RunWithCommandExitErrorTests < RunSetupTests
140
+ desc "and run with a command that error exits"
141
+ setup do
142
+ Assert.stub(@command_spy, :run){ raise CommandExitError }
143
+ @cli.run(@argv)
144
+ end
145
+
146
+ should "have unsuccessfully exited with no stderr output" do
147
+ assert_equal 1, @kernel_spy.exit_status
148
+ assert_empty @stderr.read
149
+ end
150
+
151
+ end
152
+
153
+ class RunWithHelpTests < RunSetupTests
154
+ desc "and run with the help switch"
155
+ setup do
156
+ @cli.run([ '--help' ])
157
+ end
158
+
159
+ should "output the invalid command's help" do
160
+ assert_equal @invalid_command.help, @stdout.read
161
+ assert_empty @stderr.read
162
+ end
163
+
164
+ should "have successfully exited" do
165
+ assert_equal 0, @kernel_spy.exit_status
166
+ end
167
+
168
+ end
169
+
170
+ class RunWithVersionTests < RunSetupTests
171
+ desc "and run with the version switch"
172
+ setup do
173
+ @cli.run([ '--version' ])
174
+ end
175
+
176
+ should "have output its version" do
177
+ assert_equal "#{GGem::VERSION}\n", @stdout.read
178
+ assert_empty @stderr.read
179
+ end
180
+
181
+ should "have successfully exited" do
182
+ assert_equal 0, @kernel_spy.exit_status
183
+ end
184
+
185
+ end
186
+
187
+ class RunWithErrorTests < RunSetupTests
188
+ setup do
189
+ @exception = RuntimeError.new(Factory.string)
190
+ Assert.stub(@command_spy, :run){ raise @exception }
191
+ @cli.run(@argv)
192
+ end
193
+
194
+ should "have output an error message" do
195
+ exp = "#{@exception.class}: #{@exception.message}\n" \
196
+ "#{@exception.backtrace.join("\n")}\n"
197
+ assert_equal exp, @stderr.read
198
+ assert_empty @stdout.read
199
+ end
200
+
201
+ should "have unsuccessfully exited" do
202
+ assert_equal 1, @kernel_spy.exit_status
203
+ end
204
+
205
+ end
206
+
207
+ class InvalidCommandTests < UnitTests
208
+ desc "InvalidCommand"
209
+ setup do
210
+ @name = Factory.string
211
+ @command_class = InvalidCommand
212
+ @cmd = @command_class.new(@name)
213
+ end
214
+ subject{ @cmd }
215
+
216
+ should have_readers :name, :clirb
217
+ should have_imeths :new, :run, :help
218
+
219
+ should "know its attrs" do
220
+ assert_equal @name, subject.name
221
+ assert_instance_of CLIRB, subject.clirb
222
+ end
223
+
224
+ should "set its argv and return itself using `new`" do
225
+ assert_same subject, subject.new
226
+ end
227
+
228
+ should "parse its argv on run" do
229
+ assert_raises(CLIRB::HelpExit){ subject.new.run([ '--help' ]) }
230
+ assert_raises(CLIRB::VersionExit){ subject.new.run([ '--version' ]) }
231
+ end
232
+
233
+ should "raise a help exit if its name is empty" do
234
+ cmd = @command_class.new([nil, ''].choice)
235
+ argv = [Factory.string, Factory.string]
236
+ assert_raises(CLIRB::HelpExit){ cmd.new.run(argv) }
237
+ end
238
+
239
+ should "raise an invalid command error when run" do
240
+ assert_raises(InvalidCommandError){ subject.new.run([Factory.string]) }
241
+ end
242
+
243
+ should "know its help" do
244
+ exp = "Usage: ggem [COMMAND] [options]\n\n" \
245
+ "Options: #{subject.clirb}\n" \
246
+ "Commands:\n" \
247
+ "#{COMMANDS.to_s.split("\n").map{ |l| " #{l}" }.join("\n")}\n"
248
+ assert_equal exp, subject.help
249
+ end
250
+
251
+ end
252
+
253
+ class IOCommandTests < UnitTests
254
+ setup do
255
+ @stdout, @stderr = IOSpy.new, IOSpy.new
256
+ end
257
+ subject{ @cmd }
258
+
259
+ end
260
+
261
+ class ValidCommandTests < IOCommandTests
262
+ desc "ValidCommand"
263
+ setup do
264
+ @command_class = Class.new{ include ValidCommand }
265
+ @cmd = @command_class.new
266
+ end
267
+
268
+ should have_imeths :clirb, :run, :summary
269
+
270
+ should "know its CLI.RB" do
271
+ assert_instance_of CLIRB, subject.clirb
272
+ end
273
+
274
+ should "parse its args when run" do
275
+ argv = Factory.integer(3).times.map{ Factory.string }
276
+ subject.run(argv, @stdout, @stderr)
277
+ assert_equal argv, subject.clirb.args
278
+ end
279
+
280
+ should "default its summary" do
281
+ assert_equal '', subject.summary
282
+ end
283
+
284
+ end
285
+
286
+ class GitRepoCommandTests < IOCommandTests
287
+ desc "GitRepoCommand"
288
+ setup do
289
+ @gem1_root_path = TEST_SUPPORT_PATH.join('gem1')
290
+ Assert.stub(Dir, :pwd){ @gem1_root_path}
291
+
292
+ @command_class = Class.new{ include GitRepoCommand }
293
+ @cmd = @command_class.new
294
+ end
295
+
296
+ should "be a valid, notify cmd command" do
297
+ assert_kind_of ValidCommand, subject
298
+ assert_kind_of NotifyCmdCommand, subject
299
+ end
300
+
301
+ should "build a new git repo at the current pwd root" do
302
+ gitrepo_new_called_with = nil
303
+ Assert.stub(GGem::GitRepo, :new){ |*args| gitrepo_new_called_with = args }
304
+
305
+ @command_class.new
306
+ assert_equal [Dir.pwd], gitrepo_new_called_with
307
+ end
308
+
309
+ end
310
+
311
+ module RootPathTests
312
+ include MuchPlugin
313
+
314
+ plugin_included do
315
+ setup do
316
+ @root_path = Factory.path
317
+ Assert.stub(Dir, :pwd){ @root_path }
318
+ end
319
+ end
320
+
321
+ end
322
+
323
+ module GitRepoSpyTests
324
+ include MuchPlugin
325
+
326
+ plugin_included do
327
+ include RootPathTests
328
+
329
+ setup do
330
+ @repo_spy = nil
331
+ Assert.stub(GGem::GitRepo, :new){ |*args| @repo_spy = GitRepoSpy.new(*args) }
332
+ end
333
+
334
+ end
335
+
336
+ end
337
+
338
+ class GenerateCommandTests < IOCommandTests
339
+ include GitRepoSpyTests
340
+
341
+ desc "GenerateCommand"
342
+ setup do
343
+ @name = Factory.string
344
+
345
+ @path = Factory.dir_path
346
+ Assert.stub(Dir, :pwd){ @path }
347
+
348
+ @gem_new_called_with = []
349
+ @gem_spy = GemSpy.new
350
+ @gem_class = GGem::Gem
351
+ Assert.stub(@gem_class, :new) do |*args|
352
+ @gem_new_called_with = args
353
+ @gem_spy
354
+ end
355
+
356
+ @command_class = GenerateCommand
357
+ @cmd = @command_class.new
358
+ end
359
+
360
+ should "be a valid command" do
361
+ assert_kind_of ValidCommand, subject
362
+ end
363
+
364
+ should "know its summary" do
365
+ exp = "Create a gem given a GEM-NAME"
366
+ assert_equal exp, subject.summary
367
+ end
368
+
369
+ should "know its help" do
370
+ exp = "Usage: ggem generate [options] GEM-NAME\n\n" \
371
+ "Options: #{subject.clirb}\n" \
372
+ "Description:\n" \
373
+ " #{subject.summary}"
374
+ assert_equal exp, subject.help
375
+ end
376
+
377
+ should "save a gem and initialize a git repo for it when run" do
378
+ subject.run([@name], @stdout, @stderr)
379
+
380
+ assert_equal [@path, @name], @gem_new_called_with
381
+ assert_true @gem_spy.save_called
382
+
383
+ assert_equal @gem_spy.path, @repo_spy.path
384
+ assert_true @repo_spy.run_init_cmd_called
385
+
386
+ exp = "created gem in #{@gem_spy.path}\n" \
387
+ "initialized gem git repo\n"
388
+ assert_equal exp, @stdout.read
389
+ end
390
+
391
+ should "re-raise a specific argument error on gem 'no name' errors" do
392
+ Assert.stub(@gem_class, :new){ raise GGem::Gem::NoNameError }
393
+ err = nil
394
+ begin
395
+ cmd = @command_class.new
396
+ cmd.run([])
397
+ rescue ArgumentError => err
398
+ end
399
+
400
+ assert_not_nil err
401
+ exp = "GEM-NAME must be provided"
402
+ assert_equal exp, err.message
403
+ assert_not_empty err.backtrace
404
+ end
405
+
406
+ end
407
+
408
+ class GemspecCommandTests < IOCommandTests
409
+ desc "GemspecCommand"
410
+ setup do
411
+ @gem1_root_path = TEST_SUPPORT_PATH.join('gem1')
412
+ Assert.stub(Dir, :pwd){ @gem1_root_path}
413
+
414
+ @command_class = Class.new{ include GemspecCommand }
415
+ @cmd = @command_class.new
416
+ end
417
+
418
+ should "be a valid, notify cmd command" do
419
+ assert_kind_of ValidCommand, subject
420
+ assert_kind_of NotifyCmdCommand, subject
421
+ end
422
+
423
+ should "build a new gemspec at the current pwd root" do
424
+ gemspec_new_called_with = nil
425
+ Assert.stub(GGem::Gemspec, :new){ |*args| gemspec_new_called_with = args }
426
+
427
+ @command_class.new
428
+ assert_equal [Dir.pwd], gemspec_new_called_with
429
+ end
430
+
431
+ should "complain if no gemspec file can be found at the current pwd" do
432
+ root = Factory.path
433
+ Assert.stub(Dir, :pwd){ root }
434
+
435
+ begin
436
+ cmd = @command_class.new
437
+ rescue ArgumentError => err
438
+ end
439
+ assert_not_nil err
440
+ exp = "There are no gemspecs at #{Dir.pwd}"
441
+ assert_equal exp, err.message
442
+ end
443
+
444
+ end
445
+
446
+ module GemspecSpyTests
447
+ include MuchPlugin
448
+
449
+ plugin_included do
450
+ include RootPathTests
451
+
452
+ setup do
453
+ @spec_spy = nil
454
+ Assert.stub(GGem::Gemspec, :new){ |*args| @spec_spy = GemspecSpy.new(*args) }
455
+ end
456
+ end
457
+
458
+ end
459
+
460
+ class BuildCommandTests < IOCommandTests
461
+ include GemspecSpyTests
462
+
463
+ desc "BuildCommand"
464
+ setup do
465
+ @command_class = BuildCommand
466
+ @cmd = @command_class.new
467
+ end
468
+
469
+ should "be a gemspec command" do
470
+ assert_kind_of GemspecCommand, subject
471
+ end
472
+
473
+ should "know its summary" do
474
+ exp = "Build #{@spec_spy.gem_file_name} into the " \
475
+ "#{GGem::Gemspec::BUILD_TO_DIRNAME} directory"
476
+ assert_equal exp, subject.summary
477
+ end
478
+
479
+ should "know its help" do
480
+ exp = "Usage: ggem build [options]\n\n" \
481
+ "Options: #{subject.clirb}\n" \
482
+ "Description:\n" \
483
+ " #{subject.summary}"
484
+ assert_equal exp, subject.help
485
+ end
486
+
487
+ should "call the spec's run build cmd when run" do
488
+ ENV['DEBUG'] = [nil, '1'].choice
489
+ subject.run([], @stdout, @stderr)
490
+
491
+ assert_true @spec_spy.run_build_cmd_called
492
+
493
+ exp = ENV['DEBUG'] == '1' ? "build\nbuild cmd was run\n" : ''
494
+ exp += "#{@spec_spy.name} #{@spec_spy.version} built to #{@spec_spy.gem_file}\n"
495
+ assert_equal exp, @stdout.read
496
+
497
+ ENV['DEBUG'] = nil
498
+ end
499
+
500
+ should "handle cmd errors when run" do
501
+ err_msg = Factory.string
502
+ Assert.stub(@spec_spy, :run_build_cmd){ raise GGem::Gemspec::CmdError, err_msg }
503
+
504
+ assert_raises(CommandExitError){ subject.run([], @stdout, @stderr) }
505
+ assert_equal "#{err_msg}\n", @stderr.read
506
+ end
507
+
508
+ end
509
+
510
+ class InstallCommandTests < IOCommandTests
511
+ include GemspecSpyTests
512
+
513
+ desc "InstallCommand"
514
+ setup do
515
+ @build_spy = nil
516
+ Assert.stub(BuildCommand, :new){ |*args| @build_spy = CommandSpy.new(*args) }
517
+
518
+ @command_class = InstallCommand
519
+ @argv = []
520
+ @cmd = @command_class.new
521
+ end
522
+
523
+ should "be a gemspec command" do
524
+ assert_kind_of GemspecCommand, subject
525
+ end
526
+
527
+ should "know its summary" do
528
+ exp = "Build and install #{@spec_spy.gem_file_name} into system gems"
529
+ assert_equal exp, subject.summary
530
+ end
531
+
532
+ should "know its help" do
533
+ exp = "Usage: ggem install [options]\n\n" \
534
+ "Options: #{subject.clirb}\n" \
535
+ "Description:\n" \
536
+ " #{subject.summary}"
537
+ assert_equal exp, subject.help
538
+ end
539
+
540
+ should "build a build command using its argv" do
541
+ assert @build_spy
542
+ end
543
+
544
+ should "run the build command and call the spec's run install cmds when run" do
545
+ ENV['DEBUG'] = [nil, '1'].choice
546
+ subject.run(@argv, @stdout, @stderr)
547
+
548
+ assert_true @build_spy.run_called
549
+ assert_equal @argv, @build_spy.argv
550
+ assert_true @spec_spy.run_install_cmd_called
551
+
552
+ exp = ENV['DEBUG'] == '1' ? "install\ninstall cmd was run\n" : ''
553
+ exp += "#{@spec_spy.name} #{@spec_spy.version} installed to system gems\n"
554
+ assert_includes exp, @stdout.read
555
+
556
+ ENV['DEBUG'] = nil
557
+ end
558
+
559
+ should "handle cmd errors when run" do
560
+ err_msg = Factory.string
561
+ Assert.stub(@spec_spy, :run_install_cmd){ raise GGem::Gemspec::CmdError, err_msg }
562
+
563
+ assert_raises(CommandExitError){ subject.run(@argv, @stdout, @stderr) }
564
+ assert_equal "#{err_msg}\n", @stderr.read
565
+ end
566
+
567
+ end
568
+
569
+ class PushCommandTests < IOCommandTests
570
+ include GemspecSpyTests
571
+
572
+ desc "PushCommand"
573
+ setup do
574
+ @build_spy = nil
575
+ Assert.stub(BuildCommand, :new){ |*args| @build_spy = CommandSpy.new(*args) }
576
+
577
+ @command_class = PushCommand
578
+ @argv = []
579
+ @cmd = @command_class.new
580
+ end
581
+
582
+ should "be a gemspec command" do
583
+ assert_kind_of GemspecCommand, subject
584
+ end
585
+
586
+ should "know its summary" do
587
+ exp = "Push built #{@spec_spy.gem_file_name} to #{@spec_spy.push_host}"
588
+ assert_equal exp, subject.summary
589
+ end
590
+
591
+ should "know its help" do
592
+ exp = "Usage: ggem push [options]\n\n" \
593
+ "Options: #{subject.clirb}\n" \
594
+ "Description:\n" \
595
+ " #{subject.summary}"
596
+ assert_equal exp, subject.help
597
+ end
598
+
599
+ should "build a build command using its argv" do
600
+ assert @build_spy
601
+ end
602
+
603
+ should "run the build command and call the spec's run push cmds when run" do
604
+ ENV['DEBUG'] = [nil, '1'].choice
605
+ subject.run(@argv, @stdout, @stderr)
606
+
607
+ assert_true @build_spy.run_called
608
+ assert_equal @argv, @build_spy.argv
609
+ assert_true @spec_spy.run_push_cmd_called
610
+
611
+ exp = "Pushing #{@spec_spy.gem_file_name} to #{@spec_spy.push_host}...\n"
612
+ exp += ENV['DEBUG'] == '1' ? "push\npush cmd was run\n" : ''
613
+ exp += "#{@spec_spy.gem_file_name} received.\n"
614
+ assert_equal exp, @stdout.read
615
+
616
+ ENV['DEBUG'] = nil
617
+ end
618
+
619
+ should "handle cmd errors when run" do
620
+ err_msg = Factory.string
621
+ Assert.stub(@spec_spy, :run_push_cmd){ raise GGem::Gemspec::CmdError, err_msg }
622
+
623
+ assert_raises(CommandExitError){ subject.run(@argv, @stdout, @stderr) }
624
+ assert_equal "#{err_msg}\n", @stderr.read
625
+ end
626
+
627
+ end
628
+
629
+ class TagCommandTests < IOCommandTests
630
+ include GitRepoSpyTests
631
+ include GemspecSpyTests
632
+
633
+ desc "TagCommand"
634
+ setup do
635
+ @command_class = TagCommand
636
+ @cmd = @command_class.new
637
+ end
638
+
639
+ should "be a gemspec command" do
640
+ assert_kind_of GemspecCommand, subject
641
+ end
642
+
643
+ should "know its summary" do
644
+ exp = "Tag #{@spec_spy.version_tag} and push git commits/tags"
645
+ assert_equal exp, subject.summary
646
+ end
647
+
648
+ should "know its help" do
649
+ exp = "Usage: ggem tag [options]\n\n" \
650
+ "Options: #{subject.clirb}\n" \
651
+ "Description:\n" \
652
+ " #{subject.summary}"
653
+ assert_equal exp, subject.help
654
+ end
655
+
656
+ should "call the repo's run build/push cmds when run" do
657
+ ENV['DEBUG'] = [nil, '1'].choice
658
+ subject.run([], @stdout, @stderr)
659
+
660
+ assert_true @repo_spy.run_validate_clean_cmd_called
661
+ assert_true @repo_spy.run_validate_committed_cmd_called
662
+
663
+ exp = [@spec_spy.version, @spec_spy.version_tag]
664
+ assert_equal exp, @repo_spy.run_add_version_tag_cmd_called_with
665
+
666
+ assert_true @repo_spy.run_push_cmd_called
667
+ assert_nil @repo_spy.run_rm_tag_cmd_called_with
668
+
669
+ exp = if ENV['DEBUG'] == '1'
670
+ "validate clean\nvalidate clean cmd was run\n" \
671
+ "validate committed\nvalidate committed cmd was run\n" \
672
+ "add tag\nadd tag cmd was run\n"
673
+ else
674
+ ''
675
+ end
676
+ exp += "Tagged #{@spec_spy.version_tag}.\n"
677
+ exp += ENV['DEBUG'] == '1' ? "push\npush cmd was run\n" : ''
678
+ exp += "Pushed git commits and tags.\n"
679
+ assert_equal exp, @stdout.read
680
+
681
+ ENV['DEBUG'] = nil
682
+ end
683
+
684
+ should "handle validation cmd errors when run" do
685
+ err_msg = Factory.string
686
+ err_on = [:run_validate_clean_cmd, :run_validate_committed_cmd].choice
687
+ Assert.stub(@repo_spy, err_on){ raise GGem::GitRepo::CmdError, err_msg }
688
+
689
+ assert_raises(CommandExitError){ subject.run([], @stdout, @stderr) }
690
+ exp = "There are files that need to be committed first.\n"
691
+ assert_equal exp, @stderr.read
692
+ end
693
+
694
+ should "handle non-validation cmd errors when run" do
695
+ err_msg = Factory.string
696
+ err_on = [:run_add_version_tag_cmd, :run_push_cmd].choice
697
+ Assert.stub(@repo_spy, err_on){ raise GGem::GitRepo::CmdError, err_msg }
698
+
699
+ assert_raises(CommandExitError){ subject.run([], @stdout, @stderr) }
700
+ assert_equal "#{err_msg}\n", @stderr.read
701
+ end
702
+
703
+ should "remove the version tag on push errors" do
704
+ err_msg = Factory.string
705
+ Assert.stub(@repo_spy, :run_push_cmd){ raise GGem::GitRepo::CmdError, err_msg }
706
+
707
+ assert_raises(CommandExitError){ subject.run([], @stdout, @stderr) }
708
+ assert_equal "#{err_msg}\n", @stderr.read
709
+
710
+ exp = [@spec_spy.version_tag]
711
+ assert_equal exp, @repo_spy.run_rm_tag_cmd_called_with
712
+ end
713
+
714
+ should "handle tag removal cmd errors when run" do
715
+ Assert.stub(@repo_spy, :run_push_cmd){ raise GGem::GitRepo::CmdError, Factory.string }
716
+ err_msg = Factory.string
717
+ Assert.stub(@repo_spy, :run_rm_tag_cmd){ raise GGem::GitRepo::CmdError, err_msg }
718
+
719
+ assert_raises(CommandExitError){ subject.run([], @stdout, @stderr) }
720
+ assert_equal "#{err_msg}\n", @stderr.read
721
+ end
722
+
723
+ end
724
+
725
+ class ReleaseCommandTests < IOCommandTests
726
+ include GemspecSpyTests
727
+
728
+ desc "ReleaseCommand"
729
+ setup do
730
+ @tag_spy = nil
731
+ Assert.stub(TagCommand, :new){ |*args| @tag_spy = CommandSpy.new(*args) }
732
+
733
+ @push_spy = nil
734
+ Assert.stub(PushCommand, :new){ |*args| @push_spy = CommandSpy.new(*args) }
735
+
736
+ @command_class = ReleaseCommand
737
+ @argv = []
738
+ @cmd = @command_class.new
739
+ end
740
+
741
+ should "be a gemspec command" do
742
+ assert_kind_of GemspecCommand, subject
743
+ end
744
+
745
+ should "know its summary" do
746
+ exp = "Tag #{@spec_spy.version_tag} and push built #{@spec_spy.gem_file_name} to " \
747
+ "#{@spec_spy.push_host}"
748
+ assert_equal exp, subject.summary
749
+ end
750
+
751
+ should "know its help" do
752
+ exp = "Usage: ggem release [options]\n\n" \
753
+ "Options: #{subject.clirb}\n" \
754
+ "Description:\n" \
755
+ " #{subject.summary}\n" \
756
+ " (macro for running `ggem tag && ggem push`)"
757
+ assert_equal exp, subject.help
758
+ end
759
+
760
+ should "build a tag and push command using its argv" do
761
+ [@tag_spy, @push_spy].each do |spy|
762
+ assert spy
763
+ end
764
+ end
765
+
766
+ should "run the tag and push command when run" do
767
+ subject.run(@argv, @stdout, @stderr)
768
+
769
+ [@tag_spy, @push_spy].each do |spy|
770
+ assert_true spy.run_called
771
+ assert_equal @argv, spy.argv
772
+ end
773
+ end
774
+
775
+ end
776
+
777
+ class CommandSetTests < UnitTests
778
+ desc "CommandSet"
779
+ setup do
780
+ @unknown_cmd_block_called_with = nil
781
+ @set = CommandSet.new{ |*args| @unknown_cmd_block_called_with = args }
782
+ end
783
+ subject{ @set }
784
+
785
+ should have_imeths :add, :remove, :[], :size
786
+
787
+ should "add/rm commands, be able to look them up and know its size" do
788
+ assert_equal 0, subject.size
789
+ assert_equal '', subject.to_s
790
+
791
+ subject.add(CommandSpy, 'test', 't', 'tst')
792
+ assert_equal 1, subject.size
793
+
794
+ assert_instance_of CommandSpy, subject['test']
795
+ assert_same subject['test'], subject['t']
796
+ assert_same subject['test'], subject['tst']
797
+
798
+ exp_strs = ["test (t, tst) # #{subject['test'].summary}"]
799
+ assert_equal exp_strs.join("\n"), subject.to_s
800
+
801
+ subject.add(CommandSpy, 'add1')
802
+ exp_strs << "add1 # #{subject['add1'].summary}"
803
+
804
+ @cmd_spy = CommandSpy.new
805
+ Assert.stub(@cmd_spy, :summary){ [nil, ''].choice }
806
+ Assert.stub(CommandSpy, :new){ @cmd_spy }
807
+
808
+ subject.add(CommandSpy, 'add2', 'add')
809
+ exp_strs << "add2 (add) "
810
+
811
+ subject.add(CommandSpy, 'add3')
812
+ Assert.stub(subject['add3'], :summary){ [nil, ''].choice }
813
+ exp_strs << "add3 "
814
+
815
+ assert_equal exp_strs.join("\n"), subject.to_s
816
+
817
+ subject.remove('test')
818
+ subject.remove('add1')
819
+ subject.remove('add2')
820
+ subject.remove('add3')
821
+
822
+ assert_equal 0, subject.size
823
+ assert_equal '', subject.to_s
824
+ end
825
+
826
+ should "call the given block when looking up unknown command names" do
827
+ unknown_cmd_name = Factory.string
828
+ subject[unknown_cmd_name]
829
+ assert_equal [unknown_cmd_name], @unknown_cmd_block_called_with
830
+ end
831
+
832
+ end
833
+
834
+ class CLISpy
835
+ attr_reader :run_called_with
836
+
837
+ def initialize
838
+ @run_called_with = nil
839
+ end
840
+
841
+ def run(args)
842
+ @run_called_with = args
843
+ end
844
+ end
845
+
846
+ class CommandSpy
847
+ attr_reader :argv, :stdout, :stderr, :run_called
848
+
849
+ def initialize
850
+ @argv = nil
851
+ @stdout, @stderr = nil, nil
852
+ @run_called = false
853
+ end
854
+
855
+ def run(argv, stdout = nil, stderr = nil)
856
+ @argv = argv
857
+ @stdout, @stderr = stdout, stderr
858
+ @run_called = true
859
+ end
860
+
861
+ def summary
862
+ @summary ||= Factory.string
863
+ end
864
+
865
+ def help
866
+ @help ||= Factory.text
867
+ end
868
+ end
869
+
870
+ class KernelSpy
871
+ attr_reader :exit_status
872
+
873
+ def initialize
874
+ @exit_status = nil
875
+ end
876
+
877
+ def exit(code)
878
+ @exit_status ||= code
879
+ end
880
+ end
881
+
882
+ class IOSpy
883
+ def initialize
884
+ @io = StringIO.new
885
+ end
886
+
887
+ def puts(message)
888
+ @io.puts message
889
+ end
890
+
891
+ def read
892
+ @io.rewind
893
+ @io.read
894
+ end
895
+ end
896
+
897
+ class GemSpy
898
+ attr_reader :save_called
899
+
900
+ def initialize
901
+ @save_called = false
902
+ end
903
+
904
+ def save!
905
+ @save_called = true
906
+ self
907
+ end
908
+
909
+ def path
910
+ @path ||= Factory.path
911
+ end
912
+ end
913
+
914
+ class GemspecSpy
915
+ attr_reader :name, :version, :version_tag, :push_host
916
+ attr_reader :run_build_cmd_called, :run_install_cmd_called, :run_push_cmd_called
917
+
918
+ def initialize(root_path)
919
+ @root = Pathname.new(File.expand_path(root_path))
920
+ @name = Factory.string
921
+ @version = Factory.string
922
+ @version_tag = Factory.string
923
+ @push_host = Factory.url
924
+
925
+ @run_build_cmd_called = false
926
+ @run_install_cmd_called = false
927
+ @run_push_cmd_called = false
928
+ end
929
+
930
+ def path
931
+ @root.join("#{self.name}.gemspec")
932
+ end
933
+
934
+ def gem_file_name
935
+ "#{self.name}-#{self.version}.gem"
936
+ end
937
+
938
+ def gem_file
939
+ File.join(GGem::Gemspec::BUILD_TO_DIRNAME, self.gem_file_name)
940
+ end
941
+
942
+ def run_build_cmd
943
+ @run_build_cmd_called = true
944
+ ['build', 0, 'build cmd was run']
945
+ end
946
+
947
+ def run_install_cmd
948
+ @run_install_cmd_called = true
949
+ ['install', 0, 'install cmd was run']
950
+ end
951
+
952
+ def run_push_cmd
953
+ @run_push_cmd_called = true
954
+ ['push', 0, 'push cmd was run']
955
+ end
956
+
957
+ end
958
+
959
+ class GitRepoSpy
960
+ attr_reader :path
961
+ attr_reader :run_init_cmd_called
962
+ attr_reader :run_validate_clean_cmd_called, :run_validate_committed_cmd_called
963
+ attr_reader :run_add_version_tag_cmd_called_with, :run_rm_tag_cmd_called_with
964
+ attr_reader :run_push_cmd_called
965
+
966
+ def initialize(path)
967
+ @path = path
968
+
969
+ @run_init_cmd_called = false
970
+
971
+ @run_validate_clean_cmd_called = false
972
+ @run_validate_committed_cmd_called = false
973
+
974
+ @run_add_version_tag_cmd_called_with = nil
975
+ @run_rm_tag_cmd_called_with = nil
976
+
977
+ @run_push_cmd_called = false
978
+ end
979
+
980
+ def run_init_cmd
981
+ @run_init_cmd_called = true
982
+ ['init', 0, 'init cmd was run']
983
+ end
984
+
985
+ def run_validate_clean_cmd
986
+ @run_validate_clean_cmd_called = true
987
+ ['validate clean', 0, 'validate clean cmd was run']
988
+ end
989
+
990
+ def run_validate_committed_cmd
991
+ @run_validate_committed_cmd_called = true
992
+ ['validate committed', 0, 'validate committed cmd was run']
993
+ end
994
+
995
+ def run_add_version_tag_cmd(*args)
996
+ @run_add_version_tag_cmd_called_with = args
997
+ ['add tag', 0, 'add tag cmd was run']
998
+ end
999
+
1000
+ def run_rm_tag_cmd(*args)
1001
+ @run_rm_tag_cmd_called_with = args
1002
+ ['rm tag', 0, 'rm tag cmd was run']
1003
+ end
1004
+
1005
+ def run_push_cmd
1006
+ @run_push_cmd_called = true
1007
+ ['push', 0, 'push cmd was run']
1008
+ end
1009
+
1010
+ end
1011
+
1012
+ end