Created
September 7, 2008 19:30
-
-
Save rgarver/9300 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Paste me into spec_helper.rb, or save me somewhere else and require me in. | |
class BeValidXhtml | |
# require 'action_controller/test_process' | |
# require 'test/unit' | |
require 'net/http' | |
require 'md5' | |
require 'ftools' | |
def initialize | |
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) | |
return true if validity_checks_disabled? | |
case response | |
when String | |
response = match_string(response) | |
else | |
response = match_action_controller_response(response) | |
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 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["NONET"] == '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) | |
File.makedirs(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 match_string(response) | |
run_validation_on_fragment(response) | |
end | |
def match_action_controller_response(response) | |
fn = response.rendered_file | |
fragment = response.body | |
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 = run_validation_on_fragment | |
File.open(results_filename, 'w+') do |f| Marshal.dump(response, f) end | |
end | |
response | |
end | |
def run_validation_on_fragment(fragment) | |
http.start(MARKUP_VALIDATOR_HOST).post2(MARKUP_VALIDATOR_PATH, "fragment=#{CGI.escape(fragment)}&output=xml") | |
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment