public
Description: A Ruby on Rails blogging app for the fashionable developer - it's better than Mephisto or SimpleLog
Homepage: http://www.enkiblog.com/
Clone URL: git://github.com/xaviershay/enki.git
Click here to lend your support to: enki and make a donation at www.pledgie.com !
xaviershay (author)
Fri Jun 19 23:39:03 -0700 2009
commit  a5c95871ecb2217063ddd2dac86005e367483162
tree    a06b67e7c3e0ec47a029ee2fcbb70e4c53dba05c
parent  672b986e4531a30af4adeab5c9e870b1b8a1f22b
enki / spec / be_valid_xhtml.rb
100644 152 lines (124 sloc) 4.858 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# Paste me into spec_helper.rb, or save me somewhere else and require me in.
 
class BeValidXhtml
  require 'net/http'
  require 'digest/md5'
  
  def initialize(options)
    @fragment = options[:fragment]
  end
  
  # Assert that markup (html/xhtml) is valid according the W3C validator web service.
  # By default, it validates the contents of @response.body, which is set after calling
  # one of the get/post/etc helper methods. You can also pass it a string to be validated.
  # Validation errors, if any, will be included in the output. The input fragment and
  # response from the validator service will be cached in the $RAILS_ROOT/tmp directory to
  # minimize network calls.
  #
  # For example, if you have a FooController with an action Bar, put this in foo_controller_test.rb:
  #
  # def test_bar_valid_markup
  # get :bar
  # assert_valid_markup
  # end
  #
  MARKUP_VALIDATOR_HOST = ENV['MARKUP_VALIDATOR_HOST'] || 'validator.w3.org'
  MARKUP_VALIDATOR_PATH = ENV['MARKUP_VALIDATOR_PATH'] || '/check'
  CSS_VALIDATOR_HOST = ENV['CSS_VALIDATOR_HOST'] || 'jigsaw.w3.org'
  CSS_VALIDATOR_PATH = ENV['CSS_VALIDATOR_PATH'] || '/css-validator/validator'
  
  @@display_invalid_content = false
  cattr_accessor :display_invalid_content
 
  @@auto_validate = false
  cattr_accessor :auto_validate
 
  class_inheritable_accessor :auto_validate_excludes
  class_inheritable_accessor :auto_validate_includes
  
  
  def matches?(response)
    fn = response.rendered.to_s
    fragment = response.body
    fragment = wrap_with_xhtml_header(fragment) if @fragment
    return true if validity_checks_disabled?
    base_filename = cache_resource('markup',fragment,'html',fn)
    
    return false unless base_filename
    results_filename = base_filename + '-results.yml'
 
    begin
      response = File.open(results_filename) do |f| Marshal.load(f) end
    rescue
      response = http.start(MARKUP_VALIDATOR_HOST).post2(MARKUP_VALIDATOR_PATH, "fragment=#{CGI.escape(fragment)}&output=xml")
      File.open(results_filename, 'w+') do |f| Marshal.dump(response, f) end
    end
    markup_is_valid = response['x-w3c-validator-status'] == 'Valid'
    @message = ''
    unless markup_is_valid
      fragment.split($/).each_with_index{|line, index| message << "#{'%04i' % (index+1)} : #{line}#{$/}"} if @@display_invalid_content
      @message << XmlSimple.xml_in(response.body)['messages'][0]['msg'].collect{ |m| "Invalid markup: line #{m['line']}: #{CGI.unescapeHTML(m['content'])}" }.join("\n")
    end
    if markup_is_valid
      return true
    else
      return false
    end
  end
 
  def wrap_with_xhtml_header(fragment)
    ret = <<-EOS
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
"http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg-flat.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test</title>
</head>
<body>
#{fragment}
</body>
</html>
EOS
  end
  
  def description
    "be valid xhtml"
  end
  
  def failure_message
   " expected xhtml to be valid, but validation produced these errors:\n #{@message}"
  end
  
  def negative_failure_message
    " expected to not be valid, but was (missing validation?)"
  end
  
  private
    def validity_checks_disabled?
      ENV["NET"] != 'true'
    end
 
    def text_to_multipart(key,value)
      return "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"\r\n\r\n#{value}\r\n"
    end
 
    def file_to_multipart(key,filename,mime_type,content)
      return "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"; filename=\"#{filename}\"\r\n" +
                "Content-Transfer-Encoding: binary\r\nContent-Type: #{mime_type}\r\n\r\n#{content}\r\n"
    end
 
    def cache_resource(base,resource,extension,fn)
      resource_md5 = MD5.md5(resource).to_s
      file_md5 = nil
 
      output_dir = "#{RAILS_ROOT}/tmp/#{base}"
      base_filename = File.join(output_dir, fn)
      filename = base_filename + extension
 
      parent_dir = File.dirname(filename)
      FileUtils.mkdir_p(parent_dir) unless File.exists?(parent_dir)
 
      File.open(filename, 'r') do |f|
        file_md5 = MD5.md5(f.read(f.stat.size)).to_s
      end if File.exists?(filename)
 
      if file_md5 != resource_md5
        Dir["#{base_filename}[^.]*"] .each {|f| File.delete(f)}
        File.open(filename, 'w+') do |f| f.write(resource); end
      end
      base_filename
    end
 
    def http
      if Module.constants.include?("ApplicationConfig") && ApplicationConfig.respond_to?(:proxy_config)
        Net::HTTP::Proxy(ApplicationConfig.proxy_config['host'], ApplicationConfig.proxy_config['port'])
      else
        Net::HTTP
      end
    end
  
end
 
def be_valid_xhtml
  BeValidXhtml.new
end
 
def be_valid_xhtml_fragment
  BeValidXhtml.new(:fragment => true)
end