codersdojo 0.9.7 → 0.9.8
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.
- data/app/argument_parser.rb +36 -0
- data/app/codersdojo.rb +4 -618
- data/app/console_view.rb +108 -0
- data/app/controller.rb +50 -0
- data/app/filename_formatter.rb +34 -0
- data/app/progress.rb +19 -0
- data/app/runner.rb +39 -0
- data/app/scheduler.rb +15 -0
- data/app/session_id_generator.rb +17 -0
- data/app/shell_wrapper.rb +96 -0
- data/app/state_reader.rb +57 -0
- data/app/uploader.rb +49 -0
- data/app/xml_element_extractor.rb +11 -0
- data/bin/codersdojo +4 -0
- data/spec/argument_parser_spec.rb +54 -0
- data/spec/progress_spec.rb +23 -0
- data/spec/runner_spec.rb +59 -0
- data/spec/session_id_generator_spec.rb +21 -0
- data/spec/state_reader_spec.rb +27 -0
- data/spec/uploader_spec.rb +78 -0
- data/spec/xml_element_extractor_spec.rb +12 -0
- data/templates/any/README +10 -0
- data/templates/any/run-endless.sh +2 -0
- data/templates/any/run-once.sh +1 -0
- data/templates/clojure.is-test/README +12 -0
- data/templates/clojure.is-test/lib/clojure-contrib.jar +0 -0
- data/templates/clojure.is-test/run-endless.sh +1 -0
- data/templates/clojure.is-test/run-once.sh +2 -0
- data/templates/java.junit/README +20 -0
- data/templates/java.junit/run-endless.sh +1 -0
- data/templates/java.junit/run-once.sh +3 -0
- data/templates/javascript.jspec/README +8 -0
- data/templates/python.unittest/README +8 -0
- data/templates/ruby.test-unit/README +5 -0
- metadata +42 -5
- data/spec/codersdojo_spec.rb +0 -265
data/app/console_view.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'shell_wrapper'
|
2
|
+
|
3
|
+
class ConsoleView
|
4
|
+
|
5
|
+
@@VERSION = '0.9'
|
6
|
+
|
7
|
+
def show_help
|
8
|
+
puts <<-helptext
|
9
|
+
Personal CodersDojo, Version #{@@VERSION}, http://www.codersdojo.com, Copyright by it-agile GmbH (http://www.it-agile.de)
|
10
|
+
PersonalCodersDojo automatically runs your tests of a code kata.
|
11
|
+
|
12
|
+
helptext
|
13
|
+
show_usage
|
14
|
+
end
|
15
|
+
|
16
|
+
def show_usage
|
17
|
+
puts <<-helptext
|
18
|
+
Usage: #{$0} command [options]
|
19
|
+
Commands:
|
20
|
+
help, -h, --help Print this help text.
|
21
|
+
help <command> See the details of the command.
|
22
|
+
setup <framework> <kata_file> Setup the environment for running the kata.
|
23
|
+
upload <framework> <session_dir> Upload the kata to http://www.codersdojo.org
|
24
|
+
|
25
|
+
Report bugs to <codersdojo@it-agile.de>
|
26
|
+
helptext
|
27
|
+
end
|
28
|
+
|
29
|
+
def show_detailed_help command
|
30
|
+
if command == 'setup' then
|
31
|
+
show_help_setup
|
32
|
+
elsif command == 'start' then
|
33
|
+
show_help_start
|
34
|
+
elsif command == 'upload' then
|
35
|
+
show_help_upload
|
36
|
+
else
|
37
|
+
show_help_unknown command
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def show_help_setup
|
42
|
+
templates = ShellWrapper.new.list_templates
|
43
|
+
puts <<-helptext
|
44
|
+
|
45
|
+
setup <framework> <kata_file_no_ext> Setup the environment for the kata for the given framework and kata file.
|
46
|
+
The kata_file should not have an extension. Use 'prime' and not 'prime.java'.
|
47
|
+
By now <framework> is one of #{templates}.
|
48
|
+
Use ??? as framework if your framework isn't in the list.
|
49
|
+
|
50
|
+
Example:
|
51
|
+
:/dojo/my_kata% #{$0} setup ruby.test/unit prime
|
52
|
+
Show the instructions how to setup the environment for kata execution with Ruby and test/unit.
|
53
|
+
helptext
|
54
|
+
end
|
55
|
+
|
56
|
+
def show_help_start
|
57
|
+
puts <<-helptext
|
58
|
+
|
59
|
+
start <shell_command> <kata_file> Start the continuous test runner, that runs <shell-command> whenever <kata_file>
|
60
|
+
changes. The <kata_file> has to include the whole source code of the kata.
|
61
|
+
Whenever the test runner is started, it creates a new session directory in the
|
62
|
+
directory .codersdojo where it logs the steps of the kata.
|
63
|
+
helptext
|
64
|
+
end
|
65
|
+
|
66
|
+
def show_help_upload
|
67
|
+
templates = ShellWrapper.new.list_templates
|
68
|
+
puts <<-helptext
|
69
|
+
|
70
|
+
upload <framework> <session_directory> Upload the kata written with <framework> in <session_directory> to codersdojo.com.
|
71
|
+
<session_directory> is relative to the working directory.
|
72
|
+
By now <framework> is one of #{templates}.
|
73
|
+
If you used another framework, use ??? and send an email to codersdojo@it-agile.de
|
74
|
+
|
75
|
+
Example:
|
76
|
+
:/dojo/my_kata$ #{$0} upload ruby.test/unit .codersdojo/2010-11-02_16-21-53
|
77
|
+
Upload the kata (written in Ruby with the test/unit framework) located in directory ".codersdojo/2010-11-02_16-21-53" to codersdojo.com.
|
78
|
+
helptext
|
79
|
+
end
|
80
|
+
|
81
|
+
def show_help_unknown command
|
82
|
+
puts <<-helptext
|
83
|
+
Command #{command} not known. Try '#{$0} help' to list the supported commands.
|
84
|
+
helptext
|
85
|
+
end
|
86
|
+
|
87
|
+
def show_start_kata command, file
|
88
|
+
puts "Starting PersonalCodersDojo with command #{command} and kata file #{file}. Use Ctrl+C to finish the kata."
|
89
|
+
end
|
90
|
+
|
91
|
+
def show_missing_command_argument_error command
|
92
|
+
puts "Command <#{command}> recognized but no argument was provided (at least one argument is required).\n\n"
|
93
|
+
show_usage
|
94
|
+
end
|
95
|
+
|
96
|
+
def show_upload_start hostname
|
97
|
+
puts "Start upload to #{hostname}"
|
98
|
+
end
|
99
|
+
|
100
|
+
def show_upload_result result
|
101
|
+
puts result
|
102
|
+
end
|
103
|
+
|
104
|
+
def show_socket_error command
|
105
|
+
puts "Encountered network error while <#{command}>. Is http://www.codersdojo.com down?"
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
data/app/controller.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
class Controller
|
2
|
+
|
3
|
+
def initialize view, hostname
|
4
|
+
@view = view
|
5
|
+
@hostname = hostname
|
6
|
+
end
|
7
|
+
|
8
|
+
def help command=nil
|
9
|
+
if command then
|
10
|
+
@view.show_detailed_help command.downcase
|
11
|
+
else
|
12
|
+
@view.show_help
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate framework, kata_file
|
17
|
+
shell = ShellWrapper.new
|
18
|
+
shell.scaffold framework
|
19
|
+
generator_text = IO.readlines("README").to_s;
|
20
|
+
generator_text = generator_text.gsub('#{kata_file}', kata_file)
|
21
|
+
generator_text = generator_text.gsub('#{$0}', $0)
|
22
|
+
generator_text = shell.make_os_specific generator_text
|
23
|
+
puts "\n" + generator_text
|
24
|
+
end
|
25
|
+
|
26
|
+
def start command, file
|
27
|
+
if not command or not file then
|
28
|
+
@view.show_missing_command_argument_error "start"
|
29
|
+
return
|
30
|
+
end
|
31
|
+
@view.show_start_kata command, file
|
32
|
+
dojo = Runner.new ShellWrapper.new, SessionIdGenerator.new
|
33
|
+
dojo.file = file
|
34
|
+
dojo.run_command = command
|
35
|
+
scheduler = Scheduler.new dojo
|
36
|
+
scheduler.start
|
37
|
+
end
|
38
|
+
|
39
|
+
def upload framework, session_directory
|
40
|
+
@view.show_upload_start @hostname
|
41
|
+
if session_directory then
|
42
|
+
uploader = Uploader.new @hostname, framework, session_directory
|
43
|
+
p uploader.upload
|
44
|
+
else
|
45
|
+
@view.show_missing_command_argument_error "upload"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class FilenameFormatter
|
2
|
+
|
3
|
+
CODERSDOJO_WORKSPACE = ".codersdojo"
|
4
|
+
RESULT_FILE = "result.txt"
|
5
|
+
STATE_DIR_PREFIX = "state_"
|
6
|
+
|
7
|
+
def self.state_dir_prefix
|
8
|
+
STATE_DIR_PREFIX
|
9
|
+
end
|
10
|
+
|
11
|
+
def source_code_file state_dir
|
12
|
+
Dir.entries(state_dir).each { |file|
|
13
|
+
return state_file state_dir, file unless file =='..' || file == '.' ||file == RESULT_FILE }
|
14
|
+
end
|
15
|
+
|
16
|
+
def result_file state_dir
|
17
|
+
state_file state_dir, RESULT_FILE
|
18
|
+
end
|
19
|
+
|
20
|
+
def state_file state_dir, file
|
21
|
+
"#{state_dir}/#{file}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def state_dir session_id, step
|
25
|
+
session_directory = session_dir session_id
|
26
|
+
"#{session_directory}/#{STATE_DIR_PREFIX}#{step}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def session_dir session_id
|
30
|
+
"#{CODERSDOJO_WORKSPACE}/#{session_id}"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
data/app/progress.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class Progress
|
2
|
+
|
3
|
+
def self.write_empty_progress states
|
4
|
+
STDOUT.print "#{states} states to upload"
|
5
|
+
STDOUT.print "["+" "*states+"]"
|
6
|
+
STDOUT.print "\b"*(states+1)
|
7
|
+
STDOUT.flush
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.next
|
11
|
+
STDOUT.print "."
|
12
|
+
STDOUT.flush
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.end
|
16
|
+
STDOUT.puts
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/app/runner.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "filename_formatter"
|
2
|
+
|
3
|
+
class Runner
|
4
|
+
|
5
|
+
attr_accessor :file, :run_command
|
6
|
+
|
7
|
+
def initialize shell, session_provider
|
8
|
+
@filename_formatter = FilenameFormatter.new
|
9
|
+
@shell = shell
|
10
|
+
@session_provider = session_provider
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
init_session
|
15
|
+
execute
|
16
|
+
end
|
17
|
+
|
18
|
+
def init_session
|
19
|
+
@step = 0
|
20
|
+
@session_id = @session_provider.generate_id
|
21
|
+
@shell.mkdir_p(@filename_formatter.session_dir @session_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute
|
25
|
+
change_time = @shell.ctime @file
|
26
|
+
if change_time == @previous_change_time then
|
27
|
+
return
|
28
|
+
end
|
29
|
+
result = @shell.execute "#{@run_command} #{@file}"
|
30
|
+
state_dir = @filename_formatter.state_dir @session_id, @step
|
31
|
+
@shell.mkdir state_dir
|
32
|
+
@shell.cp @file, state_dir
|
33
|
+
@shell.write_file @filename_formatter.result_file(state_dir), result
|
34
|
+
@step += 1
|
35
|
+
@previous_change_time = change_time
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
data/app/scheduler.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class SessionIdGenerator
|
2
|
+
|
3
|
+
def generate_id time=Time.new
|
4
|
+
year = format_to_length time.year, 4
|
5
|
+
month = format_to_length time.month, 2
|
6
|
+
day = format_to_length time.day, 2
|
7
|
+
hour = format_to_length time.hour, 2
|
8
|
+
minute = format_to_length time.min, 2
|
9
|
+
second = format_to_length time.sec, 2
|
10
|
+
"#{year}-#{month}-#{day}_#{hour}-#{minute}-#{second}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def format_to_length value, len
|
14
|
+
value.to_s.rjust len,"0"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
class ShellWrapper
|
4
|
+
|
5
|
+
MAX_STDOUT_LENGTH = 100000
|
6
|
+
ANY_TEMPLATE = "any"
|
7
|
+
|
8
|
+
def cp source, destination
|
9
|
+
FileUtils.cp source, destination
|
10
|
+
end
|
11
|
+
|
12
|
+
def mkdir dir
|
13
|
+
FileUtils.mkdir dir
|
14
|
+
end
|
15
|
+
|
16
|
+
def mkdir_p dirs
|
17
|
+
FileUtils.mkdir_p dirs
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute command
|
21
|
+
spec_pipe = IO.popen(command, "r")
|
22
|
+
result = spec_pipe.read MAX_STDOUT_LENGTH
|
23
|
+
spec_pipe.close
|
24
|
+
puts result
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_file filename, content
|
29
|
+
file = File.new filename, "w"
|
30
|
+
file << content
|
31
|
+
file.close
|
32
|
+
end
|
33
|
+
|
34
|
+
def read_file filename
|
35
|
+
file = File.new filename
|
36
|
+
content = file.read
|
37
|
+
file.close
|
38
|
+
content
|
39
|
+
end
|
40
|
+
|
41
|
+
def ctime filename
|
42
|
+
File.new(filename).ctime
|
43
|
+
end
|
44
|
+
|
45
|
+
def list_templates
|
46
|
+
templates = real_dir_entries template_path
|
47
|
+
templates.delete ANY_TEMPLATE
|
48
|
+
templates.join(', ')
|
49
|
+
end
|
50
|
+
|
51
|
+
def scaffold template
|
52
|
+
begin
|
53
|
+
dir_path = "#{template_path}/#{template}"
|
54
|
+
to_copy = real_dir_entries dir_path
|
55
|
+
rescue
|
56
|
+
dir_path = "#{template_path}/#{ANY_TEMPLATE}"
|
57
|
+
to_copy = real_dir_entries dir_path
|
58
|
+
end
|
59
|
+
to_copy.each do |item|
|
60
|
+
FileUtils.cp_r "#{dir_path}/#{item}", "."
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def template_path
|
65
|
+
file_path_elements = __FILE__.split '/'
|
66
|
+
file_path_elements[-2..-1] = nil
|
67
|
+
(file_path_elements << 'templates').join '/'
|
68
|
+
end
|
69
|
+
|
70
|
+
def real_dir_entries dir
|
71
|
+
current_and_parent = 2
|
72
|
+
Dir.new(dir).entries.drop current_and_parent
|
73
|
+
end
|
74
|
+
|
75
|
+
def make_os_specific text
|
76
|
+
text.gsub('%sh%', shell_extension).gsub('%:%', path_separator).gsub('%rm%', remove_command_name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def remove_command_name
|
80
|
+
windows? ? 'delete' : 'rm'
|
81
|
+
end
|
82
|
+
|
83
|
+
def shell_extension
|
84
|
+
windows? ? 'cmd' : 'sh'
|
85
|
+
end
|
86
|
+
|
87
|
+
def path_separator
|
88
|
+
windows? ? ';' : ':'
|
89
|
+
end
|
90
|
+
|
91
|
+
def windows?
|
92
|
+
RUBY_PLATFORM.downcase.include? "windows"
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
data/app/state_reader.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'filename_formatter'
|
2
|
+
|
3
|
+
class StateReader
|
4
|
+
|
5
|
+
attr_accessor :session_id, :next_step
|
6
|
+
|
7
|
+
def initialize shell
|
8
|
+
@filename_formatter = FilenameFormatter.new
|
9
|
+
@shell = shell
|
10
|
+
@next_step = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def state_count
|
14
|
+
dummy_dirs_current_and_parent = 2
|
15
|
+
Dir.new(@filename_formatter.session_dir @session_id).count - dummy_dirs_current_and_parent
|
16
|
+
end
|
17
|
+
|
18
|
+
def enough_states?
|
19
|
+
state_count >= states_needed_for_one_move
|
20
|
+
end
|
21
|
+
|
22
|
+
def states_needed_for_one_move
|
23
|
+
2
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_state_dir
|
27
|
+
@filename_formatter.state_dir(@session_id, @next_step)
|
28
|
+
end
|
29
|
+
|
30
|
+
def has_next_state
|
31
|
+
File.exist?(get_state_dir)
|
32
|
+
end
|
33
|
+
|
34
|
+
def read_next_state
|
35
|
+
state = State.new
|
36
|
+
state_dir = get_state_dir
|
37
|
+
state.time = @shell.ctime state_dir
|
38
|
+
state.code = @shell.read_file @filename_formatter.source_code_file(state_dir)
|
39
|
+
state.result = @shell.read_file @filename_formatter.result_file(state_dir)
|
40
|
+
@next_step += 1
|
41
|
+
state
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class State
|
47
|
+
|
48
|
+
attr_accessor :time, :code, :result
|
49
|
+
|
50
|
+
def initialize time=nil, code=nil, result=nil
|
51
|
+
@time = time
|
52
|
+
@code = code
|
53
|
+
@result = result
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
data/app/uploader.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'state_reader'
|
2
|
+
require 'progress'
|
3
|
+
require 'xml_element_extractor'
|
4
|
+
require 'rest_client'
|
5
|
+
|
6
|
+
class Uploader
|
7
|
+
|
8
|
+
def initialize hostname, framework, session_dir, state_reader = StateReader.new(ShellWrapper.new)
|
9
|
+
@hostname = hostname
|
10
|
+
@framework = framework
|
11
|
+
@state_reader = state_reader
|
12
|
+
@state_reader.session_id = session_dir.gsub('.codersdojo/', '')
|
13
|
+
end
|
14
|
+
|
15
|
+
def upload_kata
|
16
|
+
RestClient.post "#{@hostname}#{@@kata_path}", {:framework => @framework}
|
17
|
+
end
|
18
|
+
|
19
|
+
def upload_state kata_id
|
20
|
+
state = @state_reader.read_next_state
|
21
|
+
RestClient.post "#{@hostname}#{@@kata_path}/#{kata_id}#{@@state_path}", {:code => state.code, :result => state.result, :created_at => state.time}
|
22
|
+
Progress.next
|
23
|
+
end
|
24
|
+
|
25
|
+
def upload_states kata_id
|
26
|
+
Progress.write_empty_progress @state_reader.state_count
|
27
|
+
while @state_reader.has_next_state
|
28
|
+
upload_state kata_id
|
29
|
+
end
|
30
|
+
Progress.end
|
31
|
+
end
|
32
|
+
|
33
|
+
def upload_kata_and_states
|
34
|
+
kata = upload_kata
|
35
|
+
upload_states(XMLElementExtractor.extract('kata/id', kata))
|
36
|
+
"This is the link to review and comment your kata #{XMLElementExtractor.extract('kata/short-url', kata)}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def upload
|
40
|
+
return upload_kata_and_states if @state_reader.enough_states?
|
41
|
+
return "You need at least two states"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
@@kata_path = '/katas'
|
46
|
+
@@state_path = '/states'
|
47
|
+
|
48
|
+
end
|
49
|
+
|
data/bin/codersdojo
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
codersdojo_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'app'))
|
3
|
+
infrastructure_dir = "#{codersdojo_dir}/infrastructure"
|
4
|
+
models_dir = "#{codersdojo_dir}/models"
|
3
5
|
$LOAD_PATH.unshift(codersdojo_dir) unless $LOAD_PATH.include?(codersdojo_dir)
|
6
|
+
$LOAD_PATH.unshift(infrastructure_dir) unless $LOAD_PATH.include?(infrastructure_dir)
|
7
|
+
$LOAD_PATH.unshift(models_dir) unless $LOAD_PATH.include?(models_dir)
|
4
8
|
require 'codersdojo'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'argument_parser'
|
2
|
+
|
3
|
+
describe ArgumentParser do
|
4
|
+
|
5
|
+
before (:each) do
|
6
|
+
@controller_mock = mock.as_null_object
|
7
|
+
@parser = ArgumentParser.new @controller_mock
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should reject empty command" do
|
11
|
+
lambda{@parser.parse []}.should raise_error
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should reject unknown command" do
|
15
|
+
lambda{@parser.parse "unknown command"}.should raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should accept help command" do
|
19
|
+
@controller_mock.should_receive(:help).with(nil)
|
20
|
+
@parser.parse ["help"]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should accept start command" do
|
24
|
+
@controller_mock.should_receive(:start).with "aCommand", "aFile"
|
25
|
+
@parser.parse ["start", "aCommand","aFile"]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should prepend *.sh start scripts with 'bash'" do
|
29
|
+
@controller_mock.should_receive(:start).with "bash aCommand.sh", "aFile"
|
30
|
+
@parser.parse ["start", "aCommand.sh","aFile"]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should prepend *.bat start scripts with 'start'" do
|
34
|
+
@controller_mock.should_receive(:start).with "start aCommand.bat", "aFile"
|
35
|
+
@parser.parse ["start", "aCommand.bat","aFile"]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should prepend *.cmd start scripts with 'start'" do
|
39
|
+
@controller_mock.should_receive(:start).with "start aCommand.cmd", "aFile"
|
40
|
+
@parser.parse ["start", "aCommand.cmd","aFile"]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should accept upload command" do
|
44
|
+
@controller_mock.should_receive(:upload).with "framework", "dir"
|
45
|
+
@parser.parse ["upload", "framework", "dir"]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should accept uppercase commands" do
|
49
|
+
@controller_mock.should_receive(:help).with(nil)
|
50
|
+
@parser.parse ["HELP"]
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'progress'
|
2
|
+
|
3
|
+
describe Progress do
|
4
|
+
|
5
|
+
it 'should print infos and empty progress in initialization' do
|
6
|
+
STDOUT.should_receive(:print).with("2 states to upload")
|
7
|
+
STDOUT.should_receive(:print).with("[ ]")
|
8
|
+
STDOUT.should_receive(:print).with("\b\b\b")
|
9
|
+
Progress.write_empty_progress 2
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should print dots and flush in next' do
|
13
|
+
STDOUT.should_receive(:print).with(".")
|
14
|
+
STDOUT.should_receive(:flush)
|
15
|
+
Progress.next
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should print empty line in end' do
|
19
|
+
STDOUT.should_receive(:puts)
|
20
|
+
Progress.end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/spec/runner_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'runner'
|
2
|
+
|
3
|
+
describe Runner, "in run mode" do
|
4
|
+
|
5
|
+
WORKSPACE_DIR = ".codersdojo"
|
6
|
+
SESSION_ID = "id0815"
|
7
|
+
SESSION_DIR = "#{WORKSPACE_DIR}/#{SESSION_ID}"
|
8
|
+
STATE_DIR_PREFIX = "#{SESSION_DIR}/state_"
|
9
|
+
|
10
|
+
before (:each) do
|
11
|
+
@shell_mock = mock.as_null_object
|
12
|
+
@session_id_provider_mock = mock.as_null_object
|
13
|
+
@session_id_provider_mock.should_receive(:generate_id).and_return SESSION_ID
|
14
|
+
@runner = Runner.new @shell_mock, @session_id_provider_mock
|
15
|
+
@runner.file = "my_file.rb"
|
16
|
+
@runner.run_command = "ruby"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should create codersdojo directory if it doesn't exist with session sub-directory" do
|
20
|
+
@shell_mock.should_receive(:mkdir_p).with SESSION_DIR
|
21
|
+
@runner.start
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should run ruby command on kata file given as argument" do
|
25
|
+
@shell_mock.should_receive(:execute).with "ruby my_file.rb"
|
26
|
+
@runner.start
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should create a state directory for every state" do
|
30
|
+
@shell_mock.should_receive(:ctime).with("my_file.rb").and_return 1
|
31
|
+
@shell_mock.should_receive(:mkdir).with "#{STATE_DIR_PREFIX}0"
|
32
|
+
@shell_mock.should_receive(:cp).with "my_file.rb", "#{STATE_DIR_PREFIX}0"
|
33
|
+
@runner.start
|
34
|
+
@shell_mock.should_receive(:ctime).with("my_file.rb").and_return 2
|
35
|
+
@shell_mock.should_receive(:mkdir).with "#{STATE_DIR_PREFIX}1"
|
36
|
+
@shell_mock.should_receive(:cp).with "my_file.rb", "#{STATE_DIR_PREFIX}1"
|
37
|
+
@runner.execute
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should not run if the kata file wasn't modified" do
|
41
|
+
a_time = Time.new
|
42
|
+
@shell_mock.should_receive(:ctime).with("my_file.rb").and_return a_time
|
43
|
+
@shell_mock.should_receive(:mkdir).with "#{STATE_DIR_PREFIX}0"
|
44
|
+
@shell_mock.should_receive(:cp).with "my_file.rb", "#{STATE_DIR_PREFIX}0"
|
45
|
+
@runner.start
|
46
|
+
@shell_mock.should_receive(:ctime).with("my_file.rb").and_return a_time
|
47
|
+
@shell_mock.should_not_receive(:mkdir).with "#{STATE_DIR_PREFIX}1"
|
48
|
+
@shell_mock.should_not_receive(:cp).with "my_file.rb", "#{STATE_DIR_PREFIX}1"
|
49
|
+
@runner.execute
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should capture run result into state directory" do
|
53
|
+
@shell_mock.should_receive(:execute).and_return "spec result"
|
54
|
+
@shell_mock.should_receive(:write_file).with "#{STATE_DIR_PREFIX}0/result.txt", "spec result"
|
55
|
+
@runner.start
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'session_id_generator'
|
2
|
+
|
3
|
+
describe SessionIdGenerator do
|
4
|
+
|
5
|
+
before (:each) do
|
6
|
+
@time_mock = mock
|
7
|
+
@generator = SessionIdGenerator.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should format id as yyyy-mm-dd_hh-mm-ss" do
|
11
|
+
@time_mock.should_receive(:year).and_return 2010
|
12
|
+
@time_mock.should_receive(:month).and_return 8
|
13
|
+
@time_mock.should_receive(:day).and_return 7
|
14
|
+
@time_mock.should_receive(:hour).and_return 6
|
15
|
+
@time_mock.should_receive(:min).and_return 5
|
16
|
+
@time_mock.should_receive(:sec).and_return 0
|
17
|
+
@generator.generate_id(@time_mock).should == "2010-08-07_06-05-00"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|