Skip to content

Instantly share code, notes, and snippets.

@rgarver
Created September 7, 2008 19:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rgarver/9300 to your computer and use it in GitHub Desktop.
Save rgarver/9300 to your computer and use it in GitHub Desktop.
# 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