rspec 0.5.12 → 0.5.13

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 (54) hide show
  1. data/CHANGES +9 -1
  2. data/README +2 -2
  3. data/Rakefile +13 -5
  4. data/examples/custom_formatter.rb +2 -2
  5. data/examples/file_accessor.rb +18 -0
  6. data/examples/file_accessor_spec.rb +38 -0
  7. data/examples/io_processor.rb +8 -0
  8. data/examples/io_processor_spec.rb +21 -0
  9. data/lib/spec/api/exceptions.rb +3 -0
  10. data/lib/spec/api/mocks/message_expectation.rb +45 -29
  11. data/lib/spec/api/mocks/mock.rb +1 -1
  12. data/lib/spec/api/mocks/order_group.rb +1 -1
  13. data/lib/spec/runner.rb +1 -5
  14. data/lib/spec/runner/formatter.rb +5 -0
  15. data/lib/spec/runner/formatter/base_text_formatter.rb +79 -0
  16. data/lib/spec/runner/formatter/html_formatter.rb +156 -0
  17. data/lib/spec/runner/formatter/progress_bar_formatter.rb +27 -0
  18. data/lib/spec/runner/formatter/rdoc_formatter.rb +22 -0
  19. data/lib/spec/runner/formatter/specdoc_formatter.rb +22 -0
  20. data/lib/spec/runner/option_parser.rb +17 -17
  21. data/lib/spec/runner/reporter.rb +1 -1
  22. data/lib/spec/version.rb +1 -1
  23. data/test/spec/api/helper/arbitrary_predicate_test.rb +38 -38
  24. data/test/spec/api/helper/diff_test.rb +1 -1
  25. data/test/spec/api/helper/identity_test.rb +17 -10
  26. data/test/spec/api/helper/{equality_test.rb → object_equality_test.rb} +15 -29
  27. data/test/spec/api/helper/regex_matching_test.rb +7 -9
  28. data/test/spec/api/helper/throwing_test.rb +11 -12
  29. data/test/spec/api/helper/true_false_special_case_test.rb +15 -17
  30. data/test/spec/api/helper/typing_test.rb +27 -26
  31. data/test/spec/api/mocks/mock_arg_constraints_test.rb +1 -1
  32. data/test/spec/api/mocks/mock_test.rb +45 -11
  33. data/test/spec/api/mocks/null_object_test.rb +3 -3
  34. data/test/spec/runner/context_matching_test.rb +2 -2
  35. data/test/spec/runner/formatter/failure_dump_test.rb +94 -0
  36. data/test/spec/runner/formatter/html_formatter_test.rb +48 -0
  37. data/test/spec/runner/formatter/progress_bar_formatter_test.rb +56 -0
  38. data/test/spec/runner/formatter/rdoc_formatter_test.rb +51 -0
  39. data/test/spec/runner/formatter/specdoc_formatter_test.rb +57 -0
  40. data/test/spec/runner/kernel_ext_test.rb +1 -1
  41. data/test/spec/runner/option_parser_test.rb +22 -12
  42. data/test/spec/runner/reporter_test.rb +1 -1
  43. data/test/test_classes.rb +7 -7
  44. metadata +19 -14
  45. data/lib/spec/runner/base_text_formatter.rb +0 -77
  46. data/lib/spec/runner/html_formatter.rb +0 -153
  47. data/lib/spec/runner/progress_bar_formatter.rb +0 -25
  48. data/lib/spec/runner/rdoc_formatter.rb +0 -20
  49. data/lib/spec/runner/specdoc_formatter.rb +0 -20
  50. data/test/spec/runner/failure_dump_test.rb +0 -92
  51. data/test/spec/runner/html_formatter_test.rb +0 -47
  52. data/test/spec/runner/progress_bar_formatter_test.rb +0 -54
  53. data/test/spec/runner/rdoc_formatter_test.rb +0 -50
  54. data/test/spec/runner/specdoc_formatter_test.rb +0 -55
data/CHANGES CHANGED
@@ -1,12 +1,20 @@
1
1
  = RSpec Changelog
2
2
 
3
+ == Version 0.5.13
4
+ This release fixes some subtle bugs in the mock API.
5
+
6
+ * Use fully-qualified class name of Exceptions in failure message. Easier to debug that way.
7
+ * Fixed a bug that caused mocks to yield a one-element array (rather than the element) when one yield arg specified.
8
+ * Mocks not raise AmbiguousReturnError if an explicit return is used at the same time as an expectation block.
9
+ * Blocks passed to yielding mocks can now raise without causing mock verification to fail.
10
+
3
11
  == Version 0.5.12
