assert_valid_markup 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Matt Conway
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,71 @@
1
+ = assert_valid_markup plugin for Rails
2
+
3
+
4
+ Validate your (X)HTML from within your functional tests. If anything changes to invalidate
5
+ your markup, you'll know pronto.
6
+
7
+ If xmllint/xmlcatalog are available in your PATH, this plugin will use them to validate your xml.
8
+ When doing so, it will automatically fetch and cache all DTDs locally so that you don't incur a
9
+ network hit on future runs.
10
+
11
+ Otherwise, validations will be done using the W3C Validator web service (http://validator.w3.org/).
12
+ Responses from the web service are cached, so your tests aren't slowed down unless something has changed.
13
+
14
+ == Installation
15
+
16
+ Install as a gem:
17
+
18
+ gem install assert_valid_markup
19
+
20
+ and edit config/environments/test.rb:
21
+
22
+ config.gem 'assert_valid_markup'
23
+
24
+ or install as a plugin:
25
+
26
+ ./script/plugin install http://github.com/wr0ngway/assert_valid_markup
27
+
28
+
29
+ == Usage
30
+
31
+ Calling the assertion with no parameters validates whatever is in @request.body,
32
+ which is automatically set by the existing get/post/etc helpers. For example:
33
+
34
+ class FooControllerTest < Test::Unit::TestCase
35
+ def test_bar_markup
36
+ get :bar
37
+ assert_valid_markup
38
+ end
39
+ end
40
+
41
+ Add a string parameter to the assertion to validate any random fragment. Por ejemplo:
42
+
43
+ class FooControllerTest < Test::Unit::TestCase
44
+ def test_bar_markup
45
+ assert_valid_markup "<div>Hello, world.</div>"
46
+ end
47
+ end
48
+
49
+ For the ultimate in convenience, use the class-level methods to validate a slew of
50
+ actions in one line. Par exemple:
51
+
52
+ class FooControllerTest < Test::Unit::TestCase
53
+ assert_valid_markup :bar, :baz, :qux
54
+ end
55
+
56
+ # automatically validate all GETs in BarControllerTest
57
+ class BarControllerTest < Test::Unit::TestCase
58
+ assert_all_valid_markup
59
+ end
60
+
61
+ # Add this to test_helper to automatically validate the responses for ALL GETs in ALL controllers
62
+ class ActionController::TestCase < ActiveSupport::TestCase
63
+ assert_all_valid_markup
64
+ end
65
+
66
+
67
+ == Credits
68
+
69
+ Scott Raymond <sco@scottraymond.net>. Released under the MIT license.
70
+ Matt Conway <matt@conwaysplace.com> (xmllint additions)
71
+ Latest version: http://github.com/wr0ngway/assert_valid_markup
data/VERSION ADDED
@@ -0,0 +1,2 @@
1
+ 0.5.0
2
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init"
@@ -0,0 +1,149 @@
1
+ require 'test/unit'
2
+ require 'net/http'
3
+ require 'digest/md5'
4
+ require 'open-uri'
5
+ require 'fileutils'
6
+ require 'tempfile'
7
+ require 'xmlsimple'
8
+ require 'cgi'
9
+
10
+ class Test::Unit::TestCase
11
+
12
+ @@default_avm_options = {
13
+ :catalog_path => File.expand_path("~/.xml-catalogs"),
14
+ :validation_service => system("xmllint --version > /dev/null 2>&1") ? :local : :w3c,
15
+ :dtd_validate => true
16
+ }
17
+
18
+ # Assert that markup (html/xhtml) is valid according the W3C validator web service.
19
+ # By default, it validates the contents of @response.body, which is set after calling
20
+ # one of the get/post/etc helper methods. You can also pass it a string to be validated.
21
+ # Validation errors, if any, will be included in the output. The response from the validator
22
+ # service will be cached in the system temp directory to minimize duplicate calls.
23
+ #
24
+ # For example, if you have a FooController with an action Bar, put this in foo_controller_test.rb:
25
+ #
26
+ # def test_bar_valid_markup
27
+ # get :bar
28
+ # assert_valid_markup
29
+ # end
30
+ #
31
+ def assert_valid_markup(fragment=@response.body, options={})
32
+ opts = @@default_avm_options.merge(options)
33
+ result = ''
34
+ if opts[:validation_service] == :local
35
+ result = local_validate(fragment, opts[:dtd_validate], opts[:catalog_path])
36
+ else
37
+ result = w3c_validate(fragment, opts[:dtd_validate])
38
+ end
39
+ assert result.empty?, result
40
+ end
41
+
42
+ # Class-level method to quickly create validation tests for a bunch of actions at once.
43
+ # For example, if you have a FooController with three actions, just add one line to foo_controller_test.rb:
44
+ #
45
+ # assert_valid_markup :bar, :baz, :qux
46
+ #
47
+ # If you pass :but_first => :something, #something will be called at the beginning of each test case
48
+ def self.assert_valid_markup(*actions)
49
+ options = actions.find { |i| i.kind_of? Hash }
50
+ actions.delete_if { |i| i.kind_of? Hash }
51
+ actions.each do |action|
52
+ toeval = "def test_#{action}_valid_markup\n"
53
+ toeval << "#{options[:but_first].id2name}\n" if options and options[:but_first]
54
+ toeval << "get :#{action}\n"
55
+ toeval << "assert_valid_markup\n"
56
+ toeval << "end\n"
57
+ class_eval toeval
58
+ end
59
+ end
60
+
61
+ # Class-level method to to turn on validation for the response from any successful html request via "get"
62
+ def self.assert_all_valid_markup
63
+ self.class_eval do
64
+ # automatically check markup for all successfull GETs
65
+ def get_with_assert_valid_markup(*args)
66
+ get_without_assert_valid_markup(*args)
67
+ assert_valid_markup if ! @@skip_validation && @request.format.html? && @response.success?
68
+ end
69
+ alias_method_chain :get, :assert_valid_markup
70
+ end
71
+ end
72
+
73
+ @@skip_validation = false
74
+
75
+ # Allows one to skip validation for the given block - useful when you use assert_all_valid_markup and need to only
76
+ # skip validation for a handful of tests
77
+ def skip_markup_validation
78
+ begin
79
+ @@skip_validation = true
80
+ yield
81
+ ensure
82
+ @@skip_validation = false
83
+ end
84
+ end
85
+
86
+ def local_validate(xmldata, dtd_validate, catalog_path)
87
+ catalog_file = "#{catalog_path}/catalog"
88
+ if ! File.exists? catalog_path
89
+ puts "Creating xml catalog at: #{catalog_path}"
90
+ FileUtils.mkdir_p(catalog_path)
91
+ out = `xmlcatalog --noout --create '#{catalog_file}' 2>&1`
92
+ if $? != 0
93
+ puts out
94
+ exit 1
95
+ end
96
+ end
97
+
98
+ ENV["XML_DEBUG_CATALOG"] = ""
99
+ ENV["SGML_CATALOG_FILES"] = catalog_file
100
+ tmpfile = Tempfile.new('xmllint')
101
+ tmpfile.write(xmldata)
102
+ tmpfile.close
103
+ validation_output = `xmllint --catalogs --memory --noout #{dtd_validate ? '--valid' : ''} #{tmpfile.path} 2>&1`
104
+ ENV.delete("XML_DEBUG_CATALOG")
105
+
106
+ validation_output.each do |line|
107
+ line.chomp!
108
+ if match = line.match(/Resolve: pubID (.*) sysID (.*)/)
109
+ pubid = match[1]
110
+ sysid = match[2]
111
+ localdtd = "#{catalog_path}/#{sysid.split('/').last}"
112
+ if ! File.exists? localdtd
113
+ puts "Adding xml catalog resource\n\tpublic id: '#{pubid}'\n\turi: '#{sysid}'\n\tfile: '#{localdtd}'"
114
+ open(localdtd, "w") {|f| f.write(open(sysid).read())}
115
+ out = `xmlcatalog --noout --add 'public' '#{pubid}' 'file://#{localdtd}' '#{catalog_file}' 2>&1`
116
+ if $? != 0
117
+ puts out
118
+ exit 1
119
+ end
120
+ end
121
+ end
122
+ end
123
+ validation_failed = validation_output.grep(/^#{Regexp.escape(tmpfile.path)}:/)
124
+ return validation_failed.collect {|l| l.gsub(/^[^:]*:/, "Invalid markup: line ")}.join("\n")
125
+ end
126
+
127
+ def w3c_validate(fragment, dtd_validate)
128
+ validation_result = ''
129
+ begin
130
+ filename = File.join Dir::tmpdir, 'markup.' + Digest::MD5.hexdigest(fragment).to_s
131
+ if ! ENV['NO_CACHE_VALIDATION']
132
+ response = File.open filename {|f| Marshal.load(f) } unless ENV['NO_CACHE_VALIDATION'] rescue nil
133
+ end
134
+ if ! response
135
+ response = Net::HTTP.start('validator.w3.org').post2('/check', "fragment=#{CGI.escape(fragment)}&output=xml")
136
+ File.open filename, 'w+' do |f| Marshal.dump response, f end
137
+ end
138
+ markup_is_valid = response['x-w3c-validator-status']=='Valid'
139
+ if ! markup_is_valid
140
+ doc = XmlSimple.xml_in(response.body)
141
+ validation_result = doc['messages'][0]['msg'].collect{ |m| "Invalid markup: line #{m['line']}: #{CGI.unescapeHTML(m['content'])}" }.join("\n")
142
+ end
143
+ rescue SocketError
144
+ # if we can't reach the validator service, just let the test pass
145
+ puts "WARNING: Could not reach w3c validator service"
146
+ end
147
+ return validation_result
148
+ end
149
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'assert_valid_markup'
@@ -0,0 +1,178 @@
1
+ require 'test_helper'
2
+ require "active_support/core_ext/module"
3
+
4
+ class DummyControllerTestCase < Test::Unit::TestCase
5
+ def get(body, html, success)
6
+ @request = stub(:format => stub(:html? => html))
7
+ @response = stub(:body => "#{body}", :success? => success)
8
+ end
9
+ end
10
+
11
+ class AssertValidMarkupTest < Test::Unit::TestCase
12
+
13
+ VALID = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><title></title></head><body></body></html>'
14
+ INVALID = '<foo>'
15
+
16
+ def teardown
17
+ Object.constants.grep(/^DummyMarkup/).each do |c|
18
+ Object.send(:remove_const, c)
19
+ end
20
+ end
21
+
22
+
23
+ should "validate markup on simple test" do
24
+
25
+ eval <<-CLAZZ
26
+ class ::DummyMarkupTest < Test::Unit::TestCase
27
+ def test_foo
28
+ assert_valid_markup('#{VALID}', :validation_service => :local)
29
+ end
30
+ end
31
+ CLAZZ
32
+
33
+ result = Test::Unit::TestResult.new
34
+ DummyMarkupTest.new('test_foo').run(result, &lambda {} )
35
+ assert_equal 1, result.run_count
36
+ assert_equal 1, result.assertion_count
37
+ assert result.passed?
38
+ end
39
+
40
+ should "fail to validate for bad markup" do
41
+
42
+ eval <<-CLAZZ
43
+ class ::DummyMarkupTest < Test::Unit::TestCase
44
+ def test_foo
45
+ assert_valid_markup('#{INVALID}', :validation_service => :local)
46
+ end
47
+ end
48
+ CLAZZ
49
+
50
+ result = Test::Unit::TestResult.new
51
+ DummyMarkupTest.new('test_foo').run(result, &lambda {} )
52
+ assert_equal 1, result.run_count
53
+ assert_equal 1, result.assertion_count
54
+ assert ! result.passed?
55
+ end
56
+
57
+ should "validate for action controller response" do
58
+ eval <<-CLAZZ
59
+ class ::DummyMarkupTest < Test::Unit::TestCase
60
+ def test_foo
61
+ @response = mock(:body => '#{VALID}')
62
+ assert_valid_markup
63
+ end
64
+ end
65
+ CLAZZ
66
+
67
+ result = Test::Unit::TestResult.new
68
+ DummyMarkupTest.new('test_foo').run(result, &lambda {} )
69
+ assert_equal 1, result.run_count
70
+ assert result.passed?
71
+ end
72
+
73
+ should "validate with web service if no xmllint" do
74
+
75
+ eval <<-CLAZZ
76
+ class ::DummyMarkupTest < Test::Unit::TestCase
77
+ def test_foo
78
+ assert_valid_markup('#{VALID}', :validation_service => :w3c)
79
+ end
80
+ end
81
+ CLAZZ
82
+
83
+ result = Test::Unit::TestResult.new
84
+ DummyMarkupTest.new('test_foo').run(result, &lambda {} )
85
+ assert_equal 1, result.run_count
86
+ assert_equal 1, result.assertion_count
87
+ assert result.passed?
88
+ end
89
+
90
+ should "fail validation with web service if no xmllint" do
91
+
92
+ eval <<-CLAZZ
93
+ class ::DummyMarkupTest < Test::Unit::TestCase
94
+ def test_foo
95
+ assert_valid_markup('#{INVALID}', :validation_service => :w3c)
96
+ end
97
+ end
98
+ CLAZZ
99
+
100
+ result = Test::Unit::TestResult.new
101
+ DummyMarkupTest.new('test_foo').run(result, &lambda {} )
102
+ assert_equal 1, result.run_count
103
+ assert_equal 1, result.assertion_count
104
+ assert ! result.passed?
105
+ end
106
+
107
+ should "validate action controller tests that call get" do
108
+ eval <<-CLAZZ
109
+ class ::DummyMarkupControllerTest < DummyControllerTestCase
110
+ assert_all_valid_markup
111
+
112
+ def test_foo
113
+ get(VALID, true, true)
114
+ end
115
+ end
116
+ CLAZZ
117
+
118
+ result = Test::Unit::TestResult.new
119
+ tc = DummyMarkupControllerTest.new('test_foo')
120
+ tc.run(result, &lambda {} )
121
+ assert_equal 1, result.run_count
122
+ assert result.passed?
123
+ end
124
+
125
+ should "validate all action controller tests that call get" do
126
+ eval <<-CLAZZ
127
+ class ::DummyMarkupControllerTest < DummyControllerTestCase
128
+ assert_all_valid_markup
129
+
130
+ def test_foo
131
+ get(INVALID, true, true)
132
+ end
133
+
134
+ def test_bar
135
+ get(INVALID, true, true)
136
+ end
137
+ end
138
+ CLAZZ
139
+
140
+ result = Test::Unit::TestResult.new
141
+ tc = DummyMarkupControllerTest.suite
142
+ tc.run(result, &lambda {} )
143
+ assert_equal 2, result.run_count
144
+ assert_equal 2, result.failure_count
145
+ assert ! result.passed?
146
+ end
147
+
148
+ should "not validate action controller tests that call get with failure or non-html or skip" do
149
+ eval <<-CLAZZ
150
+ class ::DummyMarkupControllerTest < DummyControllerTestCase
151
+ assert_all_valid_markup
152
+
153
+ def test_foo
154
+ get(INVALID, true, false)
155
+ end
156
+
157
+ def test_bar
158
+ get(INVALID, false, true)
159
+ end
160
+
161
+ def test_baz
162
+ skip_markup_validation do
163
+ get(INVALID, true, true)
164
+ end
165
+ end
166
+ end
167
+ CLAZZ
168
+
169
+ result = Test::Unit::TestResult.new
170
+ tc = DummyMarkupControllerTest.suite
171
+ tc.run(result, &lambda {} )
172
+ p result
173
+ assert_equal 3, result.run_count
174
+ assert_equal 0, result.failure_count
175
+ assert result.passed?
176
+ end
177
+
178
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'assert_valid_markup'
9
+
10
+ class Test::Unit::TestCase
11
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: assert_valid_markup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Matt Conway
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-28 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mocha
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: shoulda
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: activesupport
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: xml-simple
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ description: Also contains some conveniences such as a flag to clear w3c cache at runtime, and some other cleanups
56
+ email: wr0ngway@yahoo.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - LICENSE
63
+ - README.rdoc
64
+ files:
65
+ - LICENSE
66
+ - README.rdoc
67
+ - VERSION
68
+ - init.rb
69
+ - lib/assert_valid_markup.rb
70
+ - rails/init.rb
71
+ has_rdoc: true
72
+ homepage: http://github.com/wr0ngway/assert_valid_markup
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options:
77
+ - --charset=UTF-8
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ version:
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.3.5
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: Fork of assert_valid_markup, sped up by using xmllint locally rather than hitting w3c service
99
+ test_files:
100
+ - test/assert_valid_markup_test.rb
101
+ - test/test_helper.rb