rcomp 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -6
- data/CHANGELOG.rdoc +8 -0
- data/Gemfile.lock +2 -1
- data/README.md +24 -18
- data/Rakefile +5 -0
- data/features/generate.feature +94 -2
- data/features/init.feature +36 -12
- data/features/step_definitions/test_steps.rb +5 -0
- data/features/step_definitions/version_steps.rb +7 -0
- data/features/support/env.rb +27 -20
- data/features/test.feature +104 -2
- data/features/version.feature +1 -1
- data/lib/rcomp.rb +2 -0
- data/lib/rcomp/actions.rb +6 -0
- data/lib/rcomp/cli.rb +20 -57
- data/lib/rcomp/conf.rb +30 -74
- data/lib/rcomp/initializer.rb +108 -0
- data/lib/rcomp/process.rb +44 -0
- data/lib/rcomp/reporter.rb +12 -15
- data/lib/rcomp/runner.rb +20 -22
- data/lib/rcomp/suite.rb +19 -2
- data/lib/rcomp/version.rb +1 -1
- data/rcomp.gemspec +5 -5
- metadata +24 -6
- data/features/set_command.feature +0 -24
- data/features/set_directory.feature +0 -22
data/features/version.feature
CHANGED
data/lib/rcomp.rb
CHANGED
data/lib/rcomp/actions.rb
CHANGED
data/lib/rcomp/cli.rb
CHANGED
@@ -3,9 +3,10 @@ require 'thor'
|
|
3
3
|
module RComp
|
4
4
|
class CLI < Thor
|
5
5
|
|
6
|
-
include
|
6
|
+
include Thor::Actions
|
7
7
|
include RComp::Runner
|
8
8
|
include RComp::Suite
|
9
|
+
include RComp::Initializer
|
9
10
|
|
10
11
|
def initialize(args=[], options={}, config={})
|
11
12
|
super
|
@@ -13,69 +14,47 @@ module RComp
|
|
13
14
|
@conf = Conf.instance
|
14
15
|
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
###
|
18
|
+
# CLI Commands
|
19
|
+
###
|
19
20
|
|
20
|
-
# init
|
21
21
|
desc "init", "Setup rcomp test directory"
|
22
22
|
def init
|
23
|
-
|
24
|
-
puts "RComp already initialized"
|
25
|
-
exit 1
|
26
|
-
end
|
23
|
+
guard_initialized
|
27
24
|
|
28
|
-
unless
|
29
|
-
|
30
|
-
exit 1
|
25
|
+
unless command_exists?
|
26
|
+
@conf.set_command(ask("Enter the command you want to test:"))
|
31
27
|
end
|
32
28
|
|
33
|
-
|
34
|
-
mkdir @conf.root
|
35
|
-
mkdir @conf.test_root
|
36
|
-
mkdir @conf.expected_root
|
37
|
-
mkdir @conf.result_root
|
38
|
-
|
29
|
+
initialize_directories
|
39
30
|
puts "RComp successfully initialized"
|
40
31
|
end
|
41
32
|
|
42
|
-
|
33
|
+
|
43
34
|
desc "version", "Prints RComp's version information"
|
44
35
|
def version
|
45
36
|
puts "RComp version #{RComp::VERSION}"
|
46
37
|
end
|
47
|
-
map %w(-v --version) => :version
|
48
38
|
|
49
|
-
|
50
|
-
desc "set_command COMMAND", "Sets the command RComp will run tests with"
|
51
|
-
def set_command(command)
|
52
|
-
@conf.set_conf_value("command", command)
|
53
|
-
end
|
54
|
-
map "c" => :set_command
|
39
|
+
map %w(-v --version) => :version
|
55
40
|
|
56
|
-
# set-directory
|
57
|
-
desc "set_directory PATH", "Set the directory RComp will store files"
|
58
|
-
def set_directory(path)
|
59
|
-
@conf.set_conf_value("directory", path)
|
60
|
-
end
|
61
|
-
map "d" => :set_directory
|
62
41
|
|
63
|
-
# test
|
64
42
|
desc "test", "Run all tests"
|
65
43
|
method_option :grep,
|
66
44
|
:type => :string,
|
67
45
|
:desc => "Only test files that match pattern"
|
68
46
|
def test
|
69
|
-
|
47
|
+
guard_uninitialized
|
70
48
|
if @options[:grep]
|
71
49
|
run_suite(load_suite(@options[:grep]), :test)
|
72
50
|
else
|
73
51
|
run_suite(load_suite, :test)
|
74
52
|
end
|
75
53
|
end
|
54
|
+
|
76
55
|
map "t" => :test
|
77
56
|
|
78
|
-
|
57
|
+
|
79
58
|
desc "generate", "Generate expected output for all tests"
|
80
59
|
method_option :grep,
|
81
60
|
:type => :string,
|
@@ -86,11 +65,14 @@ module RComp
|
|
86
65
|
:aliases => "-O",
|
87
66
|
:desc => "Overwrite expected output file for test if present"
|
88
67
|
def generate
|
89
|
-
|
68
|
+
guard_uninitialized
|
90
69
|
|
91
70
|
# Display confirmation dialouge when -O is passed without filter
|
92
71
|
if !@options[:grep] && options.overwrite
|
93
|
-
|
72
|
+
unless yes? "This will overwrite all existing expected results."
|
73
|
+
say 'Aborting...'
|
74
|
+
exit 1
|
75
|
+
end
|
94
76
|
end
|
95
77
|
|
96
78
|
if @options[:grep]
|
@@ -99,26 +81,7 @@ module RComp
|
|
99
81
|
run_suite(load_suite, :generate, @options)
|
100
82
|
end
|
101
83
|
end
|
102
|
-
map "g" => :generate
|
103
|
-
|
104
|
-
private
|
105
|
-
|
106
|
-
def confirm_action(warning)
|
107
|
-
puts warning
|
108
|
-
print 'Are you sure? (Y/N) '
|
109
|
-
confirm = STDIN.gets.chomp
|
110
|
-
|
111
|
-
unless confirm.downcase == 'y'
|
112
|
-
say 'Aborting...'
|
113
|
-
exit 1
|
114
|
-
end
|
115
|
-
end
|
116
84
|
|
117
|
-
|
118
|
-
File.exists?(@conf.root) &&
|
119
|
-
File.exists?(@conf.test_root) &&
|
120
|
-
File.exists?(@conf.result_root) &&
|
121
|
-
File.exists?(@conf.expected_root)
|
122
|
-
end
|
85
|
+
map "g" => :generate
|
123
86
|
end
|
124
87
|
end
|
data/lib/rcomp/conf.rb
CHANGED
@@ -8,61 +8,58 @@ module RComp
|
|
8
8
|
include RComp::Actions
|
9
9
|
|
10
10
|
attr_reader :root, :test_root, :result_root, :expected_root,
|
11
|
-
:command
|
11
|
+
:command, :ignore, :timeout
|
12
|
+
|
13
|
+
# Conf file path
|
14
|
+
CONF_PATH = '.rcomp'
|
15
|
+
|
16
|
+
# Valid configuraiton keys
|
17
|
+
VALID_KEYS = ['directory',
|
18
|
+
'command',
|
19
|
+
'ignore',
|
20
|
+
'timeout']
|
21
|
+
|
22
|
+
# Default configuration options
|
23
|
+
DEFAULT = { 'directory' => 'rcomp',
|
24
|
+
'timeout' => 5 }
|
12
25
|
|
13
26
|
# Initialize a new config object
|
14
27
|
#
|
15
28
|
# Loads options from config file, merges with defaults
|
16
29
|
# and stores everything in memory
|
17
30
|
def initialize
|
18
|
-
#
|
19
|
-
@path = '.rcomp'
|
20
|
-
|
21
|
-
# Set valid keys for config file
|
22
|
-
@valid_keys = ['directory',
|
23
|
-
'command']
|
24
|
-
|
25
|
-
# Set default options and overwrite with config file options
|
26
|
-
@default = { 'directory' => 'rcomp' }
|
31
|
+
# Load custom configuration and merge it with defaults
|
27
32
|
@custom = read_conf_file
|
28
|
-
@conf =
|
33
|
+
@conf = DEFAULT.merge(@custom)
|
29
34
|
|
30
35
|
# Load configuration values into attributes
|
31
36
|
@command = @conf['command']
|
37
|
+
@ignore = @conf['ignore']
|
38
|
+
@ignore ||= []
|
39
|
+
@timeout = @conf['timeout']
|
32
40
|
@root = @conf['directory']
|
33
41
|
@test_root = @root + '/tests'
|
34
42
|
@result_root = @root + '/results'
|
35
43
|
@expected_root = @root + '/expected'
|
36
44
|
end
|
37
45
|
|
38
|
-
# Set a
|
46
|
+
# Set a command as a custom configuration value
|
39
47
|
#
|
40
48
|
# Returns nothing
|
41
|
-
def
|
42
|
-
@custom[
|
43
|
-
puts "
|
49
|
+
def set_command(command)
|
50
|
+
@custom['command'] = command
|
51
|
+
puts "Command set to #{command}"
|
44
52
|
write_conf_file
|
45
53
|
end
|
46
|
-
|
47
|
-
# Emit error unless all required conf keys are present in conf file
|
48
|
-
#
|
49
|
-
# Returns nothing
|
50
|
-
def require_basic_conf
|
51
|
-
require_command
|
52
|
-
require_root_exists
|
53
|
-
require_root_subdirs
|
54
|
-
end
|
55
|
-
|
56
|
-
|
54
|
+
|
57
55
|
private
|
58
56
|
|
59
|
-
# Write the current config options to the config file
|
57
|
+
# Write the current custom config options to the config file
|
60
58
|
#
|
61
59
|
# Returns nothing
|
62
60
|
def write_conf_file
|
63
|
-
|
64
|
-
|
65
|
-
conf_file = File.open(@path, 'w')
|
61
|
+
touch CONF_PATH unless File.exists?(CONF_PATH)
|
62
|
+
conf_file = File.open(CONF_PATH, 'w')
|
66
63
|
conf_file.puts YAML.dump @custom
|
67
64
|
end
|
68
65
|
|
@@ -71,58 +68,17 @@ module RComp
|
|
71
68
|
# Returns a Hash of config options
|
72
69
|
def read_conf_file
|
73
70
|
conf = {}
|
74
|
-
|
75
|
-
if File.exists?(@path) && File.size?(@path)
|
76
|
-
|
71
|
+
if File.exists?(CONF_PATH) && File.size?(CONF_PATH)
|
77
72
|
# Store valid conf keys
|
78
|
-
YAML.load_file(
|
79
|
-
|
80
|
-
if @valid_keys.include? key
|
73
|
+
YAML.load_file(CONF_PATH).each do |key, value|
|
74
|
+
if VALID_KEYS.include? key
|
81
75
|
conf[key] = value
|
82
76
|
else
|
83
77
|
say "Invalid configuration key: #{key}"
|
84
78
|
end
|
85
79
|
end
|
86
80
|
end
|
87
|
-
|
88
81
|
conf
|
89
82
|
end
|
90
|
-
|
91
|
-
# Require the command config option to be set
|
92
|
-
# Print error and exit otherwise
|
93
|
-
#
|
94
|
-
# Returns nothing
|
95
|
-
def require_command
|
96
|
-
unless @command
|
97
|
-
puts "No command present"
|
98
|
-
puts "Run rcomp c COMMAND to add a command to test with"
|
99
|
-
exit 1
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# Require the existance of the root directory
|
104
|
-
# Print error and exit otherwise
|
105
|
-
#
|
106
|
-
# Returns nothing
|
107
|
-
def require_root_exists
|
108
|
-
unless File.exists? @root
|
109
|
-
puts "No RComp directory. Run rcomp init to create"
|
110
|
-
exit 1
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Require all sudirectories of the root directory to exist
|
115
|
-
# Print error and exit otherwise
|
116
|
-
#
|
117
|
-
# Returns nothing
|
118
|
-
def require_root_subdirs
|
119
|
-
unless File.exists?(@test_root) &&
|
120
|
-
File.exists?(@result_root) &&
|
121
|
-
File.exists?(@expected_root)
|
122
|
-
puts "Missing RComp directories at #{@root}"
|
123
|
-
puts "Run rcomp init to repair"
|
124
|
-
exit 1
|
125
|
-
end
|
126
|
-
end
|
127
83
|
end
|
128
84
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module RComp
|
2
|
+
module Initializer
|
3
|
+
|
4
|
+
include RComp::Actions
|
5
|
+
|
6
|
+
@@conf = Conf.instance
|
7
|
+
|
8
|
+
# Emit error unless RComp is fully initialized
|
9
|
+
#
|
10
|
+
# Returns nothing
|
11
|
+
def guard_uninitialized
|
12
|
+
guard_command_exists
|
13
|
+
guard_root_dir_exists
|
14
|
+
guard_root_subdirs_exist
|
15
|
+
end
|
16
|
+
|
17
|
+
# Emit error unless RComp is not fully initialized
|
18
|
+
#
|
19
|
+
# Returns nothing
|
20
|
+
def guard_initialized
|
21
|
+
if initialized?
|
22
|
+
puts "RComp already initialized"
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create RComp directories if they don't already exist
|
28
|
+
#
|
29
|
+
# Returns nothing
|
30
|
+
def initialize_directories
|
31
|
+
mkpath @@conf.root
|
32
|
+
mkdir @@conf.test_root
|
33
|
+
mkdir @@conf.expected_root
|
34
|
+
mkdir @@conf.result_root
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Checks for the existance of a command to test with
|
40
|
+
#
|
41
|
+
# Returns a boolean
|
42
|
+
def command_exists?
|
43
|
+
@@conf.command
|
44
|
+
end
|
45
|
+
|
46
|
+
# Checks for the existance of RComp's root directory
|
47
|
+
#
|
48
|
+
# Returns a boolean
|
49
|
+
def root_dir_exists?
|
50
|
+
File.exists?(@@conf.root)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Checks for the existance of the required subdirectories inside
|
54
|
+
# of RComp's root directory
|
55
|
+
#
|
56
|
+
# Returns a boolean
|
57
|
+
def root_subdirs_exist?
|
58
|
+
File.exists?(@@conf.test_root) &&
|
59
|
+
File.exists?(@@conf.result_root) &&
|
60
|
+
File.exists?(@conf.expected_root)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Checks to see if RComp is fully initialized
|
64
|
+
#
|
65
|
+
# Returns a boolean
|
66
|
+
def initialized?
|
67
|
+
command_exists? &&
|
68
|
+
root_dir_exists? &&
|
69
|
+
root_subdirs_exist?
|
70
|
+
end
|
71
|
+
|
72
|
+
# Require the command config option to be set
|
73
|
+
# Print error and exit otherwise
|
74
|
+
#
|
75
|
+
# Returns nothing
|
76
|
+
def guard_command_exists
|
77
|
+
unless command_exists?
|
78
|
+
puts "No command present"
|
79
|
+
puts "Run rcomp init to setup"
|
80
|
+
exit 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Require the existance of the root directory
|
85
|
+
# Print error and exit otherwise
|
86
|
+
#
|
87
|
+
# Returns nothing
|
88
|
+
def guard_root_dir_exists
|
89
|
+
unless root_dir_exists?
|
90
|
+
puts "No RComp directory"
|
91
|
+
puts "Run rcomp init to create"
|
92
|
+
exit 1
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Require all sudirectories of the root directory to exist
|
97
|
+
# Print error and exit otherwise
|
98
|
+
#
|
99
|
+
# Returns nothing
|
100
|
+
def guard_root_subdirs_exist
|
101
|
+
unless root_subdirs_exist?
|
102
|
+
puts "Missing RComp directories at #{@@conf.root}"
|
103
|
+
puts "Run rcomp init to repair"
|
104
|
+
exit 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'childprocess'
|
2
|
+
|
3
|
+
module RComp
|
4
|
+
class Process
|
5
|
+
|
6
|
+
include RComp::Actions
|
7
|
+
|
8
|
+
# Initialize a new process
|
9
|
+
#
|
10
|
+
# cmd - An array of shellwords of a command
|
11
|
+
# timeout - Time until the process is automatically killed
|
12
|
+
# out - Path to send stdout of process
|
13
|
+
# err - Path to send stderr of process
|
14
|
+
def initialize(cmd, timeout, out, err)
|
15
|
+
@timeout = timeout
|
16
|
+
@process = ChildProcess.build(*cmd)
|
17
|
+
@process.io.stdout = File.new(out, 'w')
|
18
|
+
@process.io.stderr = File.new(err, 'w')
|
19
|
+
end
|
20
|
+
|
21
|
+
# Runs a process and with a specified command and timeout
|
22
|
+
#
|
23
|
+
# Returns nothing
|
24
|
+
def run
|
25
|
+
begin @process.start
|
26
|
+
rescue ChildProcess::LaunchError => e
|
27
|
+
raise StandardError.new(e.message)
|
28
|
+
end
|
29
|
+
|
30
|
+
begin @process.poll_for_exit(@timeout)
|
31
|
+
rescue ChildProcess::TimeoutError
|
32
|
+
@timedout = true
|
33
|
+
@process.stop
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Check if the proccess timed out or not
|
38
|
+
#
|
39
|
+
# Returns a boolean
|
40
|
+
def timedout?
|
41
|
+
@timedout ||= false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|