ciat 0.4.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/History.txt +96 -0
- data/README.rdoc +135 -0
- data/Rakefile +40 -0
- data/ciat.gemspec +53 -0
- data/lib/ciat.rb +22 -0
- data/lib/ciat/cargo.rb +55 -0
- data/lib/ciat/compilers/java.rb +54 -0
- data/lib/ciat/crate.rb +58 -0
- data/lib/ciat/differs/html_differ.rb +20 -0
- data/lib/ciat/erb_helpers.rb +83 -0
- data/lib/ciat/executors/java.rb +36 -0
- data/lib/ciat/executors/parrot.rb +51 -0
- data/lib/ciat/feedback/composite.rb +20 -0
- data/lib/ciat/feedback/feedback_counter.rb +45 -0
- data/lib/ciat/feedback/html_feedback.rb +40 -0
- data/lib/ciat/feedback/return_status.rb +23 -0
- data/lib/ciat/feedback/standard_output.rb +29 -0
- data/lib/ciat/processors/basic_processing.rb +64 -0
- data/lib/ciat/processors/compilation_interpreter.rb +18 -0
- data/lib/ciat/processors/compiler.rb +18 -0
- data/lib/ciat/processors/copy.rb +37 -0
- data/lib/ciat/processors/interpreter.rb +18 -0
- data/lib/ciat/rake_task.rb +56 -0
- data/lib/ciat/suite.rb +112 -0
- data/lib/ciat/test.rb +41 -0
- data/lib/ciat/test_element.rb +44 -0
- data/lib/ciat/traffic_light.rb +39 -0
- data/lib/ciat/version.rb +7 -0
- data/lib/data/ciat.css +40 -0
- data/lib/data/elements.yml +30 -0
- data/lib/data/prototype.js +4228 -0
- data/lib/templates/detail_row.html.erb +9 -0
- data/lib/templates/detail_row/elements.html.erb +3 -0
- data/lib/templates/elements/diff.html.erb +7 -0
- data/lib/templates/elements/plain.html.erb +8 -0
- data/lib/templates/group_header.html.erb +7 -0
- data/lib/templates/report.html.erb +38 -0
- data/lib/templates/summary_row.html.erb +12 -0
- data/lib/templates/test_numbers.html.erb +12 -0
- metadata +99 -0
data/lib/ciat/crate.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
class CIAT::Crate #:nodoc:all
|
2
|
+
attr_reader :test_file
|
3
|
+
attr_reader :stub
|
4
|
+
attr_reader :output_folder
|
5
|
+
|
6
|
+
def initialize(test_file, output_folder)
|
7
|
+
@test_file = test_file
|
8
|
+
@output_folder = output_folder
|
9
|
+
end
|
10
|
+
|
11
|
+
def stub
|
12
|
+
test_file.gsub(File.extname(test_file), "")
|
13
|
+
end
|
14
|
+
|
15
|
+
def filename(*modifiers)
|
16
|
+
File.join(output_folder, [stub, *modifiers].compact.join("_"))
|
17
|
+
end
|
18
|
+
|
19
|
+
def read_test_file
|
20
|
+
File.readlines(test_file)
|
21
|
+
end
|
22
|
+
|
23
|
+
def process_test_file #:nodoc:
|
24
|
+
elements = empty_elements_hash
|
25
|
+
split_test_file.each do |name, contents|
|
26
|
+
elements[name] = CIAT::TestElement.new(name, filename(name), contents)
|
27
|
+
end
|
28
|
+
elements
|
29
|
+
end
|
30
|
+
|
31
|
+
def split_test_file #:nodoc:
|
32
|
+
tag = :description
|
33
|
+
content = ""
|
34
|
+
raw_elements = {}
|
35
|
+
read_test_file.each do |line|
|
36
|
+
if line =~ /^==== ((\w|\s)+?)\W*$/
|
37
|
+
raw_elements[tag] = content
|
38
|
+
tag = $1.gsub(" ", "_").to_sym
|
39
|
+
content = ""
|
40
|
+
else
|
41
|
+
content += line
|
42
|
+
end
|
43
|
+
end
|
44
|
+
raw_elements[tag] = content
|
45
|
+
raw_elements
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Helpers
|
50
|
+
#
|
51
|
+
private
|
52
|
+
|
53
|
+
def empty_elements_hash
|
54
|
+
Hash.new do |hash, name|
|
55
|
+
hash[name] = CIAT::TestElement.new(name, filename(name), nil)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CIAT
|
2
|
+
module Differs
|
3
|
+
# Module for implementing the diff between two files.
|
4
|
+
# The output is in HTML table rows with the expected output on the left and
|
5
|
+
# the generated on the right.
|
6
|
+
module HtmlDiffer
|
7
|
+
def html_diff(expected_file, generated_file, diff_file)
|
8
|
+
system("diff #{diff_options} '#{expected_file}' '#{generated_file}' > '#{diff_file}'")
|
9
|
+
end
|
10
|
+
|
11
|
+
# TODO: it would be nice to have line numbers in the output
|
12
|
+
def diff_options
|
13
|
+
"--old-group-format='<tr><td>%df</td><td class=\"red\"><pre>%<</pre></td><td></td><td></td></tr>' " +
|
14
|
+
"--new-group-format='<tr><td></td><td></td><td>%dF</td><td class=\"red\"><pre>%></pre><td></tr>' " +
|
15
|
+
"--changed-group-format='<tr class=\"yellow\"><td>%df</td><td><pre>%<</pre></td><td>%dF</td><td><pre>%></pre></td></tr>' " +
|
16
|
+
"--unchanged-group-format='<tr class=\"green\"><td>%df</td><td><pre>%=</pre></td><td>%dF</td><td><pre>%=</pre></td></tr>'"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# If it were easy for you to write your own HTML templates, then the methods
|
2
|
+
# in this module would be useful.
|
3
|
+
#
|
4
|
+
# <em>I don't know if it's easy to write your own HTML template!</em>
|
5
|
+
module CIAT::ERBHelpers
|
6
|
+
# Turns a traffic light into a more "testing" word: "FAILURE",
|
7
|
+
# "ERROR", "passed", "n/a".
|
8
|
+
def light_to_word(light)
|
9
|
+
case
|
10
|
+
when light.red? then "FAILURE"
|
11
|
+
when light.yellow? then "ERROR"
|
12
|
+
when light.green? then "passed"
|
13
|
+
when light.unset? then "n/a"
|
14
|
+
else
|
15
|
+
raise "cannot turn #{light} into word"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Turns a traffic light in a sentence wrapped in a classed +span+.
|
20
|
+
def light_to_sentence(prefix, light)
|
21
|
+
"<span class=\"#{light.setting}\">#{prefix} " +
|
22
|
+
case
|
23
|
+
when light.red? then "failed"
|
24
|
+
when light.yellow? then "errored"
|
25
|
+
when light.green? then "passed"
|
26
|
+
when light.unset? then "not run"
|
27
|
+
else
|
28
|
+
raise "cannot turn #{light} into a sentence"
|
29
|
+
end +
|
30
|
+
".</span>"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Capitalizes string as a title.
|
34
|
+
def title(text)
|
35
|
+
text.gsub(/\b\w/){$&.upcase}
|
36
|
+
end
|
37
|
+
|
38
|
+
# Replaces tabs with spaces because Firefox does _really_ wacky things with
|
39
|
+
# tabs in a +pre+ in a +table+.
|
40
|
+
def replace_tabs(string)
|
41
|
+
string.gsub("\t", " ")
|
42
|
+
end
|
43
|
+
|
44
|
+
def new_path?(result)
|
45
|
+
if @old_path == File.dirname(result.filename)
|
46
|
+
false
|
47
|
+
else
|
48
|
+
@old_path = File.dirname(result.filename)
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Recursively renders another template. If it's possible to write your own
|
54
|
+
# templates for reports, this will probably play a key role.
|
55
|
+
def render(file, locals)
|
56
|
+
ERB.new(read(file)).result(CIAT::TemplateBinder.new(locals).get_binding)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def read(file)
|
62
|
+
File.read(template_path(file))
|
63
|
+
end
|
64
|
+
|
65
|
+
def template_path(file)
|
66
|
+
File.join(File.dirname(__FILE__), '..', 'templates', file + ".html.erb")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Assists in binding local variables for a recursive render.
|
71
|
+
class CIAT::TemplateBinder
|
72
|
+
include CIAT::ERBHelpers
|
73
|
+
|
74
|
+
def initialize(locals)
|
75
|
+
locals.each do |variable, value|
|
76
|
+
self.class.send(:define_method, variable, Proc.new {value})
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_binding
|
81
|
+
binding
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module CIAT
|
2
|
+
module Executors
|
3
|
+
# Executor class for Java interpreters.
|
4
|
+
#
|
5
|
+
class Java
|
6
|
+
include CIAT::Processors::BasicProcessing
|
7
|
+
include CIAT::Differs::HtmlDiffer
|
8
|
+
|
9
|
+
# Traffic light
|
10
|
+
attr :light, true
|
11
|
+
attr_reader :processor_kind
|
12
|
+
|
13
|
+
# Creates a Java executor.
|
14
|
+
#
|
15
|
+
# Possible options:
|
16
|
+
# * <code>:description</code> is the description used in the HTML report
|
17
|
+
# for this processor (default: <code>"Parrot virtual machine"</code>).
|
18
|
+
def initialize(classpath, interpreter_class, options={})
|
19
|
+
@processor_kind = options[:processor_kind] || CIAT::Processors::Interpreter.new
|
20
|
+
@classpath = classpath
|
21
|
+
@interpreter_class = interpreter_class
|
22
|
+
@description = options[:description] || "in-Java interpreter"
|
23
|
+
@light = CIAT::TrafficLight.new
|
24
|
+
end
|
25
|
+
|
26
|
+
# Provides a description of the processor.
|
27
|
+
def describe
|
28
|
+
@description
|
29
|
+
end
|
30
|
+
|
31
|
+
def executable
|
32
|
+
"java -cp '#{@classpath}' #{@interpreter_class}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CIAT
|
2
|
+
module Executors
|
3
|
+
# Executor class for Parrot programs. This will execute PIR or PASM code
|
4
|
+
# using the +parrot+ executable.
|
5
|
+
#
|
6
|
+
# The Parrot executor expects <code>compilation</code> and
|
7
|
+
# <code>execution</code> elements. The <code>compilation</code> element
|
8
|
+
# is used as input (and it actually pulls in the generated version, but it
|
9
|
+
# should be the same as the expected). <code>execution</code> is
|
10
|
+
# compared.
|
11
|
+
#
|
12
|
+
# The Parrot executor allows for a <code>command line</code> element. This
|
13
|
+
# specifies the command-line arguments when the <code>compilation</code>
|
14
|
+
# is executed.
|
15
|
+
# If none is provided, no command-line arguments are used.
|
16
|
+
class Parrot
|
17
|
+
include CIAT::Processors::BasicProcessing
|
18
|
+
include CIAT::Differs::HtmlDiffer
|
19
|
+
|
20
|
+
# Traffic light
|
21
|
+
attr :light, true
|
22
|
+
attr_reader :processor_kind
|
23
|
+
|
24
|
+
# Creates a Parrot executor.
|
25
|
+
#
|
26
|
+
# Possible options:
|
27
|
+
# * <code>:description</code> is the description used in the HTML report
|
28
|
+
# for this processor (default: <code>"Parrot virtual machine"</code>).
|
29
|
+
# * <code>:command_line</code> is the description used in the HTML
|
30
|
+
# report
|
31
|
+
# for the command-line arguments (if any) (default: "Command-line
|
32
|
+
# arguments").
|
33
|
+
def initialize(options={})
|
34
|
+
@processor_kind = options[:processor_kind] ||
|
35
|
+
CIAT::Processors::Interpreter.new
|
36
|
+
@description = options[:description] || "Parrot virtual machine"
|
37
|
+
@libraries = options[:libraries] || []
|
38
|
+
@light = CIAT::TrafficLight.new
|
39
|
+
end
|
40
|
+
|
41
|
+
# Provides a description of the processor.
|
42
|
+
def describe
|
43
|
+
@description
|
44
|
+
end
|
45
|
+
|
46
|
+
def executable
|
47
|
+
(["parrot"] + @libraries.map { |l| "-L" + l }).join(" ")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# A feedback mechanism for compositing other feedbacks.
|
2
|
+
module CIAT::Feedback
|
3
|
+
class Composite
|
4
|
+
# Pass in instances of the feedbacks as arguments to the constructor.
|
5
|
+
def initialize(*feedbacks)
|
6
|
+
@feedbacks = feedbacks
|
7
|
+
end
|
8
|
+
|
9
|
+
def pre_tests(suite)
|
10
|
+
@feedbacks.each { |feedback| feedback.pre_tests(suite) }
|
11
|
+
end
|
12
|
+
def post_tests(suite)
|
13
|
+
@feedbacks.each { |feedback| feedback.post_tests(suite) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def processor_result(processor)
|
17
|
+
@feedbacks.each { |feedback| feedback.processor_result(processor) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module CIAT
|
2
|
+
module Feedback
|
3
|
+
# This feedback class sends some simple messages to the screen about the
|
4
|
+
# progress of a CIAT::Suite run.
|
5
|
+
class FeedbackCounter
|
6
|
+
def initialize
|
7
|
+
@error_count = 0
|
8
|
+
@failure_count = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def error_count
|
12
|
+
@error_count
|
13
|
+
end
|
14
|
+
|
15
|
+
def failure_count
|
16
|
+
@failure_count
|
17
|
+
end
|
18
|
+
|
19
|
+
def increment_error_count
|
20
|
+
@error_count += 1
|
21
|
+
end
|
22
|
+
|
23
|
+
def increment_failure_count
|
24
|
+
@failure_count += 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def pre_tests(suite)
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def post_tests(suite)
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def processor_result(processor)
|
36
|
+
case processor.light.setting
|
37
|
+
when :red
|
38
|
+
increment_failure_count
|
39
|
+
when :yellow
|
40
|
+
increment_error_count
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'ciat/erb_helpers'
|
2
|
+
|
3
|
+
module CIAT::Feedback
|
4
|
+
class HtmlFeedback
|
5
|
+
include CIAT::ERBHelpers
|
6
|
+
|
7
|
+
def initialize(counter)
|
8
|
+
@counter = counter
|
9
|
+
end
|
10
|
+
|
11
|
+
def pre_tests(suite)
|
12
|
+
suite.cargo.copy_suite_data
|
13
|
+
end
|
14
|
+
|
15
|
+
def processor_result(processor)
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def post_tests(suite)
|
20
|
+
suite.cargo.write_file(
|
21
|
+
suite.cargo.report_filename,
|
22
|
+
generate_html(suite))
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_html(suite) #:nodoc:
|
26
|
+
processors = suite.processors
|
27
|
+
results = suite.results
|
28
|
+
report_title = suite.report_title
|
29
|
+
size = suite.size
|
30
|
+
counter = @counter
|
31
|
+
ERB.new(template).result(binding)
|
32
|
+
end
|
33
|
+
|
34
|
+
def template #:nodoc:
|
35
|
+
File.read(File.join(
|
36
|
+
File.dirname(__FILE__), "..", "..", "templates", "report.html.erb"
|
37
|
+
))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# A feedback mechanism for failing a task
|
2
|
+
module CIAT::Feedback
|
3
|
+
class ReturnStatus
|
4
|
+
def pre_tests(suite)
|
5
|
+
@failure = false
|
6
|
+
end
|
7
|
+
|
8
|
+
def post_tests(suite)
|
9
|
+
if failure?
|
10
|
+
fail "CIAT tests unsuccessful"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def processor_result(processor)
|
15
|
+
@failure ||= processor.light.yellow? || processor.light.red?
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def failure?
|
20
|
+
@failure
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module CIAT
|
2
|
+
module Feedback
|
3
|
+
# This feedback class sends some simple messages to the screen about the
|
4
|
+
# progress of a CIAT::Suite run.
|
5
|
+
class StandardOutput
|
6
|
+
LIGHT_OUTPUTS = { :green => ".", :red => "F", :yellow => "E", :unset => "-" }
|
7
|
+
|
8
|
+
def initialize(counter)
|
9
|
+
@counter = counter
|
10
|
+
end
|
11
|
+
|
12
|
+
def pre_tests(suite)
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def post_tests(suite)
|
17
|
+
print "\n"
|
18
|
+
print "#{suite.size} tests executed"
|
19
|
+
print ", #{@counter.failure_count} failures" if @counter.failure_count > 0
|
20
|
+
print ", #{@counter.error_count} errors" if @counter.error_count > 0
|
21
|
+
print ".\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
def processor_result(processor)
|
25
|
+
putc LIGHT_OUTPUTS[processor.light.setting]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module CIAT::Processors
|
2
|
+
module BasicProcessing
|
3
|
+
# Produces a clone for an individual test.
|
4
|
+
def for_test
|
5
|
+
copy = clone
|
6
|
+
copy.light = light.clone
|
7
|
+
copy
|
8
|
+
end
|
9
|
+
|
10
|
+
# Executes the program, and diffs the output.
|
11
|
+
def process(test)
|
12
|
+
# TODO: verify required elements
|
13
|
+
# TODO: handle optional element
|
14
|
+
if execute(test)
|
15
|
+
if diff(test)
|
16
|
+
light.green!
|
17
|
+
else
|
18
|
+
light.red!
|
19
|
+
end
|
20
|
+
else
|
21
|
+
light.yellow!
|
22
|
+
end
|
23
|
+
test
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute(test)
|
27
|
+
system "#{executable} '#{input_file(test)}' #{command_line_args(test)} > '#{output_file(test)}' 2> '#{error_file(test)}'"
|
28
|
+
end
|
29
|
+
|
30
|
+
def command_line_args(test) #:nodoc:
|
31
|
+
test.element?(:command_line) ? test.element(:command_line).content.strip : ''
|
32
|
+
end
|
33
|
+
|
34
|
+
# Compares the expected and generated executions.
|
35
|
+
def diff(test)
|
36
|
+
html_diff(
|
37
|
+
test.element(processor_kind.output_name).as_file,
|
38
|
+
test.element(processor_kind.output_name, :generated).as_file,
|
39
|
+
test.element(processor_kind.output_name, :diff).as_file)
|
40
|
+
end
|
41
|
+
|
42
|
+
def relevant_elements(test)
|
43
|
+
relevant_element_names.
|
44
|
+
select { |name| test.element?(name) }.
|
45
|
+
map { |name| test.element(name) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def relevant_element_names
|
49
|
+
processor_kind.element_name_hash[light.setting]
|
50
|
+
end
|
51
|
+
|
52
|
+
def input_file(test)
|
53
|
+
test.element(processor_kind.input_name).as_file
|
54
|
+
end
|
55
|
+
|
56
|
+
def output_file(test)
|
57
|
+
test.element(processor_kind.output_name, :generated).as_file
|
58
|
+
end
|
59
|
+
|
60
|
+
def error_file(test)
|
61
|
+
test.element(processor_kind.output_name, :error).as_file
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|