dtf 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +13 -0
- data/README.md +66 -0
- data/bin/dtf +7 -0
- data/lib/dtf.rb +94 -0
- data/lib/dtf/active_patches.rb +21 -0
- data/lib/dtf/plugins.rb +102 -0
- data/lib/plugins/dtf/comment_test_input.rb +40 -0
- data/lib/plugins/dtf/env_match_test.rb +18 -0
- data/lib/plugins/dtf/error_summary_output.rb +93 -0
- data/lib/plugins/dtf/output_match_test.rb +17 -0
- data/lib/plugins/dtf/stats_output.rb +73 -0
- data/lib/plugins/dtf/status_test.rb +17 -0
- data/lib/plugins/dtf/text_output.rb +52 -0
- metadata +92 -0
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2011 Michal Papis
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Deryls Testing Framework
|
2
|
+
|
3
|
+
DTF is a pluggable framework for testing shell scripts (at least now).
|
4
|
+
DTF also is an umbrella which incorporates (eventually) multiple gems, each of which provides additional functionality
|
5
|
+
to DTF. DTF is the skeleton upon which all other dtf-* gems build.
|
6
|
+
|
7
|
+
|
8
|
+
## Usage
|
9
|
+
|
10
|
+
$ gem install dtf
|
11
|
+
$ dtf <path/to/file>_comment_test.sh
|
12
|
+
|
13
|
+
## Comment tests
|
14
|
+
|
15
|
+
Filename has to end with _comment_test.sh
|
16
|
+
|
17
|
+
Example test file:
|
18
|
+
|
19
|
+
## User comments start with double #
|
20
|
+
## command can be writen in one line with multiple tests:
|
21
|
+
true # status=0; match=/^$/
|
22
|
+
## or tests can be placed in following lines:
|
23
|
+
false
|
24
|
+
# status=1
|
25
|
+
|
26
|
+
### Matchers
|
27
|
+
|
28
|
+
The test can be negated by replacing `=` with `!=`
|
29
|
+
|
30
|
+
- status=<number> - check if command returned given status (0 is success)
|
31
|
+
- match=/<regexp>/ - regexp match command output
|
32
|
+
- env[<var_name>]=/<regexp>/ - regexp match the given environment variable name
|
33
|
+
|
34
|
+
## Example
|
35
|
+
|
36
|
+
$ bin/dtf example_tests/comment/*
|
37
|
+
F..
|
38
|
+
##### Processed commands 2 of 2, success tests 2 of 3, failure tests 1 of 3.
|
39
|
+
$ false
|
40
|
+
# failed: status = 0 # was 1
|
41
|
+
|
42
|
+
$ bin/dtf example_tests/comment/* --text
|
43
|
+
##### starting test failure.
|
44
|
+
$ false
|
45
|
+
# failed: status = 0 # was 1
|
46
|
+
##### starting test success.
|
47
|
+
$ true
|
48
|
+
# passed: status = 0
|
49
|
+
# passed: status != 1
|
50
|
+
##### Processed commands 2 of 2, success tests 2 of 3, failure tests 1 of 3.
|
51
|
+
|
52
|
+
## Internal architecture
|
53
|
+
|
54
|
+
Framework will load plugins from any available gem and local `lib/` path, for example:
|
55
|
+
|
56
|
+
lib/plugins/dtf/text_output.rb
|
57
|
+
lib/plugins/dtf/status_test.rb
|
58
|
+
lib/plugins/dtf/comment_test_input.rb
|
59
|
+
|
60
|
+
The search pattern is:
|
61
|
+
|
62
|
+
lib/plugins/dtf/*.rb
|
63
|
+
|
64
|
+
And plugins are selected with:
|
65
|
+
|
66
|
+
lib/plugins/dtf/*_{input,test,output}.rb
|
data/bin/dtf
ADDED
data/lib/dtf.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'singleton'
|
3
|
+
require 'yaml'
|
4
|
+
require 'session'
|
5
|
+
|
6
|
+
lib_root = File.dirname( __FILE__ )
|
7
|
+
|
8
|
+
# include lib in path so plugins get found with Gem.find_files
|
9
|
+
$:.unshift "#{lib_root}"
|
10
|
+
|
11
|
+
class DTF; end
|
12
|
+
# load dtf/*.rb
|
13
|
+
Dir["#{lib_root}/dtf/*.rb"].each{|lib| require lib }
|
14
|
+
|
15
|
+
class DTF
|
16
|
+
def initialize
|
17
|
+
@ruby = File.join(RbConfig::CONFIG["bindir"],RbConfig::CONFIG["ruby_install_name"])
|
18
|
+
@plugins = DTF::Plugins.instance
|
19
|
+
@failures = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def run_tests args
|
23
|
+
@plugins.load(%w( all_test ))
|
24
|
+
input_files, not_processed = @plugins.parse_args(args)
|
25
|
+
if not_processed.size > 0
|
26
|
+
$stderr.puts "No plugin recognized this option '#{not_processed*" "}'."
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
@plugins.load(%w( ErrorSummaryOutput )) if @plugins.output_plugins.empty?
|
30
|
+
process(input_files)
|
31
|
+
@failures == 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def process input_files
|
35
|
+
@plugins.output_plugins(:start_processing)
|
36
|
+
input_files.each do |plugin,file|
|
37
|
+
process_test( plugin.load(file) )
|
38
|
+
end
|
39
|
+
@plugins.output_plugins(:end_processing)
|
40
|
+
end
|
41
|
+
|
42
|
+
def env shell
|
43
|
+
Hash[ shell.execute(
|
44
|
+
@ruby + ' -e \'ENV.each{|k,v| printf "#{k}=#{v}\0"}\''
|
45
|
+
)[0].split("\0").map{|var| var.split('=', 2) } ]
|
46
|
+
end
|
47
|
+
|
48
|
+
def process_test test
|
49
|
+
name, commands = test[:name], test[:commands]
|
50
|
+
shell = Session::Bash.new
|
51
|
+
_env = env(shell)
|
52
|
+
@plugins.output_plugins(:start_test, test, _env)
|
53
|
+
commands.each do |line|
|
54
|
+
command, tests = line[:cmd], line[:tests]
|
55
|
+
@plugins.output_plugins(:start_command, line)
|
56
|
+
_stdout = StringIO.new
|
57
|
+
_stderr = StringIO.new
|
58
|
+
_stdboth = StringIO.new
|
59
|
+
shell.execute "#{command}" do |out, err|
|
60
|
+
if out
|
61
|
+
@plugins.output_plugins(:command_out, out)
|
62
|
+
_stdout << out
|
63
|
+
_stdboth << out
|
64
|
+
end
|
65
|
+
if err
|
66
|
+
@plugins.output_plugins(:command_err, err)
|
67
|
+
_stderr << err
|
68
|
+
_stdboth << err
|
69
|
+
end
|
70
|
+
end
|
71
|
+
_status = shell.status
|
72
|
+
_env = env(shell)
|
73
|
+
@plugins.output_plugins(:end_command, line, _status, _env)
|
74
|
+
process_command_tests _stdout.string, _stderr.string, _stdboth.string, _status, _env, tests
|
75
|
+
end
|
76
|
+
@plugins.output_plugins(:end_test, test)
|
77
|
+
end
|
78
|
+
|
79
|
+
def process_command_tests _stdout, _stderr, _stdboth, _status, env, tests
|
80
|
+
tests.each do |test|
|
81
|
+
plugin = @plugins.test_plugins.find{|_plugin| _plugin.matches? test }
|
82
|
+
if plugin.nil?
|
83
|
+
status, msg = false, "Could not find plugin for test '#{test}'."
|
84
|
+
else
|
85
|
+
status, msg = plugin.execute(test, _stdout, _stderr, _stdboth, _status, env)
|
86
|
+
end
|
87
|
+
@failures+=1 unless status
|
88
|
+
@plugins.output_plugins(:test_processed, test, status, msg)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class << self
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
unless String.method_defined? :blank?
|
2
|
+
String.class_eval do
|
3
|
+
def blank?
|
4
|
+
self == ""
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
unless Array.method_defined? :blank?
|
9
|
+
Array.class_eval do
|
10
|
+
def blank?
|
11
|
+
size == 0
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
unless NilClass.method_defined? :blank?
|
16
|
+
NilClass.class_eval do
|
17
|
+
def blank?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/dtf/plugins.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
class DTF::Plugins
|
2
|
+
include Singleton
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
detect
|
6
|
+
@additional_plugins = []
|
7
|
+
@input_plugins = []
|
8
|
+
@output_plugins = []
|
9
|
+
@test_plugins = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def detect
|
13
|
+
@plugins = Gem.find_files('plugins/dtf/*.rb')
|
14
|
+
end
|
15
|
+
|
16
|
+
def add plugin
|
17
|
+
@additional_plugins << plugin
|
18
|
+
end
|
19
|
+
|
20
|
+
def delete plugin
|
21
|
+
@additional_plugins.delete plugin
|
22
|
+
end
|
23
|
+
|
24
|
+
def file_to_class item
|
25
|
+
File.basename(item,'.rb').capitalize.gsub(/_(.)/){ $1.upcase }
|
26
|
+
end
|
27
|
+
|
28
|
+
def list pattern=nil
|
29
|
+
# collect to lists
|
30
|
+
_list = @plugins + @additional_plugins
|
31
|
+
# filter by pattern if given
|
32
|
+
_list = _list.select{|item| item.match("_#{pattern}.rb$") } unless pattern.nil?
|
33
|
+
# get path and class name
|
34
|
+
_list.map!{|item| [ item, file_to_class(item), pattern ] }
|
35
|
+
# TODO: limit plugin versions (highest || use bundler)
|
36
|
+
_list.each{|item, klass, type| require item }
|
37
|
+
_list
|
38
|
+
end
|
39
|
+
|
40
|
+
def load wanted
|
41
|
+
[ :input, :test, :output ].each do |type|
|
42
|
+
_list = list(type)
|
43
|
+
if ! wanted.include?("all") && ! wanted.include?("all_#{type}")
|
44
|
+
_list = _list.select{|item, klass, _type| wanted.include?(klass) }
|
45
|
+
end
|
46
|
+
_list.each{|item, klass, _type|
|
47
|
+
klass = DTF.const_get(klass)
|
48
|
+
instance_variable_get("@#{type}_plugins".to_sym) << klass.new
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def match_arg_klass arg, klass, type
|
54
|
+
klass = DTF.const_get(klass)
|
55
|
+
return nil unless klass.respond_to? :argument_matches?
|
56
|
+
matches = klass.argument_matches? arg
|
57
|
+
return nil if matches.nil?
|
58
|
+
matches.each do |match|
|
59
|
+
case match
|
60
|
+
when :load
|
61
|
+
instance_variable_get("@#{type}_plugins".to_sym) << klass.new
|
62
|
+
when :input
|
63
|
+
@input_files << [klass.new, arg]
|
64
|
+
else
|
65
|
+
return nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
return matches
|
69
|
+
rescue NameError
|
70
|
+
return nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_args args
|
74
|
+
@input_files, not_processed = [], []
|
75
|
+
available_plugins = [ :input, :test, :output ].map{ |type| list(type) }.flatten(1)
|
76
|
+
args.each do |arg|
|
77
|
+
matched = available_plugins.map do |item, klass, type|
|
78
|
+
match_arg_klass arg, klass, type
|
79
|
+
end.flatten.reject(&:nil?)
|
80
|
+
if matched.empty?
|
81
|
+
not_processed << arg
|
82
|
+
end
|
83
|
+
end
|
84
|
+
[ @input_files, not_processed ]
|
85
|
+
end
|
86
|
+
|
87
|
+
def input_plugins
|
88
|
+
@input_plugins
|
89
|
+
end
|
90
|
+
|
91
|
+
def output_plugins *args
|
92
|
+
if args.empty?
|
93
|
+
@output_plugins
|
94
|
+
else
|
95
|
+
@output_plugins.each{|plugin| plugin.send(*args) }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_plugins
|
100
|
+
@test_plugins
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class DTF::CommentTestInput
|
2
|
+
def initialize
|
3
|
+
end
|
4
|
+
|
5
|
+
def self.argument_matches? argument
|
6
|
+
if argument =~ /_comment_test\.sh$/ && File.exist?(argument)
|
7
|
+
[:load, :input]
|
8
|
+
else
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def load file_name
|
14
|
+
lines = []
|
15
|
+
File.readlines(file_name).each{|line|
|
16
|
+
# Fix jruby-1.6.6-d19 bug with empty strings from files
|
17
|
+
line = "#{line}"
|
18
|
+
# remove human comments
|
19
|
+
line.sub!(/##.*$/,'')
|
20
|
+
# reject empty lines
|
21
|
+
line.strip!
|
22
|
+
next if line =~ /^$/
|
23
|
+
# extract command and tests
|
24
|
+
cmd, tests = line.split("#")
|
25
|
+
cmd.strip!
|
26
|
+
tests = if tests.blank?
|
27
|
+
[]
|
28
|
+
else
|
29
|
+
tests.split(";").map(&:strip)
|
30
|
+
end
|
31
|
+
if cmd.blank?
|
32
|
+
lines.last[:tests] += tests unless lines.last.nil?
|
33
|
+
else
|
34
|
+
lines << { :cmd => cmd, :tests => tests }
|
35
|
+
end
|
36
|
+
}
|
37
|
+
name = file_name.gsub(/^.*\//,'').sub(/_comment_test\.sh$/,'')
|
38
|
+
{ :name => name, :commands => lines }
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class DTF::EnvMatchTest
|
2
|
+
MATCHER = /^env\[(.*)\]([!]?=)[~]?\/(.*)\//
|
3
|
+
|
4
|
+
def matches? test
|
5
|
+
test =~ DTF::EnvMatchTest::MATCHER
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute test, _stdout, _stderr, _stdboth, _status, env
|
9
|
+
test =~ DTF::EnvMatchTest::MATCHER
|
10
|
+
variable, sign, value = $1.strip, $2, $3
|
11
|
+
var_val = env[ variable ]
|
12
|
+
if ( sign == "=" ) ^ ( Regexp.new(value) =~ "#{var_val}" )
|
13
|
+
[ false, "failed: env #{variable} #{sign} /#{value}/ # was '#{var_val}'" ]
|
14
|
+
else
|
15
|
+
[ true, "passed: env #{variable} #{sign} /#{value}/" ]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
class DTF::ErrorSummaryOutput
|
2
|
+
RED = `tput setaf 1`
|
3
|
+
GREEN = `tput setaf 2`
|
4
|
+
YELLOW = `tput setaf 3`
|
5
|
+
BLUE = `tput setaf 4`
|
6
|
+
RESET = `tput setaf 9`
|
7
|
+
|
8
|
+
def self.argument_matches? argument
|
9
|
+
[:load] if argument == "--dotted"
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize output=nil
|
13
|
+
@counts={}
|
14
|
+
@counts[:commands] = 0
|
15
|
+
@counts[:tests] = 0
|
16
|
+
@counts[:commands_started] = 0
|
17
|
+
@counts[:commands_finished] = 0
|
18
|
+
@counts[:tests_success] = 0
|
19
|
+
@counts[:tests_failure] = 0
|
20
|
+
@counter_id = 0
|
21
|
+
@summary = {}
|
22
|
+
@output = output || $stdout
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_processing
|
26
|
+
end
|
27
|
+
|
28
|
+
def status
|
29
|
+
text = "#{BLUE}##### Processed commands #{@counts[:commands_finished]} of #{@counts[:commands]}"
|
30
|
+
if @counts[:tests_success] > 0
|
31
|
+
text += ", #{GREEN}success tests #{@counts[:tests_success]} of #{@counts[:tests]}"
|
32
|
+
end
|
33
|
+
if @counts[:tests_failure] > 0
|
34
|
+
text += ", #{RED}failure tests #{@counts[:tests_failure]} of #{@counts[:tests]}"
|
35
|
+
end
|
36
|
+
skipped = @counts[:tests] - @counts[:tests_success] - @counts[:tests_failure]
|
37
|
+
if skipped > 0
|
38
|
+
text += ", #{YELLOW}skipped tests #{skipped} of #{@counts[:tests]}"
|
39
|
+
end
|
40
|
+
text += ".#{RESET}"
|
41
|
+
text
|
42
|
+
end
|
43
|
+
|
44
|
+
def summary
|
45
|
+
@summary.sort{|a,b| ak,_=a ; bk,_=b ; ak <=> bk }.each{|k,v|
|
46
|
+
@output.puts "#{YELLOW}$ #{v[:cmd]}#{RESET}"
|
47
|
+
v[:failed_tests].each{|t| puts "#{RED}# #{t}#{RESET}" }
|
48
|
+
}
|
49
|
+
text = ""
|
50
|
+
text
|
51
|
+
end
|
52
|
+
|
53
|
+
def end_processing
|
54
|
+
@output.printf "\n"
|
55
|
+
@output.puts status
|
56
|
+
@output.puts summary
|
57
|
+
end
|
58
|
+
|
59
|
+
def start_test test, env
|
60
|
+
@counts[:commands] += test[:commands].size
|
61
|
+
tests_counts = test[:commands].map{|line| line[:tests].nil? ? 0 : line[:tests].size }
|
62
|
+
@counts[:tests] += tests_counts.empty? ? 0 : tests_counts.inject(&:+)
|
63
|
+
end
|
64
|
+
|
65
|
+
def end_test test
|
66
|
+
end
|
67
|
+
|
68
|
+
def start_command line
|
69
|
+
@counts[:commands_started] += 1
|
70
|
+
@current_line = line.merge(:counter_id => @counts[:commands_started])
|
71
|
+
end
|
72
|
+
|
73
|
+
def end_command line, status, env
|
74
|
+
@counts[:commands_finished] += 1
|
75
|
+
end
|
76
|
+
|
77
|
+
def command_out out
|
78
|
+
end
|
79
|
+
|
80
|
+
def command_err err
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_processed test, status, msg
|
84
|
+
@output.printf status ? "." : "F"
|
85
|
+
if status
|
86
|
+
@counts[:tests_success] += 1
|
87
|
+
else
|
88
|
+
@counts[:tests_failure] += 1
|
89
|
+
@summary[@current_line[:counter_id]] ||= @current_line.merge({:failed_tests=>[]})
|
90
|
+
@summary[@current_line[:counter_id]][:failed_tests] << msg
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class DTF::OutputMatchTest
|
2
|
+
MATCHER = /^match([!]?=)[~]?\/(.*)\//
|
3
|
+
|
4
|
+
def matches? test
|
5
|
+
test =~ DTF::OutputMatchTest::MATCHER
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute test, _stdout, _stderr, _stdboth, _status, env
|
9
|
+
test =~ DTF::OutputMatchTest::MATCHER
|
10
|
+
sign, value = $1, $2
|
11
|
+
if ( sign == "=" ) ^ ( Regexp.new(value) =~ "#{_stdboth}" )
|
12
|
+
[ false, "failed: match #{sign} /#{value}/" ]
|
13
|
+
else
|
14
|
+
[ true, "passed: match #{sign} /#{value}/" ]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class DTF::StatsOutput
|
2
|
+
RED = `tput setaf 1`
|
3
|
+
GREEN = `tput setaf 2`
|
4
|
+
YELLOW = `tput setaf 3`
|
5
|
+
BLUE = `tput setaf 4`
|
6
|
+
RESET = `tput setaf 9`
|
7
|
+
|
8
|
+
def self.argument_matches? argument
|
9
|
+
[:load] if argument == "--text"
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@counts={}
|
14
|
+
@counts[:commands] = 0
|
15
|
+
@counts[:tests] = 0
|
16
|
+
@counts[:commands_finished] = 0
|
17
|
+
@counts[:tests_success] = 0
|
18
|
+
@counts[:tests_failure] = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_processing
|
22
|
+
end
|
23
|
+
|
24
|
+
def status
|
25
|
+
text = "#{BLUE}##### Processed commands #{@counts[:commands_finished]} of #{@counts[:commands]}"
|
26
|
+
if @counts[:tests_success] > 0
|
27
|
+
text += ", #{GREEN}success tests #{@counts[:tests_success]} of #{@counts[:tests]}"
|
28
|
+
end
|
29
|
+
if @counts[:tests_failure] > 0
|
30
|
+
text += ", #{RED}failure tests #{@counts[:tests_failure]} of #{@counts[:tests]}"
|
31
|
+
end
|
32
|
+
skipped = @counts[:tests] - @counts[:tests_success] - @counts[:tests_failure]
|
33
|
+
if skipped > 0
|
34
|
+
text += ", #{YELLOW}skipped tests #{skipped} of #{@counts[:tests]}"
|
35
|
+
end
|
36
|
+
text += ".#{RESET}"
|
37
|
+
text
|
38
|
+
end
|
39
|
+
|
40
|
+
def end_processing
|
41
|
+
puts status
|
42
|
+
end
|
43
|
+
|
44
|
+
def start_test test, env
|
45
|
+
@counts[:commands] += test[:commands].size
|
46
|
+
tests_counts = test[:commands].map{|line| line[:tests].nil? ? 0 : line[:tests].size }
|
47
|
+
@counts[:tests] += tests_counts.empty? ? 0 : tests_counts.inject(&:+)
|
48
|
+
end
|
49
|
+
|
50
|
+
def end_test test
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_command line
|
54
|
+
end
|
55
|
+
|
56
|
+
def end_command line, status, env
|
57
|
+
@counts[:commands_finished] += 1
|
58
|
+
end
|
59
|
+
|
60
|
+
def command_out out
|
61
|
+
end
|
62
|
+
|
63
|
+
def command_err err
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_processed test, status, msg
|
67
|
+
if status
|
68
|
+
@counts[:tests_success] += 1
|
69
|
+
else
|
70
|
+
@counts[:tests_failure] += 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class DTF::StatusTest
|
2
|
+
MATCHER = /^status([!]?=)([[:digit:]]+)$/
|
3
|
+
|
4
|
+
def matches? test
|
5
|
+
test =~ DTF::StatusTest::MATCHER
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute test, _stdout, _stderr, _stdboth, _status, env
|
9
|
+
test =~ DTF::StatusTest::MATCHER
|
10
|
+
sign, value = $1, $2.to_i
|
11
|
+
if ( sign == "=" ) ^ ( _status == value )
|
12
|
+
[ false, "failed: status #{sign} #{value} # was #{_status}" ]
|
13
|
+
else
|
14
|
+
[ true, "passed: status #{sign} #{value}" ]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class DTF::TextOutput
|
2
|
+
RED = `tput setaf 1`
|
3
|
+
GREEN = `tput setaf 2`
|
4
|
+
YELLOW = `tput setaf 3`
|
5
|
+
BLUE = `tput setaf 4`
|
6
|
+
RESET = `tput setaf 9`
|
7
|
+
|
8
|
+
def self.argument_matches? argument
|
9
|
+
[:load] if argument == "--text"
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
end
|
14
|
+
|
15
|
+
def start_processing
|
16
|
+
end
|
17
|
+
|
18
|
+
def end_processing
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_test test, env
|
22
|
+
puts "#{BLUE}##### starting test #{test[:name]}.#{RESET}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def end_test test
|
26
|
+
#puts "#{BLUE}##### finished test #{test[:name]}.#{RESET}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def start_command line
|
30
|
+
puts "#{YELLOW}$ #{line[:cmd]}#{RESET}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def end_command line, status, env
|
34
|
+
#puts ": $?=#{status}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def command_out out
|
38
|
+
puts out
|
39
|
+
end
|
40
|
+
|
41
|
+
def command_err err
|
42
|
+
puts err
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_processed test, status, msg
|
46
|
+
if status
|
47
|
+
puts "#{GREEN}# #{msg}#{RESET}"
|
48
|
+
else
|
49
|
+
puts "#{RED}# #{msg}#{RESET}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dtf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Deryl R. Doucette
|
14
|
+
- Michal Papis
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2012-05-08 00:00:00 Z
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: session
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
version: "3.0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
description: Testing Framework solely based on plugins. For now only tests using Bash.
|
37
|
+
email: mpapis+dtf@gmail.com
|
38
|
+
executables:
|
39
|
+
- dtf
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- lib/dtf.rb
|
46
|
+
- lib/dtf/active_patches.rb
|
47
|
+
- lib/dtf/plugins.rb
|
48
|
+
- lib/plugins/dtf/output_match_test.rb
|
49
|
+
- lib/plugins/dtf/error_summary_output.rb
|
50
|
+
- lib/plugins/dtf/stats_output.rb
|
51
|
+
- lib/plugins/dtf/text_output.rb
|
52
|
+
- lib/plugins/dtf/status_test.rb
|
53
|
+
- lib/plugins/dtf/env_match_test.rb
|
54
|
+
- lib/plugins/dtf/comment_test_input.rb
|
55
|
+
- bin/dtf
|
56
|
+
- LICENSE
|
57
|
+
- README.md
|
58
|
+
homepage: http://github.com/dtf-gems/dtf
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.8.23
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Deryl Testing Framework
|
91
|
+
test_files: []
|
92
|
+
|