rcomp 0.1.1 → 0.2.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.
- 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
|