acop 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ acop-1.0.0.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # gem's dependencies in the tagfu gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2013 by Avinash Padmanabhan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ acop - enforcing accessibility for web pages
2
+ ============================================
3
+
4
+ Acop
5
+ ----
6
+
7
+ [Acop](http://eveningsamurai.github.io/acop/)
8
+
9
+ Description
10
+ -----------
11
+
12
+ acop is a command line utility for verifying accessibility in web pages
13
+
14
+ With acop, you can specify a url you want to test for accessibility and acop would run through a checklist of accessibility concerns and return any issues found
15
+
16
+ Installation
17
+ ------------
18
+
19
+ `gem install acop`
20
+
21
+ Synopsis
22
+ --------
23
+
24
+ Access the command line help
25
+
26
+ `acop --help`
27
+
28
+ Specify the url you want accessibility tested
29
+
30
+ `acop -u http://www.google.com`
31
+
32
+ Checkpoints
33
+ -----------
34
+ ### Images
35
+ `<input type='image'...`
36
+ * Image inputs elements should have alt attributes
37
+ * Image inputs elements should not have alt attributes empty
38
+
39
+ `<img...`
40
+ * Image elements should have alt attributes
41
+ * Image elements should not have alt attributes empty
42
+
43
+ `<a><img...`
44
+ * Image elements inside anchor tags should have empty alt attributes
45
+
46
+ ### Title
47
+ `<title></title>`
48
+ * Page title element should not be empty
49
+
50
+ `<!DOCTYPE Resource SYSTEM 'foo.dtd'>`
51
+ * doctype should be specified if frame or iframe elements exist on the page
52
+
53
+ `<frameset><frame title=""...`
54
+ * Frame elements should have title attributes
55
+ * Frame elements should not have title attributes empty
56
+
57
+ `<iframe title=""...`
58
+ * iFrame elements should have title attributes
59
+ * iFrame elements should not have title attributes empty
60
+
61
+ Bugs
62
+ ----
63
+ Report bugs and requests at [the Github page](https://github.com/eveningsamurai/acop).
64
+
65
+
66
+ Copyright
67
+ ---------
68
+
69
+ Copyright 2013 by [Avinash Padmanabhan](http://eveningsamurai.wordpress.com) under the MIT license (see the LICENSE file).
data/acop.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ require './lib/acop/version.rb'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'acop'
5
+ s.version = Acop::VERSION
6
+ s.date = '2013-04-22'
7
+ s.summary = "Accessibility Cop"
8
+ s.description = "A gem to enforce accessibility testing of urls'"
9
+ s.authors = ["Avinash Padmanabhan"]
10
+ s.email = ['avinashpadmanabhan@gmail.com']
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = ['spec/acop_spec.rb']
13
+ s.homepage = "https://github.com/eveningsamurai/acop"
14
+
15
+ s.add_development_dependency "OptionParser"
16
+ s.add_development_dependency "rspec"
17
+ s.add_development_dependency "nokogiri"
18
+ s.add_development_dependency "webmock"
19
+ s.require_paths = ["lib"]
20
+
21
+ s.executables << 'acop'
22
+
23
+ s.post_install_message = "Thanks for installing Accessibility Cop(acop)!"
24
+ end
data/bin/acop ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'acop'
4
+
5
+ Acop.run(*ARGV)
data/lib/acop.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'optparse'
2
+ require 'open-uri'
3
+ require_relative 'acop/accessibility.rb'
4
+
5
+ module Acop
6
+ def self.run(*args)
7
+ options = {}
8
+
9
+ option_parser = OptionParser.new do |opts|
10
+ opts.banner = 'Usage: acop -u URL'
11
+
12
+ opts.on('-u', '--url URL', 'Url to be accessibility tested') do |tag|
13
+ options[:url] = tag
14
+ end
15
+ end
16
+
17
+ begin
18
+ option_parser.parse!
19
+ raise OptionParser::MissingArgument, "Url should be provided!" if options.keys.empty?
20
+ raise OptionParser::InvalidArgument, "Url cannot be resolved!" unless valid_url?(options[:url])
21
+ rescue OptionParser::ParseError => e
22
+ puts e.message
23
+ puts
24
+ puts option_parser
25
+ exit -1
26
+ end
27
+
28
+ Enforcer.new(options).accessibility_checks
29
+ end
30
+
31
+ def self.valid_url?(url)
32
+ begin
33
+ url = "http://" + url unless url.include?("http")
34
+ contents = open(url)
35
+ return true
36
+ rescue Exception => e
37
+ return false
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,114 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ require 'rexml/document'
4
+
5
+ module Acop
6
+ class Enforcer
7
+ attr_reader :ah, :source, :contents
8
+
9
+ def initialize(options={})
10
+ @ah = Helpers.new
11
+ url = options[:url]
12
+ url = "http://" + options[:url] unless options[:url].include?("http")
13
+ @source = open(url)
14
+ @contents = Nokogiri::HTML(@source)
15
+ end
16
+
17
+ def accessibility_checks
18
+ error_messages = []
19
+
20
+ self.methods.each do |method|
21
+ error_messages << (self.public_send(method)) if method[0..5] == "check_"
22
+ end
23
+
24
+ puts error_messages
25
+ end
26
+
27
+ def check_image_input_alt(source=@contents)
28
+ input_elements = source.css('input')
29
+ image_inputs = input_elements.select {|image_input| image_input['type'] =~ /image/i}
30
+ error_messages = []
31
+ image_inputs.each do |input|
32
+ if (@ah.attribute_empty_or_nil(input, "alt") and input.parent.name != "a")
33
+ error_messages.push("Missing alt text/attribute for image button with id/name: " + (input['name'] || input['id'] || ""))
34
+ end
35
+ end
36
+ error_messages
37
+ end
38
+
39
+ def check_image_alt(source=@contents)
40
+ image_elements = source.css('img')
41
+ error_messages = []
42
+ image_elements.each do |element|
43
+ if (@ah.attribute_empty_or_nil(element, "alt") and element.parent.name != "a")
44
+ error_messages.push("Missing alt text/attribute for image with src: " + element['src'])
45
+ end
46
+ end
47
+ error_messages
48
+ end
49
+
50
+ def check_image_links(source=@contents)
51
+ link_elements = source.css('a img')
52
+ error_messages = []
53
+ image_links = []
54
+ link_elements.each do |link_element|
55
+ if(link_element['alt'] != "")
56
+ error_messages.push("Alt Text not empty or nil for image link with src: " + link_element['src'])
57
+ end
58
+ end
59
+ error_messages
60
+ end
61
+
62
+ def check_page_title(source=@contents)
63
+ title_element = source.css('title')
64
+ error_messages = []
65
+ error_messages.push("Missing title element") if title_element.empty?
66
+ error_messages.push("Empty title element") if(title_element.first and title_element.first.text == "")
67
+ error_messages.push("More than 1 title element") if title_element.length > 1
68
+
69
+ error_messages
70
+ end
71
+
72
+ def check_doctype(source=@contents)
73
+ frame_elements = source.css("frame")
74
+ iframe_elements = source.css("iframe")
75
+ error_messages = []
76
+ if(frame_elements.length > 0 or iframe_elements.length > 0)
77
+ doctype = REXML::Document.new(@source.string).doctype
78
+ error_messages.push("Frames/iFrames present but doctype is missing") unless doctype
79
+ end
80
+ error_messages
81
+ end
82
+
83
+ def check_frame_title(source=@contents)
84
+ return [] if source.css("frameset").length < 1
85
+ frame_elements = source.css("frame")
86
+ error_messages = []
87
+ frame_elements.each do |frame|
88
+ error_messages.push("Missing frame title element") unless frame['title']
89
+ error_messages.push("Empty frame title element") if frame['title'] == ""
90
+ end
91
+ error_messages
92
+ end
93
+
94
+ def check_iframe_title(source=@contents)
95
+ iframe_elements = source.css("iframe")
96
+ error_messages = []
97
+ iframe_elements.each do |iframe|
98
+ error_messages.push("Missing iframe title element") unless iframe['title']
99
+ error_messages.push("Empty iframe title element") if iframe['title'] == ""
100
+ end
101
+ error_messages
102
+ end
103
+ end
104
+
105
+ class Helpers
106
+ def attribute_empty_or_nil(element, attribute)
107
+ if(element[attribute] == nil || element[attribute] == "")
108
+ return true
109
+ end
110
+ false
111
+ end
112
+ end
113
+
114
+ end
@@ -0,0 +1,3 @@
1
+ module Acop
2
+ VERSION = "1.0.0"
3
+ end
data/spec/acop_spec.rb ADDED
@@ -0,0 +1,155 @@
1
+ require '../lib/acop/accessibility.rb'
2
+ require 'rspec/expectations'
3
+ require 'webmock/rspec'
4
+ require 'open-uri'
5
+
6
+ RSpec.configure do |config|
7
+ config.before(:all) do
8
+ end
9
+
10
+ config.after(:all) do
11
+ end
12
+
13
+ describe Acop::Enforcer do
14
+ it "should not return error messages when no issues with image tags" do
15
+ stub_request(:any, "www.example.com").to_return(:body => "<html><body><input type='image' alt='alt text'/></body></html>", :status => 200)
16
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
17
+ error_messages = enf.check_image_input_alt
18
+ error_messages.should be_empty
19
+ end
20
+
21
+ it "should return error messages when alt tags absent from input image elements" do
22
+ stub_request(:any, "www.example.com").to_return(:body => "<html><body><input type='image'/></body></html>", :status => 200)
23
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
24
+ error_messages = enf.check_image_input_alt
25
+ error_messages.should_not be_empty
26
+ error_messages[0].should match("Missing alt text/attribute for image button")
27
+ end
28
+
29
+ it "should return error messages when alt tags empty in input image elements" do
30
+ stub_request(:any, "www.example.com").to_return(:body => "<html><body><input type='image' alt=''/></body></html>", :status => 200)
31
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
32
+ error_messages = enf.check_image_input_alt
33
+ error_messages.should_not be_empty
34
+ error_messages[0].should match("Missing alt text/attribute for image button")
35
+ end
36
+
37
+ it "should return error messages when alt tags absent from image elements" do
38
+ stub_request(:any, "www.example.com").to_return(:body => "<html><body><img src='www.intuit.com'></body></html>", :status => 200)
39
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
40
+ error_messages = enf.check_image_alt
41
+ error_messages.should_not be_empty
42
+ error_messages[0].should match("Missing alt text/attribute for image with src")
43
+ end
44
+
45
+ it "should return error messages when alt tags empty in image elements" do
46
+ stub_request(:any, "www.example.com").to_return(:body => "<html><body><img alt='' src='www.intuit.com'></body></html>", :status => 200)
47
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
48
+ error_messages = enf.check_image_alt
49
+ error_messages.should_not be_empty
50
+ error_messages[0].should match("Missing alt text/attribute for image with src")
51
+ end
52
+
53
+ it "should return error messages when alt tags absent from image links" do
54
+ stub_request(:any, "www.example.com").to_return(:body => "<html><body><img src='www.intuit.com'></body></html>", :status => 200)
55
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
56
+ error_messages = enf.check_image_alt
57
+ error_messages.should_not be_empty
58
+ error_messages[0].should match("Missing alt text/attribute for image with src")
59
+ end
60
+
61
+ it "should have alt tags empty in image links" do
62
+ stub_request(:any, "www.example.com").to_return(:body => "<a class='visually-hidden'><img id='img_link' src='\/try_qbo_free.png' alt=''/>Try QuickBooks Online for Free</a>", :status => 200)
63
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
64
+ error_messages = enf.check_image_links
65
+ error_messages.should be_empty
66
+ end
67
+
68
+ it "should return error messages when alt tags not empty in image links" do
69
+ stub_request(:any, "www.example.com").to_return(:body => "<a class='visually-hidden'><img id='img_link' src='\/try_qbo_free.png' alt='bla bla'/>Try QuickBooks Online for Free</a>", :status => 200)
70
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
71
+ error_messages = enf.check_image_links
72
+ error_messages.should_not be_empty
73
+ error_messages[0].should match("Alt Text not empty or nil for image link with src")
74
+ end
75
+
76
+ it "should return error messages when alt tags nil in image links" do
77
+ stub_request(:any, "www.example.com").to_return(:body => "<a class='visually-hidden'><img id='img_link' src='\/try_qbo_free.png' alt='bla bla'/>Try QuickBooks Online for Free</a>", :status => 200)
78
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
79
+ error_messages = enf.check_image_links
80
+ error_messages.should_not be_empty
81
+ error_messages[0].should match("Alt Text not empty or nil for image link with src")
82
+ end
83
+
84
+ it "should return error messages when title not present" do
85
+ stub_request(:any, "www.example.com").to_return(:body => "<html><head></head></html>", :status => 200)
86
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
87
+ error_messages = enf.check_page_title
88
+ error_messages.should_not be_empty
89
+ error_messages[0].should match("Missing title element")
90
+ end
91
+
92
+ it "should return error messages when title element empty" do
93
+ stub_request(:any, "www.example.com").to_return(:body => "<html><head><title></title></head></html>", :status => 200)
94
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
95
+ error_messages = enf.check_page_title
96
+ error_messages.should_not be_empty
97
+ error_messages[0].should match("Empty title element")
98
+ end
99
+
100
+ it "should return error messages when more than 1 title element" do
101
+ stub_request(:any, "www.example.com").to_return(:body => "<html><head><title>Some Title</title><title>Another title</title></head></html>", :status => 200)
102
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
103
+ error_messages = enf.check_page_title
104
+ error_messages.should_not be_empty
105
+ error_messages[0].should match("More than 1 title element")
106
+ end
107
+
108
+ it "should return no error messages when frameset is not present" do
109
+ stub_request(:any, "www.example.com").to_return(:body => "<frame src='frame_a.htm' title=''><frame src='frame_b.htm' title='bla'>", :status => 200)
110
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
111
+ error_messages = enf.check_frame_title
112
+ error_messages.should be_empty
113
+ end
114
+
115
+ it "should return error messages when frame/iframe present but no doctype" do
116
+ stub_request(:any, "www.example.com").to_return(:body => "<!DOCTYPE Resource SYSTEM 'foo.dtd'><frameset cols='50%,50%'><frame src='frame_a.htm'/><frame src='frame_b.htm'/></frameset>", :status => 200)
117
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
118
+ error_messages = enf.check_doctype
119
+ puts error_messages
120
+ error_messages.should be_empty
121
+ end
122
+
123
+ it "should return error messages when frame does not have a title" do
124
+ stub_request(:any, "www.example.com").to_return(:body => "<frameset cols='50%,50%'><frame src='frame_a.htm'><frame src='frame_b.htm'></frameset>", :status => 200)
125
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
126
+ error_messages = enf.check_frame_title
127
+ error_messages.should_not be_empty
128
+ error_messages[0].should match("Missing frame title element")
129
+ end
130
+
131
+ it "should return error messages when frame title is empty" do
132
+ stub_request(:any, "www.example.com").to_return(:body => "<frameset cols='50%,50%'><frame src='frame_a.htm' title=''><frame src='frame_b.htm' title='bla'></frameset>", :status => 200)
133
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
134
+ error_messages = enf.check_frame_title
135
+ error_messages.should_not be_empty
136
+ error_messages[0].should match("Empty frame title element")
137
+ end
138
+
139
+ it "should return error messages when iframe does not have a title" do
140
+ stub_request(:any, "www.example.com").to_return(:body => "<iframe src='www.google.com'></iframe>", :status => 200)
141
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
142
+ error_messages = enf.check_iframe_title
143
+ error_messages.should_not be_empty
144
+ error_messages[0].should match("Missing iframe title element")
145
+ end
146
+
147
+ it "should return error messages when iframe title is empty" do
148
+ stub_request(:any, "www.example.com").to_return(:body => "<iframe title='' src='www.google.com'></iframe>", :status => 200)
149
+ enf = Acop::Enforcer.new({:url => "www.example.com"})
150
+ error_messages = enf.check_iframe_title
151
+ error_messages.should_not be_empty
152
+ error_messages[0].should match("Empty iframe title element")
153
+ end
154
+ end
155
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acop
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Avinash Padmanabhan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: OptionParser
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: nokogiri
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: webmock
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: A gem to enforce accessibility testing of urls'
79
+ email:
80
+ - avinashpadmanabhan@gmail.com
81
+ executables:
82
+ - acop
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - Gemfile
88
+ - LICENSE
89
+ - README.md
90
+ - acop.gemspec
91
+ - bin/acop
92
+ - lib/acop.rb
93
+ - lib/acop/accessibility.rb
94
+ - lib/acop/version.rb
95
+ - spec/acop_spec.rb
96
+ homepage: https://github.com/eveningsamurai/acop
97
+ licenses: []
98
+ post_install_message: Thanks for installing Accessibility Cop(acop)!
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 1.8.25
117
+ signing_key:
118
+ specification_version: 3
119
+ summary: Accessibility Cop
120
+ test_files:
121
+ - spec/acop_spec.rb