assert_valid_markup 0.5.0

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.
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