4
12
  This release adds diff support for failure messages, a HTML formatter plus some other
5
13
  minor enhancements.
6
14
 
7
15
  * Added HTML formatter.
8
16
  * Added fail_on_error option to spectask.
9
- * Added support for diffing, using the lcs-diff Rubygem (#2648).
17
+ * Added support for diffing, using the diff-lcs Rubygem (#2648).
10
18
  * Remove RSpec on Rails files from backtrace (#4694).
11
19
  * All of RSpec's own tests run successfully after translation with test2spec.
12
20
  * Added --verbose mode for test2spec - useful for debugging when classes fail to translate.
data/README CHANGED
@@ -8,12 +8,12 @@ Then you must install the following gems:
8
8
  * webgen
9
9
  * RedCloth
10
10
  * syntax
11
- * lcs-diff
11
+ * diff-lcs
12
12
 
13
13
  Note that RSpec itself - once built - doesn't have any dependencies outside the Ruby core
14
14
  and stdlib - with a few exceptions:
15
15
 
16
- * The spec command line uses lcs-diff when --diff is specified.
16
+ * The spec command line uses diff-lcs when --diff is specified.
17
17
  * The test2spec command line uses ParseTree and RubyInline.
18
18
  * The Spec::Rake::SpecTask needs RCov if RCov is enabled in the task.
19
19
 
data/Rakefile CHANGED
@@ -32,8 +32,12 @@ Spec::Rake::SpecTask.new('failing_examples') do |t|
32
32
  t.spec_files = FileList['failing_examples/**/*_spec.rb']
33
33
  end
34
34
 
35
+ require 'rbconfig'
36
+ windows = Config::CONFIG['target_os'] == 'mswin32'
35
37
  Rake::TestTask.new do |t|
36
- t.test_files = FileList['test/**/*_test.rb']
38
+ tests = FileList['test/**/*_test.rb']
39
+ tests.exclude 'test/spec/test_to_spec/*.rb' if windows
40
+ t.test_files = tests
37
41
  t.verbose = true
38
42
  end
39
43
 
@@ -44,21 +48,25 @@ Rcov::RcovTask.new do |t|
44
48
  end
45
49
 
46
50
  desc 'Translate our own tests to specs'
47
- task :test2spec do
51
+ task :test2spec => :create_test2spec_dir do
48
52
  rm_rf 'spec/translated'
49
53
  `bin/test2spec --force --template spec/test2spec.erb --specdir spec/translated test`
50
54
  # Remove the spec translations that we don't care about.
51
55
  rm 'spec/translated/spec/test_to_spec/sexp_transformer_assertion_spec.rb'
52
56
  rm 'spec/translated/spec/test_to_spec/sexp_transformer_spec.rb'
53
57
  end
58
+ task :create_test2spec_dir do
59
+ mkdir_p 'doc/output/tools' unless File.exist? 'doc/output/tools'
60
+ end
54
61
 
55
62
  desc 'Runs all RSpec specs - translated with test2spec from our own tests'
56
63
  Spec::Rake::SpecTask.new('test2spec_test' => :test2spec) do |t|
57
64
  t.spec_files = FileList['spec/**/*_spec.rb']
58
- t.options = ['--diff']
65
+ t.spec_opts = ["--format", "html", "--diff"]
66
+ t.out = 'doc/output/tools/rspec_specs.html'
59
67
  end
60
68
 
61
- desc 'Generate HTML documentation'
69
+ desc 'Generate HTML documentation for website'
62
70
  task :webgen => :test2spec do
63
71
  Dir.chdir 'doc' do
64
72
  output = nil
@@ -155,7 +163,7 @@ task :tag do
155
163
  end
156
164
 
157
165
  desc "Build the website with rdoc and rcov, but do not publish it"
158
- task :website => [:clobber, :rcov_verify, :webgen, :failing_examples_with_html, :examples_specdoc, :rdoc]
166
+ task :website => [:clobber, :rcov_verify, :webgen, :failing_examples_with_html, :test2spec_test, :examples_specdoc, :rdoc]
159
167
 
160
168
  task :verify_user do
161
169
  raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
@@ -1,8 +1,8 @@
1
- require 'spec/runner/base_text_formatter'
1
+ require 'spec/runner/formatter/base_text_formatter'
2
2
 
3
3
  # Example of a custom formatter. Run me with:
4
4
  # bin/spec examples -r examples/custom_formatter.rb -f CustomFormatter
5
- class CustomFormatter < Spec::Runner::BaseTextFormatter
5
+ class CustomFormatter < Spec::Runner::Formatter::BaseTextFormatter
6
6
  def add_context(name, first)
7
7
  @output << "\n" if first
8
8
  end
@@ -0,0 +1,18 @@
1
+ class FileAccessor
2
+ def open_and_handle_with(pathname, processor)
3
+ pathname.open do |io|
4
+ processor.process(io)
5
+ end
6
+ end
7
+ end
8
+
9
+ if __FILE__ == $0
10
+ require File.dirname(__FILE__) + '/io_processor'
11
+ require 'pathname'
12
+
13
+ accessor = FileAccessor.new
14
+ io_processor = IoProcessor.new
15
+ file = Pathname.new ARGV[0]
16
+
17
+ accessor.open_and_handle_with(file, io_processor)
18
+ end
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + '/../lib/spec'
2
+ require File.dirname(__FILE__) + '/file_accessor'
3
+ require 'stringio'
4
+
5
+ context "A FileAccessor" do
6
+ # This sequence diagram illustrates what this spec specifies.
7
+ #
8
+ # +--------------+ +----------+ +-------------+
9
+ # | FileAccessor | | Pathname | | IoProcessor |
10
+ # +--------------+ +----------+ +-------------+
11
+ # | | |
12
+ # open_and_handle_with | | |
13
+ # -------------------->| | open | |
14
+ # | |--------------->| | |
15
+ # | | io | | |
16
+ # | |<...............| | |
17
+ # | | | process(io) |
18
+ # | |---------------------------------->| |
19
+ # | | | | |
20
+ # | |<..................................| |
21
+ # | | |
22
+ #
23
+ specify "should open a file and pass it to the processor's process method" do
24
+ # This is the primary actor
25
+ accessor = FileAccessor.new
26
+
27
+ # These are the primary actor's neighbours, which we mock.
28
+ file = mock "Pathname"
29
+ io_processor = mock "IoProcessor"
30
+
31
+ io = StringIO.new "whatever"
32
+ file.should_receive(:open).and_yield io
33
+ io_processor.should_receive(:process).with(io)
34
+
35
+ accessor.open_and_handle_with(file, io_processor)
36
+ end
37
+
38
+ end
@@ -0,0 +1,8 @@
1
+ class DataTooShort < StandardError; end
2
+
3
+ class IoProcessor
4
+ # Does some fancy stuff unless the length of +io+ is shorter than 32
5
+ def process(io)
6
+ raise DataTooShort if io.read.length < 32
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/../lib/spec'
2
+ require File.dirname(__FILE__) + '/io_processor'
3
+ require 'stringio'
4
+
5
+ context "An IoProcessor" do
6
+ setup do
7
+ @processor = IoProcessor.new
8
+ end
9
+
10
+ specify "should raise nothing when the file is exactly 32 bytes" do
11
+ lambda {
12
+ @processor.process(StringIO.new("z"*32))
13
+ }.should_not_raise
14
+ end
15
+
16
+ specify "should raise an exception when the file length is less than 32 bytes" do
17
+ lambda {
18
+ @processor.process(StringIO.new("z"*31))
19
+ }.should_raise(DataTooShort)
20
+ end
21
+ end
@@ -5,5 +5,8 @@ module Spec
5
5
 
6
6
  class MockExpectationError < StandardError
7
7
  end
8
+
9
+ class AmbiguousReturnError < StandardError
10
+ end
8
11
  end
9
12
  end
@@ -4,12 +4,12 @@ module Spec
4
4
  # Represents the expection of the reception of a message
5
5
  class MessageExpectation
6
6
 
7
- def initialize(mock_name, expectation_ordering, expected_from, sym, block)
7
+ def initialize(mock_name, expectation_ordering, expected_from, sym, method_block)
8
8
  @mock_name = mock_name
9
9
  @expected_from = expected_from
10
10
  @sym = sym
11
- @method_block = block
12
- @block = proc {}
11
+ @method_block = method_block
12
+ @return_block = lambda {}
13
13
  @received_count = 0
14
14
  @expected_received_count = 1
15
15
  @args_expectation = ArgumentExpectation.new([:any_args])
@@ -67,39 +67,54 @@ module Spec
67
67
  end
68
68
 
69
69
  # This method is called when a method is invoked on a mock
70
- def verify_message(args, block)
70
+ def invoke(args, block)
71
71
 
72
72
  handle_order_constraint
73
-
74
- unless @method_block.nil?
75
- begin
76
- result = @method_block.call(*args)
77
- rescue Spec::Api::ExpectationNotMetError => detail
78
- Kernel::raise Spec::Api::MockExpectationError, "Call expectation violated with: " + detail
73
+
74
+ begin
75
+ Kernel::raise @exception_to_raise.new unless @exception_to_raise.nil?
76
+ Kernel::throw @symbol_to_throw unless @symbol_to_throw.nil?
77
+
78
+ if !@method_block.nil?
79
+ return invoke_method_block(args)
80
+ elsif !@args_to_yield.nil?
81
+ return invoke_with_yield(block)
82
+ else
83
+ return invoke_return_block(args, block)
79
84
  end
85
+ ensure
80
86
  @received_count += 1
81
- return result
82
87
  end
83
-
84
- Kernel::raise @exception_to_raise.new unless @exception_to_raise.nil?
85
- Kernel::throw @symbol_to_throw unless @symbol_to_throw.nil?
86
- unless @args_to_yield.nil?
87
- if block.nil?
88
- Kernel::raise Spec::Api::MockExpectationError, "Expected block to be passed"
89
- end
90
- if @args_to_yield.length != block.arity
91
- Kernel::raise Spec::Api::MockExpectationError, "Wrong arity of passed block. Expected #{@args_to_yield.size}"
92
- end
93
- block.call @args_to_yield
88
+ end
89
+
90
+ def invoke_method_block(args)
91
+ begin
92
+ @method_block.call(*args)
93
+ rescue Spec::Api::ExpectationNotMetError => detail
94
+ Kernel::raise Spec::Api::MockExpectationError, "Call expectation violated with: " + detail
95
+ end
96
+ end
97
+
98
+ def invoke_with_yield(block)
99
+ if block.nil?
100
+ Kernel::raise Spec::Api::MockExpectationError, "Expected block to be passed"
94
101
  end
102
+ if @args_to_yield.length != block.arity
103
+ Kernel::raise Spec::Api::MockExpectationError, "Wrong arity of passed block. Expected #{@args_to_yield.size}"
104
+ end
105
+ block.call *@args_to_yield
106
+ end
95
107
 
108
+ def invoke_return_block(args, block)
96
109
  args << block unless block.nil?
97
- @received_count += 1
98
- value = @block.call(*args)
110
+ value = @return_block.call(*args)
99
111
 
100
- return value unless @consecutive
101
-
102
- value[[@received_count, value.size].min - 1]
112
+ if @consecutive
113
+ index = [@received_count, value.size-1].min
114
+ value[index]
115
+ else
116
+ value
117
+ end
103
118
  end
104
119
 
105
120
  def with(*args)
@@ -170,11 +185,12 @@ module Spec
170
185
  self
171
186
  end
172
187
 
173
- def return(value=nil,&block)
188
+ def return(value=nil, &return_block)
189
+ Kernel::raise AmbiguousReturnError unless @method_block.nil?
174
190
  return self unless @and_seen
175
191
  @and_seen = false
176
192
  @consecutive = value.instance_of? Array
177
- @block = block_given? ? block : proc { value }
193
+ @return_block = block_given? ? return_block : lambda { value }
178
194
  end
179
195
 
180
196
  def raise(exception=Exception)
@@ -35,7 +35,7 @@ module Spec
35
35
 
36
36
  def method_missing(sym, *args, &block)
37
37
  if expectation = find_matching_expectation(sym, *args)
38
- expectation.verify_message(args, block)
38
+ expectation.invoke(args, block)
39
39
  else
40
40
  begin
41
41
  # act as null object if method is missing and we ignore them. return value too!
@@ -6,7 +6,7 @@ module Spec
6
6
  end
7
7
 
8
8
  def register(expectation)
9
- @ordering << expectation
9
+ @ordering << expectation
10
10
  end
11
11
 
12
12
  def ready_for?(expectation)
@@ -1,3 +1,4 @@
1
+ require 'spec/runner/formatter'
1
2
  require 'spec/runner/instance_exec'
2
3
  require 'spec/runner/context'
3
4
  require 'spec/runner/specification'
@@ -6,9 +7,4 @@ require 'spec/runner/context_runner'
6
7
  require 'spec/runner/option_parser'
7
8
  require 'spec/runner/backtrace_tweaker'
8
9
  require 'spec/runner/reporter'
9
- require 'spec/runner/base_text_formatter'
10
- require 'spec/runner/progress_bar_formatter'
11
- require 'spec/runner/rdoc_formatter'
12
- require 'spec/runner/specdoc_formatter'
13
- require 'spec/runner/html_formatter'
14
10
  require 'spec/runner/spec_matcher'
@@ -0,0 +1,5 @@
1
+ require 'spec/runner/formatter/base_text_formatter'
2
+ require 'spec/runner/formatter/progress_bar_formatter'
3
+ require 'spec/runner/formatter/rdoc_formatter'
4
+ require 'spec/runner/formatter/specdoc_formatter'
5
+ require 'spec/runner/formatter/html_formatter'
@@ -0,0 +1,79 @@
1
+ module Spec
2
+ module Runner
3
+ module Formatter
4
+ # Baseclass for text-based formatters. Can in fact be used for
5
+ # non-text based ones too - just ignore the +output+ constructor
6
+ # argument.
7
+ class BaseTextFormatter
8
+ def initialize(output, dry_run=false)
9
+ @dry_run = dry_run
10
+ @output = output
11
+ end
12
+
13
+ # This method is invoked before any specs are run, right after
14
+ # they have all been collected. This can be useful for special
15
+ # formatters that need to provide progress on feedback (graphical ones)
16
+ #
17
+ # This method will only be invoked once, and the next one to be invoked
18
+ # is #add_context
19
+ def start(spec_count)
20
+ end
21
+
22
+ # This method is invoked at the beginning of the execution of each context.
23
+ # +name+ is the name of the context and +first+ is true if it is the
24
+ # first context - otherwise it's false.
25
+ #
26
+ # The next method to be invoked after this is #spec_started
27
+ def add_context(name, first)
28
+ end
29
+
30
+ # This method is invoked right before a spec is executed.
31
+ # The next method to be invoked after this one is one of #spec_failed
32
+ # or #spec_passed.
33
+ def spec_started(name)
34
+ end
35
+
36
+ # This method is invoked when a spec fails, i.e. an exception occurred
37
+ # inside it (such as a failed should or other exception). +name+ is the name
38
+ # of the specification. +counter+ is the sequence number of the failure
39
+ # (starting at 1) and +failure+ is the associated Failure object.
40
+ def spec_failed(name, counter, failure)
41
+ end
42
+
43
+ # This method is invoked when a spec passes. +name+ is the name of the
44
+ # specification.
45
+ def spec_passed(name)
46
+ end
47
+
48
+ # This method is invoked after all of the specs have executed. The next method
49
+ # to be invoked after this one is #dump_failure (once for each failed spec),
50
+ def start_dump
51
+ end
52
+
53
+ # Dumps detailed information about a spec failure.
54
+ # This method is invoked for each failed spec after all specs have run. +counter+ is the sequence number
55
+ # of the associated spec. +failure+ is a Failure object, which contains detailed
56
+ # information about the failure.
57
+ def dump_failure(counter, failure)
58
+ @output << "\n"
59
+ @output << counter.to_s << ")\n"
60
+ @output << "#{failure.header}\n"
61
+ @output << "#{failure.message}\n"
62
+ @output << "#{failure.backtrace}\n"
63
+ @output.flush
64
+ end
65
+
66
+ # This method is invoked at the very end.
67
+ def dump_summary(duration, spec_count, failure_count)
68
+ return if @dry_run
69
+ @output << "\n"
70
+ @output << "Finished in " << (duration).to_s << " seconds\n\n"
71
+ @output << "#{spec_count} specification#{'s' unless spec_count == 1}, "
72
+ @output << "#{failure_count} failure#{'s' unless failure_count == 1}"
73
+ @output << "\n"
74
+ @output.flush
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,156 @@
1
+ module Spec
2
+ module Runner
3
+ module Formatter
4
+ class HtmlFormatter < BaseTextFormatter
5
+ def initialize(output, dry_run=false)
6
+ super
7
+ @current_count = 0
8
+ end
9
+
10
+ def start(spec_count)
11
+ @spec_count = spec_count
12
+
13
+ @output.puts HEADER
14
+ @output.flush
15
+ end
16
+
17
+ def add_context(name, first)
18
+ unless first
19
+ @output.puts " </ul>"
20
+ @output.puts "</div>"
21
+ end
22
+ @output.puts "<div class=\"context\">"
23
+ @output.puts " <div>#{name}</div>"
24
+ @output.puts " <ul>"
25
+ end
26
+
27
+ def start_dump
28
+ @output.puts " </ul>"
29
+ @output.puts "</div>"
30
+ @output.flush
31
+ end
32
+
33
+ def spec_started(name)
34
+ @current_spec = name
35
+ @current_count += 1
36
+ end
37
+
38
+ def spec_passed(name)
39
+ @output.puts "<li class=\"spec passed\">#{escape(@current_spec)}</li>"
40
+ end
41
+
42
+ def spec_failed(name, counter, failure)
43
+ @output.puts "<li class=\"spec failed\" onclick=\"toggle('failure_#{counter}');return false;\">"
44
+ @output.puts " <div>#{escape(@current_spec)}</div>"
45
+ @output.puts " <div class=\"failure\" id=\"failure_#{counter}\" style=\"display:none\">"
46
+ @output.puts " <div><pre>#{escape(failure.header)}</pre></div>" unless failure.header == ""
47
+ @output.puts " <div><pre>#{escape(failure.message)}</pre></div>" unless failure.message == ""
48
+ @output.puts " <div><pre>#{escape(failure.backtrace)}</pre></div>" unless failure.backtrace == ""
49
+ @output.puts " </div>"
50
+ @output.puts "</li>"
51
+ @output.flush
52
+ end
53
+
54
+ def escape(string)
55
+ string.gsub(/&/n, '&amp;').gsub(/\"/n, '&quot;').gsub(/>/n, '&gt;').gsub(/</n, '&lt;')
56
+ end
57
+
58
+ def dump_failure(counter, failure)
59
+ # @output << "\n"
60
+ # @output << counter.to_s << ")\n"
61
+ # @output << "#{failure.header}\n"
62
+ # @output << "#{failure.message}\n"
63
+ # @output << "#{failure.backtrace}\n"
64
+ # @output.flush
65
+ end
66
+
67
+ def dump_summary(duration, spec_count, failure_count)
68
+ @output << "</body>"
69
+ @output << "</html>"
70
+ @output.flush
71
+ end
72
+
73
+ HEADER = <<-HEADER
74
+ <?xml version="1.0" encoding="iso-8859-1"?>
75
+ <!DOCTYPE html
76
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
77
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
78
+
79
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
80
+ <head>
81
+ <title>RSpec results</title>
82
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
83
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
84
+ <style type="text/css">
85
+ body {
86
+ font-size: 10pt;
87
+ font: "lucida grande";
88
+ width: 85%;
89
+ }
90
+
91
+ ul {
92
+ padding-left: 8px;
93
+ }
94
+
95
+ li.passed {
96
+ background-color: #DDFFDD;
97
+ }
98
+
99
+ li {
100
+ list-style-type: none;
101
+ margin: 0;
102
+ }
103
+
104
+ li.failed {
105
+ background-color: #FFBBBB;
106
+ font-weight: bold;
107
+ }
108
+
109
+ li.failed:hover {
110
+ color: #FFFFFF;
111
+ background-color: #FF0000;
112
+ }
113
+
114
+ li.failed .failure {
115
+ font-weight: normal;
116
+ font-size: 9pt;
117
+ }
118
+
119
+ div.context {
120
+ padding:4px;
121
+ border:1px solid #000000;
122
+ margin-top:4px;
123
+ }
124
+
125
+ </style>
126
+ <script type="text/javascript">
127
+ // <![CDATA[
128
+
129
+ function toggle( id ) {
130
+ if ( document.getElementById )
131
+ elem = document.getElementById( id );
132
+ else if ( document.all )
133
+ elem = eval( "document.all." + id );
134
+ else
135
+ return false;
136
+
137
+ elemStyle = elem.style;
138
+
139
+ if ( elemStyle.display != "block" ) {
140
+ elemStyle.display = "block"
141
+ } else {
142
+ elemStyle.display = "none"
143
+ }
144
+
145
+ return true;
146
+ }
147
+ // ]]>
148
+ </script>
149
+
150
+ </head>
151
+ <body>
152
+ HEADER
153
+ end
154
+ end
155
+ end
156
+ end