CodeMonkeySteve-assert_valid_content 0.1
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/MIT-LICENSE +21 -0
- data/README.rdoc +74 -0
- data/lib/assert_valid_content.rb +28 -0
- data/lib/assert_valid_content/assertions.rb +64 -0
- data/lib/assert_valid_content/libxml.rb +38 -0
- data/lib/assert_valid_content/validator.rb +56 -0
- data/lib/assert_valid_content/w3c-net.rb +73 -0
- metadata +71 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2006-2009 Steve Sloan
|
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.
|
21
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
= assert_valid_content
|
2
|
+
|
3
|
+
assert_valid_content is a RubyGem which validates a variety content types (e.g. (X)HTML, CSS, XML) as part of your unit or functional tests.
|
4
|
+
It is inspired by assert_valid_markup[http://github.com/wr0ngway/assert_valid_markup] and
|
5
|
+
assert_valid_assert[http://www.realityforge.org/articles/2006/03/15/rails-plugin-to-validate-x-html-and-css] with the following goals:
|
6
|
+
|
7
|
+
* Allow for offline use (i.e. not reliant on web services)
|
8
|
+
* Validate a wide variety of content types: HTML, JS, JPEG, PDF, MP3, ad infinitum
|
9
|
+
* Packaged as a RubyGem, instead of a Rails plugin
|
10
|
+
* Provide for specification of more-stringent validation checks (e.g. image properties)
|
11
|
+
|
12
|
+
== Validation Modules
|
13
|
+
|
14
|
+
=== Currently supported:
|
15
|
+
[(X)HTML, XML] LibXML via libxml-ruby[http://libxml.rubyforge.org/]
|
16
|
+
[CSS] W3C CSS Validator Service[http://jigsaw.w3.org/css-validator]
|
17
|
+
|
18
|
+
=== Planned support:
|
19
|
+
[CSS] W3C CSS Validator (local execution)
|
20
|
+
[JPEG, PNG, et al.] ImageMagick via rmagick[http://rmagick.rubyforge.org]
|
21
|
+
[MP3, OGG, et al.] ruby-mp3info[http://ruby-mp3info.rubyforge.org/]
|
22
|
+
[PDF, MPEG, etc.] ?
|
23
|
+
|
24
|
+
== Usage
|
25
|
+
|
26
|
+
Validation is performed primary through dynamic assertion functions, defined in AssertValidContent::Assertions
|
27
|
+
(and automatically included into Test::Unit::TestCase, if it exists). The assertions are of the form:
|
28
|
+
|
29
|
+
assert_valid_TYPE( content )
|
30
|
+
|
31
|
+
where +TYPE+ is a MIME type name (e.g. "html", "css", etc.), and +content+ is a +String+, +Pathname+, or +IO+ object,
|
32
|
+
or any combination in an +Array+. If no +content+ is specified, and the caller is a Rails functional test, the
|
33
|
+
response body is used.
|
34
|
+
|
35
|
+
There are also a set of basic assertions:
|
36
|
+
|
37
|
+
assert_valid_content( type, content )
|
38
|
+
valid_content?( type, content ) # yields validator on invalid content
|
39
|
+
|
40
|
+
where +type+ is a MIME type constant (e.g. "Mime::HTML").
|
41
|
+
|
42
|
+
== Examples
|
43
|
+
require 'rubygems'
|
44
|
+
require 'test/unit'
|
45
|
+
require 'assert_valid_content'
|
46
|
+
|
47
|
+
class ContentTest < Test::Unit::TestCase
|
48
|
+
# simple test
|
49
|
+
def test_html
|
50
|
+
html = "<html>...</html>"
|
51
|
+
|
52
|
+
# these are all equivalent
|
53
|
+
assert_valid_html html
|
54
|
+
assert_valid_html StringIO.new(html)
|
55
|
+
assert_valid_content Mime::HTML, html
|
56
|
+
assert valid_content?(Mime::HTML, html)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Rails controller test
|
60
|
+
def test_index
|
61
|
+
get :index
|
62
|
+
assert_response :success
|
63
|
+
assert_valid_html
|
64
|
+
end
|
65
|
+
|
66
|
+
# static content test
|
67
|
+
assert_valid_css Dir.glob("#{RAILS_ROOT}/public/stylesheets/*.css")
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
Author:: Steve Sloan (mailto:steve@finagle.org)
|
72
|
+
Website:: http://github.com/CodeMonkeySteve/assert_valid_content
|
73
|
+
Copyright:: Copyright (c) 2009 Steve Sloan
|
74
|
+
License:: MIT
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
module AssertValidContent
|
4
|
+
TempDir = if defined? RAILS_ROOT
|
5
|
+
File.join RAILS_ROOT, 'tmp/validate'
|
6
|
+
else
|
7
|
+
File.join Dir.tmpdir, 'assert_valid_content'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'assert_valid_content/libxml.rb'
|
12
|
+
if AssertValidContent::LibXML::Installed
|
13
|
+
AssertValidContent::LibXML::HTML.validates Mime::HTML
|
14
|
+
AssertValidContent::LibXML::XML. validates Mime::XML
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'assert_valid_content/w3c-net.rb'
|
18
|
+
if AssertValidContent::W3C::Installed
|
19
|
+
AssertValidContent::W3C::CSS.validates Mime::CSS
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'assert_valid_content/assertions.rb'
|
23
|
+
if defined? Test::Unit::TestCase
|
24
|
+
module Test # :nodoc:all
|
25
|
+
class Test::Unit::TestCase ; include AssertValidContent::Assertions ; end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'assert_valid_content/validator'
|
2
|
+
|
3
|
+
module AssertValidContent
|
4
|
+
|
5
|
+
# Test case assertions
|
6
|
+
module Assertions
|
7
|
+
|
8
|
+
# Asserts that the content (from one ore more +srcs+) is valid for type +type+.
|
9
|
+
# Each of +srcs+ is one of +String+, +Pathname+, or +IO+ object.
|
10
|
+
def assert_valid_content( type, *srcs )
|
11
|
+
msg = nil
|
12
|
+
for src in srcs
|
13
|
+
res = AssertValidContent.valid_content?(type, src) { |val| msg = val.to_s }
|
14
|
+
assert_block( msg ) { res }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :orig_method_missing, :method_missing #:nodoc:
|
19
|
+
|
20
|
+
# Implements the +assert_valid_TYPE+(*+srcs+) dynamic assertions, where +TYPE+ is a MIME type name
|
21
|
+
# (e.g. +html+, +css+, etc.) and each of +srcs+ one of +String+, +Pathname+, or +IO+ object.
|
22
|
+
def method_missing( name, *args )
|
23
|
+
n = name.to_s
|
24
|
+
return orig_method_missing( name, *args ) unless
|
25
|
+
(n[0..12] == 'assert_valid_') and (type = Mime::Type.lookup_by_extension n[13..-1])
|
26
|
+
|
27
|
+
if args.empty? and self.respond_to?(:response) and self.response.respond_to(:body)
|
28
|
+
args = [ self.response.body ]
|
29
|
+
end
|
30
|
+
|
31
|
+
assert_valid_content type, *args
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
alias_method :orig_method_missing, :method_missing #:nodoc:
|
36
|
+
|
37
|
+
# Implements the class-level +assert_valid_TYPE+(*+srcs+) dynamic assertions. See Assertions.method_missing.
|
38
|
+
def method_missing( name, *args )
|
39
|
+
n = name.to_s
|
40
|
+
return orig_method_missing( name, *args ) unless
|
41
|
+
(n[0..12] == 'assert_valid_') and (type = Mime::Type.lookup_by_extension n[13..-1])
|
42
|
+
|
43
|
+
self.assert_valid_static_content << [ type, *args ]
|
44
|
+
end
|
45
|
+
|
46
|
+
def assert_valid_static_content #:nodoc:
|
47
|
+
@assert_valid_static_content ||= []
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.included( base ) #:nodoc:
|
52
|
+
base.extend Assertions::ClassMethods
|
53
|
+
end
|
54
|
+
|
55
|
+
# Executes class-level assertions (i.e. static content).
|
56
|
+
def test__assert_valid_static_content #:nodoc:
|
57
|
+
for args in self.class.assert_valid_static_content
|
58
|
+
assert_valid_content *args
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'assert_valid_content/validator'
|
2
|
+
|
3
|
+
# Validates using LibXML via the libxml-ruby[http://libxml.rubyforge.org/] gem.
|
4
|
+
module AssertValidContent::LibXML
|
5
|
+
|
6
|
+
# +true+ if required dependencies are installed
|
7
|
+
Installed = begin
|
8
|
+
gem( 'libxml-ruby', '~> 1.1' )
|
9
|
+
require 'libxml'
|
10
|
+
true
|
11
|
+
rescue Gem::LoadError
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
# Validates HTML and XHTML
|
16
|
+
class AssertValidContent::LibXML::HTML < AssertValidContent::Validator
|
17
|
+
def validate( content ) #:nodoc:
|
18
|
+
::LibXML::XML::Error.set_handler { |err| @errors << err }
|
19
|
+
begin
|
20
|
+
doc = self.parser( content ).parse
|
21
|
+
rescue ::LibXML::XML::Error ; end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
def parser( content ) #:nodoc:
|
26
|
+
::LibXML::XML::HTMLParser.string content
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Validates XML
|
31
|
+
class AssertValidContent::LibXML::XML < HTML
|
32
|
+
protected
|
33
|
+
def parser( content ) #:nodoc:
|
34
|
+
::LibXML::XML::Parser.string content
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'action_controller' # for Mime::Type
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module AssertValidContent # :nodoc
|
5
|
+
|
6
|
+
# Hash of +type+ to sets of Validator objects for that type.
|
7
|
+
def self.validators ; @@validators ; end
|
8
|
+
@@validators = Hash.new { |h, k| h[k] = Set.new }
|
9
|
+
|
10
|
+
# Returns +true+ if the content from +src+ is valid for type +type+. Yields on failure.
|
11
|
+
# +src+ is one of +String+, +Pathname+, or +IO+ object
|
12
|
+
def self.valid_content?( type, src ) # :yields: validator
|
13
|
+
validators = AssertValidContent.validators[type]
|
14
|
+
raise "No validators for type: #{type}" if validators.empty?
|
15
|
+
|
16
|
+
content = case src
|
17
|
+
when String then src
|
18
|
+
when Pathname then IO.read src
|
19
|
+
when IO then src.read
|
20
|
+
else raise "Unknown content src type: #{src.class}"
|
21
|
+
end
|
22
|
+
|
23
|
+
val = nil
|
24
|
+
valid = validators.all? do |cl|
|
25
|
+
val = cl.new
|
26
|
+
val.validate content
|
27
|
+
val.errors.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
yield(val) if block_given? and not valid
|
31
|
+
valid
|
32
|
+
end
|
33
|
+
|
34
|
+
# Base class for all content validators
|
35
|
+
class Validator
|
36
|
+
# Validation errors
|
37
|
+
attr_reader :errors
|
38
|
+
|
39
|
+
def initialize #:nodoc:
|
40
|
+
@errors = []
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns an error message listing validation errors (or +nil+ if there were none).
|
44
|
+
def to_s
|
45
|
+
return nil unless @errors
|
46
|
+
"#{self.class.name} validation failed:\n" + @errors.map { |e| " #{e.to_s}" }.join("\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
# Register a derived class as a validator for content of type +type+
|
51
|
+
def self.validates( type )
|
52
|
+
AssertValidContent.validators[type] << self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'assert_valid_content/validator'
|
2
|
+
require 'md5'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'cgi'
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
# Validates using W3C Web Service(s)
|
8
|
+
module AssertValidContent::W3C
|
9
|
+
|
10
|
+
# +false+ if +NONET+ environment variable is defined (and non-zero).
|
11
|
+
Installed = ENV['NONET'].to_i.zero?
|
12
|
+
|
13
|
+
# Validates via the W3C CSS validator service[http://jigsaw.w3.org/css-validator/]
|
14
|
+
# (taken from assert-valid-asset[http://github.com/CodeMonkeySteve/assert-valid-asset]).
|
15
|
+
class CSS < AssertValidContent::Validator
|
16
|
+
|
17
|
+
SrvHost = ENV['CSS_VALIDATOR_HOST'] || 'jigsaw.w3.org'
|
18
|
+
SrvPath = ENV['CSS_VALIDATOR_PATH'] || '/css-validator/validator'
|
19
|
+
TempDir = File.join AssertValidContent::TempDir, 'w3c-net'
|
20
|
+
|
21
|
+
def validate( content ) #:nodoc:
|
22
|
+
FileUtils.mkdir_p TempDir
|
23
|
+
|
24
|
+
md5 = MD5.md5( content ).to_s
|
25
|
+
resp_path = File.join TempDir, md5
|
26
|
+
|
27
|
+
begin
|
28
|
+
resp = File.read resp_path
|
29
|
+
|
30
|
+
rescue
|
31
|
+
params = [
|
32
|
+
file_to_multipart( 'file', 'file.css', 'text/css', content ),
|
33
|
+
text_to_multipart( 'warning', '1' ),
|
34
|
+
text_to_multipart( 'profile', 'css2' ),
|
35
|
+
text_to_multipart( 'usermedium', 'all' ),
|
36
|
+
]
|
37
|
+
boundary = '-----------------------------24464570528145'
|
38
|
+
query = params.collect { |p| "--#{boundary}\r\n#{p}" }.join + "--#{boundary}--\r\n"
|
39
|
+
type = "multipart/form-data; boundary=#{boundary}"
|
40
|
+
|
41
|
+
resp = http.start(SrvHost).post2( SrvPath, query, 'Content-type' => type ).body
|
42
|
+
File.open( resp_path, 'w+' ) { |f| f.write resp }
|
43
|
+
end
|
44
|
+
|
45
|
+
begin
|
46
|
+
root = REXML::Document.new( resp ).root
|
47
|
+
REXML::XPath.each( root, "//x:tr[@class='error']", { "x"=>"http://www.w3.org/1999/xhtml" } ) do |el|
|
48
|
+
@errors << "Invalid CSS: line" + el.to_s.gsub(/<[^>]+>/,' ').gsub(/\n/,' ').gsub(/\s+/, ' ')
|
49
|
+
end
|
50
|
+
rescue REXML::ParseException
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def text_to_multipart(key,value) #:nodoc:
|
55
|
+
"Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"\r\n\r\n#{value}\r\n"
|
56
|
+
end
|
57
|
+
|
58
|
+
def file_to_multipart(key,filename,mime_type,content) #:nodoc:
|
59
|
+
"Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"; filename=\"#{filename}\"\r\n" +
|
60
|
+
"Content-Transfer-Encoding: binary\r\nContent-Type: #{mime_type}\r\n\r\n#{content}\r\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
def http #:nodoc:
|
64
|
+
if Module.constants.include?('ApplicationConfig') and ApplicationConfig.respond_to?(:proxy_config)
|
65
|
+
Net::HTTP::Proxy ApplicationConfig.proxy_config['host'], ApplicationConfig.proxy_config['port']
|
66
|
+
else
|
67
|
+
Net::HTTP
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: CodeMonkeySteve-assert_valid_content
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steve Sloan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-01 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: actionpack
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: Provides test assertions for the validity of various content types (i.e. HTML, XML CSS, etc).
|
26
|
+
email: steve@finagle.org
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.rdoc
|
33
|
+
files:
|
34
|
+
- README.rdoc
|
35
|
+
- MIT-LICENSE
|
36
|
+
- lib/assert_valid_content.rb
|
37
|
+
- lib/assert_valid_content/validator.rb
|
38
|
+
- lib/assert_valid_content/assertions.rb
|
39
|
+
- lib/assert_valid_content/libxml.rb
|
40
|
+
- lib/assert_valid_content/w3c-net.rb
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/CodeMonkeySteve/assert_valid_content
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options:
|
45
|
+
- --line-numbers
|
46
|
+
- --inline-source
|
47
|
+
- --main
|
48
|
+
- README.rdoc
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.2.0
|
67
|
+
signing_key:
|
68
|
+
specification_version: 2
|
69
|
+
summary: Content validation test suite
|
70
|
+
test_files: []
|
71
|
+
|