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.
Files changed (40) hide show
  1. data/History.txt +96 -0
  2. data/README.rdoc +135 -0
  3. data/Rakefile +40 -0
  4. data/ciat.gemspec +53 -0
  5. data/lib/ciat.rb +22 -0
  6. data/lib/ciat/cargo.rb +55 -0
  7. data/lib/ciat/compilers/java.rb +54 -0
  8. data/lib/ciat/crate.rb +58 -0
  9. data/lib/ciat/differs/html_differ.rb +20 -0
  10. data/lib/ciat/erb_helpers.rb +83 -0
  11. data/lib/ciat/executors/java.rb +36 -0
  12. data/lib/ciat/executors/parrot.rb +51 -0
  13. data/lib/ciat/feedback/composite.rb +20 -0
  14. data/lib/ciat/feedback/feedback_counter.rb +45 -0
  15. data/lib/ciat/feedback/html_feedback.rb +40 -0
  16. data/lib/ciat/feedback/return_status.rb +23 -0
  17. data/lib/ciat/feedback/standard_output.rb +29 -0
  18. data/lib/ciat/processors/basic_processing.rb +64 -0
  19. data/lib/ciat/processors/compilation_interpreter.rb +18 -0
  20. data/lib/ciat/processors/compiler.rb +18 -0
  21. data/lib/ciat/processors/copy.rb +37 -0
  22. data/lib/ciat/processors/interpreter.rb +18 -0
  23. data/lib/ciat/rake_task.rb +56 -0
  24. data/lib/ciat/suite.rb +112 -0
  25. data/lib/ciat/test.rb +41 -0
  26. data/lib/ciat/test_element.rb +44 -0
  27. data/lib/ciat/traffic_light.rb +39 -0
  28. data/lib/ciat/version.rb +7 -0
  29. data/lib/data/ciat.css +40 -0
  30. data/lib/data/elements.yml +30 -0
  31. data/lib/data/prototype.js +4228 -0
  32. data/lib/templates/detail_row.html.erb +9 -0
  33. data/lib/templates/detail_row/elements.html.erb +3 -0
  34. data/lib/templates/elements/diff.html.erb +7 -0
  35. data/lib/templates/elements/plain.html.erb +8 -0
  36. data/lib/templates/group_header.html.erb +7 -0
  37. data/lib/templates/report.html.erb +38 -0
  38. data/lib/templates/summary_row.html.erb +12 -0
  39. data/lib/templates/test_numbers.html.erb +12 -0
  40. 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