html-proofer 1.6.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +74 -56
  4. data/Rakefile +4 -6
  5. data/bin/htmlproof +46 -36
  6. data/html-proofer.gemspec +22 -22
  7. data/lib/html/proofer/check_runner/issue.rb +62 -0
  8. data/lib/html/proofer/{check.rb → check_runner.rb} +11 -19
  9. data/lib/html/proofer/checkable.rb +42 -28
  10. data/lib/html/proofer/checks/favicon.rb +6 -6
  11. data/lib/html/proofer/checks/html.rb +11 -12
  12. data/lib/html/proofer/checks/images.rb +11 -11
  13. data/lib/html/proofer/checks/links.rb +30 -28
  14. data/lib/html/proofer/checks/scripts.rb +7 -8
  15. data/lib/html/proofer/log.rb +38 -0
  16. data/lib/html/proofer/url_validator.rb +135 -0
  17. data/lib/html/proofer/utils.rb +24 -0
  18. data/lib/html/proofer/version.rb +1 -1
  19. data/lib/html/proofer.rb +95 -199
  20. data/spec/html/proofer/command_spec.rb +82 -0
  21. data/spec/html/proofer/favicon_spec.rb +20 -20
  22. data/spec/html/proofer/fixtures/images/srcSetCheck.html +7 -0
  23. data/spec/html/proofer/fixtures/images/srcSetIgnorable.html +13 -0
  24. data/spec/html/proofer/fixtures/images/srcSetMissingAlt.html +7 -0
  25. data/spec/html/proofer/fixtures/images/srcSetMissingImage.html +7 -0
  26. data/spec/html/proofer/fixtures/links/erstiebegru/314/210/303/237ung.html +1 -0
  27. data/spec/html/proofer/fixtures/links/erstiebegr/303/274/303/237ung.html +1 -0
  28. data/spec/html/proofer/fixtures/links/file.foo +11 -0
  29. data/spec/html/proofer/fixtures/links/folder/multiples/catalog/file.html +8 -0
  30. data/spec/html/proofer/fixtures/links/folder/multiples/javadoc/file.html +8 -0
  31. data/spec/html/proofer/fixtures/links/nodupe.html +1 -1
  32. data/spec/html/proofer/fixtures/links/redirected_error.html +1 -0
  33. data/spec/html/proofer/fixtures/links/rootLink/rootLink.html +0 -1
  34. data/spec/html/proofer/fixtures/links/urlencoded-href.html +2 -0
  35. data/spec/html/proofer/fixtures/links/utf8Link.html +2 -0
  36. data/spec/html/proofer/fixtures/utils/lang-jp.html +1 -0
  37. data/spec/html/proofer/html_spec.rb +25 -25
  38. data/spec/html/proofer/images_spec.rb +59 -35
  39. data/spec/html/proofer/links_spec.rb +152 -109
  40. data/spec/html/proofer/scripts_spec.rb +17 -17
  41. data/spec/html/proofer/utils_spec.rb +14 -0
  42. data/spec/html/proofer_spec.rb +58 -38
  43. data/spec/spec_helper.rb +13 -6
  44. metadata +39 -7
  45. data/lib/html/proofer/checks.rb +0 -15
  46. data/lib/html/proofer/issue.rb +0 -21
data/lib/html/proofer.rb CHANGED
@@ -1,40 +1,34 @@
1
- require 'nokogiri'
2
- require 'yell'
1
+ def require_all(path)
2
+ glob = File.join(File.dirname(__FILE__), path, '*.rb')
3
+ Dir[glob].each do |f|
4
+ require f
5
+ end
6
+ end
7
+
8
+ require_all 'proofer'
9
+ require_all 'proofer/check_runner'
10
+ require_all 'proofer/checks'
11
+ require_relative './proofer/utils'
12
+
3
13
  require 'parallel'
4
- require "addressable/uri"
5
14
 
6
15
  begin
7
- require "awesome_print"
16
+ require 'awesome_print'
8
17
  rescue LoadError; end
9
18
 
10
- %w[
11
- checkable
12
- checks
13
- issue
14
- version
15
- ].each { |r| require File.join(File.dirname(__FILE__), "proofer", r) }
16
-
17
19
  module HTML
18
20
 
19
- def self.colorize(color, string)
20
- if $stdout.isatty && $stderr.isatty
21
- Colored.colorize(string, :foreground => color)
22
- else
23
- string
24
- end
25
- end
26
-
27
21
  class Proofer
28
- include Yell::Loggable
22
+ include Utils
29
23
 
30
24
  attr_reader :options, :typhoeus_opts, :parallel_opts
31
25
 
32
- def initialize(src, opts={})
26
+ def initialize(src, opts = {})
33
27
  @src = src
34
28
 
35
29
  @proofer_opts = {
36
- :ext => ".html",
37
- :favicon => false,
30
+ :ext => '.html',
31
+ :check_favicon => false,
38
32
  :href_swap => [],
39
33
  :href_ignore => [],
40
34
  :file_ignore => [],
@@ -43,184 +37,103 @@ module HTML
43
37
  :disable_external => false,
44
38
  :verbose => false,
45
39
  :only_4xx => false,
46
- :directory_index_file => "index.html",
47
- :validate_html => false,
48
- :error_sort => :path
40
+ :directory_index_file => 'index.html',
41
+ :check_html => false,
42
+ :error_sort => :path,
43
+ :checks_to_ignore => []
49
44
  }
50
45
 
51
- @typhoeus_opts = {
46
+ @typhoeus_opts = opts[:typhoeus] || {
52
47
  :followlocation => true
53
48
  }
49
+ opts.delete(:typhoeus)
50
+
51
+ @hydra_opts = opts[:hydra] || {}
52
+ opts.delete(:hydra)
54
53
 
55
54
  # fall back to parallel defaults
56
55
  @parallel_opts = opts[:parallel] || {}
57
56
  opts.delete(:parallel)
58
57
 
59
- # Typhoeus won't let you pass in any non-Typhoeus option; if the option is not
60
- # a proofer_opt, it must be for Typhoeus
61
- opts.keys.each do |key|
62
- if @proofer_opts[key].nil?
63
- @typhoeus_opts[key] = opts[key]
64
- end
65
- end
66
-
67
- @options = @proofer_opts.merge(@typhoeus_opts).merge(opts)
58
+ @options = @proofer_opts.merge(opts)
68
59
 
69
60
  @failed_tests = []
61
+ end
70
62
 
71
- Yell.new({ :format => false, :name => "HTML::Proofer", :level => "gte.#{log_level}" }) do |l|
72
- l.adapter :stdout, level: [:debug, :info, :warn]
73
- l.adapter :stderr, level: [:error, :fatal]
74
- end
63
+ def logger
64
+ @logger ||= HTML::Proofer::Log.new(@options[:verbose])
75
65
  end
76
66
 
77
67
  def run
78
- unless @src.is_a? Array
79
- external_urls = {}
80
-
81
- logger.info HTML::colorize :white, "Running #{get_checks} checks on #{@src} on *#{@options[:ext]}... \n\n"
82
-
83
- results = Parallel.map(files, @parallel_opts) do |path|
84
- html = HTML::Proofer.create_nokogiri(path)
85
- result = {:external_urls => {}, :failed_tests => []}
86
-
87
- get_checks.each do |klass|
88
- logger.debug HTML::colorize :blue, "Checking #{klass.to_s.downcase} on #{path} ..."
89
- check = Object.const_get(klass).new(@src, path, html, @options)
90
- check.run
91
- result[:external_urls].merge!(check.external_urls)
92
- result[:failed_tests].concat(check.issues) if check.issues.length > 0
93
- end
94
- result
95
- end
96
-
97
- results.each do |item|
98
- external_urls.merge!(item[:external_urls])
99
- @failed_tests.concat(item[:failed_tests])
100
- end
101
-
102
- external_link_checker(external_urls) unless @options[:disable_external]
68
+ count = checks.length
69
+ check_text = "#{checks} " << (count == 1 ? 'check' : 'checks')
70
+ logger.log :info, :blue, "Running #{check_text} on #{@src} on *#{@options[:ext]}... \n\n"
103
71
 
104
- logger.info HTML::colorize :green, "Ran on #{files.length} files!\n\n"
72
+ if @src.is_a?(Array) && !@options[:disable_external]
73
+ check_list_of_links
105
74
  else
106
- external_urls = Hash[*@src.map{ |s| [s, nil] }.flatten]
107
- external_link_checker(external_urls) unless @options[:disable_external]
75
+ check_directory_of_files
108
76
  end
109
77
 
110
78
  if @failed_tests.empty?
111
- logger.info HTML::colorize :green, "HTML-Proofer finished successfully."
79
+ logger.log :info, :green, 'HTML-Proofer finished successfully.'
112
80
  else
113
- matcher = nil
114
-
115
- # always sort by the actual option, then path, to ensure consistent alphabetical (by filename) results
116
- @failed_tests = @failed_tests.sort do |a,b|
117
- comp = (a.send(@options[:error_sort]) <=> b.send(@options[:error_sort]))
118
- comp.zero? ? (a.path <=> b.path) : comp
119
- end
81
+ print_failed_tests
82
+ end
83
+ end
120
84
 
121
- @failed_tests.each do |issue|
122
- case @options[:error_sort]
123
- when :path
124
- if matcher != issue.path
125
- logger.error HTML::colorize :blue, "- #{issue.path}"
126
- matcher = issue.path
127
- end
128
- logger.error HTML::colorize :red, " * #{issue.desc}"
129
- when :desc
130
- if matcher != issue.desc
131
- logger.error HTML::colorize :blue, "- #{issue.desc}"
132
- matcher = issue.desc
133
- end
134
- logger.error HTML::colorize :red, " * #{issue.path}"
135
- when :status
136
- if matcher != issue.status
137
- logger.error HTML::colorize :blue, "- #{issue.status}"
138
- matcher = issue.status
139
- end
140
- logger.error HTML::colorize :red, " * #{issue.to_s}"
141
- end
85
+ def check_list_of_links
86
+ if @options[:href_swap]
87
+ @src = @src.map do |external_url|
88
+ swap(external_url, @options[:href_swap])
142
89
  end
143
-
144
- raise HTML::colorize :red, "HTML-Proofer found #{@failed_tests.length} failures!"
145
90
  end
91
+ external_urls = Hash[*@src.map { |s| [s, nil] }.flatten]
92
+ validate_urls(external_urls)
146
93
  end
147
94
 
148
- # the hypothesis is that Proofer runs way faster if we pull out
149
- # all the external URLs and run the checks at the end. Otherwise, we're halting
150
- # the consuming process for every file. In addition, sorting the list lets
151
- # libcurl keep connections to hosts alive. Finally, we'll make a HEAD request,
152
- # rather than GETing all the contents
153
- def external_link_checker(external_urls)
154
- external_urls = Hash[external_urls.sort]
155
-
156
- logger.info HTML::colorize :yellow, "Checking #{external_urls.length} external links..."
95
+ # Collects any external URLs found in a directory of files. Also collectes
96
+ # every failed test from check_files_for_internal_woes.
97
+ # Sends the external URLs to Typhoeus for batch processing.
98
+ def check_directory_of_files
99
+ external_urls = {}
100
+ results = check_files_for_internal_woes
157
101
 
158
- Ethon.logger = logger # log from Typhoeus/Ethon
159
-
160
- external_urls.each_pair do |href, filenames|
161
- if has_hash? href && @options[:check_external_hash]
162
- queue_request(:get, href, filenames)
163
- else
164
- queue_request(:head, href, filenames)
165
- end
102
+ results.each do |item|
103
+ external_urls.merge!(item[:external_urls])
104
+ @failed_tests.concat(item[:failed_tests])
166
105
  end
167
- logger.debug HTML::colorize :yellow, "Running requests for all #{hydra.queued_requests.size} external URLs..."
168
- hydra.run
169
- end
170
106
 
171
- def queue_request(method, href, filenames)
172
- request = Typhoeus::Request.new(href, @typhoeus_opts.merge({:method => method}))
173
- request.on_complete { |response| response_handler(response, filenames) }
174
- hydra.queue request
107
+ validate_urls(external_urls) unless @options[:disable_external]
108
+
109
+ logger.log :info, :blue, "Ran on #{files.length} files!\n\n"
175
110
  end
176
111
 
177
- def response_handler(response, filenames)
178
- effective_url = response.options[:effective_url]
179
- href = response.request.base_url
180
- method = response.request.options[:method]
181
- response_code = response.code
182
-
183
- debug_msg = "Received a #{response_code} for #{href}"
184
- debug_msg << " in #{filenames.join(' ')}" unless filenames.nil?
185
- logger.debug debug_msg
186
-
187
- if response_code.between?(200, 299)
188
- return if @options[:only_4xx]
189
- return unless @options[:check_external_hash]
190
- if hash = has_hash?(href)
191
- body_doc = Nokogiri::HTML(response.body)
192
- # user-content is a special addition by GitHub.
193
- xpath = %$//*[@name="#{hash}"]|//*[@id="#{hash}"]$
194
- xpath << %$|//*[@name="user-content-#{hash}"]|//*[@id="user-content-#{hash}"]$ if URI.parse(href).host.match(/github\.com/i)
195
- if body_doc.xpath(xpath).empty?
196
- add_failed_tests filenames, "External link #{href} failed: #{effective_url} exists, but the hash '#{hash}' does not", response_code
197
- end
112
+ # Walks over each implemented check and runs them on the files, in parallel.
113
+ def check_files_for_internal_woes
114
+ Parallel.map(files, @parallel_opts) do |path|
115
+ html = create_nokogiri(path)
116
+ result = { :external_urls => {}, :failed_tests => [] }
117
+
118
+ checks.each do |klass|
119
+ logger.log :debug, :yellow, "Checking #{klass.to_s.downcase} on #{path} ..."
120
+ check = Object.const_get(klass).new(@src, path, html, @options)
121
+ check.run
122
+ result[:external_urls].merge!(check.external_urls)
123
+ result[:failed_tests].concat(check.issues) if check.issues.length > 0
198
124
  end
199
- elsif response.timed_out?
200
- return if @options[:only_4xx]
201
- add_failed_tests filenames, "External link #{href} failed: got a time out", response_code
202
- elsif (response_code == 405 || response_code == 420 || response_code == 503) && method == :head
203
- # 420s usually come from rate limiting; let's ignore the query and try just the path with a GET
204
- uri = URI(href)
205
- queue_request(:get, uri.scheme + "://" + uri.host + uri.path, filenames)
206
- # just be lazy; perform an explicit get request. some servers are apparently not configured to
207
- # intercept HTTP HEAD
208
- elsif method == :head
209
- queue_request(:get, effective_url, filenames)
210
- else
211
- return if @options[:only_4xx] && !response_code.between?(400, 499)
212
- # Received a non-successful http response.
213
- add_failed_tests filenames, "External link #{href} failed: #{response_code} #{response.return_message}", response_code
125
+ result
214
126
  end
215
127
  end
216
128
 
217
- def hydra
218
- @hydra ||= Typhoeus::Hydra.new
129
+ def validate_urls(external_urls)
130
+ url_validator = HTML::Proofer::UrlValidator.new(logger, external_urls, @options, @typhoeus_opts, @hydra_opts)
131
+ @failed_tests.concat(url_validator.run)
219
132
  end
220
133
 
221
134
  def files
222
135
  if File.directory? @src
223
- pattern = File.join @src, "**", "*#{@options[:ext]}"
136
+ pattern = File.join(@src, '**', "*#{@options[:ext]}")
224
137
  files = Dir.glob(pattern).select { |fn| File.file? fn }
225
138
  files.reject { |f| ignore_file?(f) }
226
139
  elsif File.extname(@src) == @options[:ext]
@@ -231,49 +144,23 @@ module HTML
231
144
  end
232
145
 
233
146
  def ignore_file?(file)
234
- @options[:file_ignore].each do |pattern|
235
- if pattern.is_a? String
236
- return pattern == file
237
- elsif pattern.is_a? Regexp
238
- return pattern =~ file
239
- end
147
+ options[:file_ignore].each do |pattern|
148
+ return true if pattern.is_a?(String) && pattern == file
149
+ return true if pattern.is_a?(Regexp) && pattern =~ file
240
150
  end
241
151
 
242
152
  false
243
153
  end
244
154
 
245
- def self.create_nokogiri(path)
246
- content = File.open(path).read
247
- Nokogiri::HTML(content)
248
- end
249
-
250
- def get_checks
251
- checks = HTML::Proofer::Checks::Check.subclasses.map { |c| c.name }
252
- checks.delete("Favicons") unless @options[:favicon]
253
- checks.delete("Html") unless @options[:validate_html]
254
- checks
255
- end
256
-
257
- def has_hash?(url)
258
- begin
259
- URI.parse(url).fragment
260
- rescue URI::InvalidURIError
261
- nil
262
- end
263
- end
264
-
265
- def log_level
266
- @options[:verbose] ? :debug : :info
267
- end
268
-
269
- def add_failed_tests(filenames, desc, status = nil)
270
- if filenames.nil?
271
- @failed_tests << Checks::Issue.new("", desc, status)
272
- elsif
273
- filenames.each { |f|
274
- @failed_tests << Checks::Issue.new(f, desc, status)
275
- }
155
+ def checks
156
+ return @checks unless @checks.nil?
157
+ @checks = HTML::Proofer::CheckRunner.checks.map(&:name)
158
+ @checks.delete('FaviconCheck') unless @options[:check_favicon]
159
+ @checks.delete('HtmlCheck') unless @options[:check_html]
160
+ @options[:checks_to_ignore].each do |ignored|
161
+ @checks.delete(ignored)
276
162
  end
163
+ @checks
277
164
  end
278
165
 
279
166
  def failed_tests
@@ -282,5 +169,14 @@ module HTML
282
169
  @failed_tests.each { |f| result << f.to_s }
283
170
  result
284
171
  end
172
+
173
+ def print_failed_tests
174
+ sorted_failures = HTML::Proofer::CheckRunner::SortedIssues.new(@failed_tests, @options[:error_sort], logger)
175
+
176
+ sorted_failures.sort_and_report
177
+ count = @failed_tests.length
178
+ failure_text = "#{count} " << (count == 1 ? 'failure' : 'failures')
179
+ fail logger.colorize :red, "HTML-Proofer found #{failure_text}!"
180
+ end
285
181
  end
286
182
  end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Command test' do
4
+ it 'works with as-links' do
5
+ output = make_bin('--as-links www.github.com,foofoofoo.biz')
6
+ expect(output).to match('1 failure')
7
+ end
8
+
9
+ it 'works with alt-ignore' do
10
+ ignorableLinks = "#{FIXTURES_DIR}/images/ignorableAltViaOptions.html"
11
+ output = make_bin('--alt-ignore /wikimedia/,gpl.png', ignorableLinks)
12
+ expect(output).to match('successfully')
13
+ end
14
+
15
+ it 'works with checks_to_ignore' do
16
+ external = "#{FIXTURES_DIR}/links/file.foo"
17
+ output = make_bin('--ext .foo --checks-to-ignore LinkCheck', external)
18
+ expect(output).to match('successfully')
19
+ expect(output).to_not match('LinkCheck')
20
+ end
21
+
22
+ it 'works with check-external-hash' do
23
+ brokenHashOnTheWeb = "#{FIXTURES_DIR}/links/brokenHashOnTheWeb.html"
24
+ output = make_bin('--check-external-hash', brokenHashOnTheWeb)
25
+ expect(output).to match('1 failure')
26
+ end
27
+
28
+ it 'works with directory-index-file' do
29
+ link_pointing_to_directory = "#{FIXTURES_DIR}/links/link_pointing_to_directory.html"
30
+ output = make_bin('--directory-index-file index.php', link_pointing_to_directory)
31
+ expect(output).to match('successfully')
32
+ end
33
+
34
+ it 'works with disable-external' do
35
+ external = "#{FIXTURES_DIR}/links/brokenLinkExternal.html"
36
+ output = make_bin('--disable-external', external)
37
+ expect(output).to match('successfully')
38
+ end
39
+
40
+ it 'works with ext' do
41
+ external = "#{FIXTURES_DIR}/links/file.foo"
42
+ output = make_bin('--ext .foo', external)
43
+ expect(output).to match('1 failure')
44
+ expect(output).to match('LinkCheck')
45
+ end
46
+
47
+ it 'works with file-ignore' do
48
+ external = "#{FIXTURES_DIR}/links/brokenHashInternal.html"
49
+ output = make_bin("--file-ignore #{external}", external)
50
+ expect(output).to match('successfully')
51
+ end
52
+
53
+ it 'works with href-ignore' do
54
+ ignorableLinks = "#{FIXTURES_DIR}/links/ignorableLinksViaOptions.html"
55
+ output = make_bin('--href-ignore /^http:\/\//,/sdadsad/,../whaadadt.html', ignorableLinks)
56
+ expect(output).to match('successfully')
57
+ end
58
+
59
+ it 'works with href-swap' do
60
+ translatedLink = "#{FIXTURES_DIR}/links/linkTranslatedViaHrefSwap.html"
61
+ output = make_bin('--href-swap "\A/articles/([\w-]+):\1.html"', translatedLink)
62
+ expect(output).to match('successfully')
63
+ end
64
+
65
+ it 'works with only-4xx' do
66
+ brokenHashOnTheWeb = "#{FIXTURES_DIR}/links/brokenHashOnTheWeb.html"
67
+ output = make_bin('--only-4xx', brokenHashOnTheWeb)
68
+ expect(output).to match('successfully')
69
+ end
70
+
71
+ it 'works with check-favicon' do
72
+ broken = "#{FIXTURES_DIR}/favicon/favicon_broken.html"
73
+ output = make_bin('--check-favicon', broken)
74
+ expect(output).to match('1 failure')
75
+ end
76
+
77
+ it 'works with check-html' do
78
+ broken = "#{FIXTURES_DIR}/html/invalid_tag.html"
79
+ output = make_bin('--check-html', broken)
80
+ expect(output).to match('1 failure')
81
+ end
82
+ end
@@ -1,47 +1,47 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
2
 
3
- describe "Favicons test" do
4
- it "ignores for absent favicon by default" do
3
+ describe 'Favicons test' do
4
+ it 'ignores for absent favicon by default' do
5
5
  absent = "#{FIXTURES_DIR}/favicon/favicon_absent.html"
6
- expect(make_proofer(absent).failed_tests).to eq []
6
+ expect(run_proofer(absent).failed_tests).to eq []
7
7
  end
8
8
 
9
- it "fails for absent favicon" do
9
+ it 'fails for absent favicon' do
10
10
  absent = "#{FIXTURES_DIR}/favicon/favicon_absent.html"
11
- proofer = make_proofer(absent, {:favicon => true})
12
- expect(proofer.failed_tests.first).to match /no favicon specified/
11
+ proofer = run_proofer(absent, { :check_favicon => true })
12
+ expect(proofer.failed_tests.first).to match(/no favicon specified/)
13
13
  end
14
14
 
15
- it "fails for absent favicon but present apple touch icon" do
15
+ it 'fails for absent favicon but present apple touch icon' do
16
16
  absent = "#{FIXTURES_DIR}/favicon/favicon_absent_apple.html"
17
- proofer = make_proofer(absent, {:favicon => true})
17
+ proofer = run_proofer(absent, { :check_favicon => true })
18
18
  # Travis gives a different error message here for some reason
19
- expect(proofer.failed_tests.last).to match /(internally linking to gpl.png, which does not exist|no favicon specified)/
19
+ expect(proofer.failed_tests.last).to match(/(internally linking to gpl.png, which does not exist|no favicon specified)/)
20
20
  end
21
21
 
22
- it "fails for broken favicon" do
22
+ it 'fails for broken favicon' do
23
23
  broken = "#{FIXTURES_DIR}/favicon/favicon_broken.html"
24
- proofer = make_proofer(broken, {:favicon => true})
24
+ proofer = run_proofer(broken, { :check_favicon => true })
25
25
 
26
- expect(proofer.failed_tests.first).to match /internally linking to asdadaskdalsdk.png/
26
+ expect(proofer.failed_tests.first).to match(/internally linking to asdadaskdalsdk.png/)
27
27
  end
28
28
 
29
- it "passes for present favicon" do
29
+ it 'passes for present favicon' do
30
30
  present = "#{FIXTURES_DIR}/favicon/favicon_present.html"
31
- proofer = make_proofer(present, {:favicon => true})
31
+ proofer = run_proofer(present, { :check_favicon => true })
32
32
  expect(proofer.failed_tests).to eq []
33
33
  end
34
34
 
35
- it "passes for present favicon with shortcut notation" do
35
+ it 'passes for present favicon with shortcut notation' do
36
36
  present = "#{FIXTURES_DIR}/favicon/favicon_present_shortcut.html"
37
- proofer = make_proofer(present, {:favicon => true})
37
+ proofer = run_proofer(present, { :check_favicon => true })
38
38
  expect(proofer.failed_tests).to eq []
39
39
  end
40
40
 
41
- it "fails for broken favicon with data-proofer-ignore" do
41
+ it 'fails for broken favicon with data-proofer-ignore' do
42
42
  broken_but_ignored = "#{FIXTURES_DIR}/favicon/favicon_broken_but_ignored.html"
43
- proofer = make_proofer(broken_but_ignored, {:favicon => true})
44
- expect(proofer.failed_tests.first).to match /no favicon specified/
43
+ proofer = run_proofer(broken_but_ignored, { :check_favicon => true })
44
+ expect(proofer.failed_tests.first).to match(/no favicon specified/)
45
45
  end
46
46
 
47
47
  end
@@ -0,0 +1,7 @@
1
+ <picture>
2
+ <!--[if IE 9]><video style="display: none;"><![endif]-->
3
+ <source srcset="examples/images/extralarge.jpg" media="(min-width: 1000px)">
4
+ <source srcset="examples/images/large.jpg" media="(min-width: 800px)">
5
+ <!--[if IE 9]></video><![endif]-->
6
+ <img src="gpl.png" alt="Working">
7
+ </picture>
@@ -0,0 +1,13 @@
1
+ <html>
2
+
3
+ <body>
4
+
5
+
6
+ <img src="gpl.png"/>Relative to self
7
+
8
+
9
+ <p>Blah blah blah. <img srcset="//upload.wikimedia.org/wikipedia/en/thumb/2/22/Heckert_GNU_white.svg/256px-Heckert_GNU_white.svg.png" /> </p>
10
+
11
+ </body>
12
+
13
+ </html>
@@ -0,0 +1,7 @@
1
+ <picture>
2
+ <!--[if IE 9]><video style="display: none;"><![endif]-->
3
+ <source srcset="examples/images/extralarge.jpg" media="(min-width: 1000px)">
4
+ <source srcset="examples/images/large.jpg" media="(min-width: 800px)">
5
+ <!--[if IE 9]></video><![endif]-->
6
+ <img srcset="gpl.png">
7
+ </picture>
@@ -0,0 +1,7 @@
1
+ <picture>
2
+ <!--[if IE 9]><video style="display: none;"><![endif]-->
3
+ <source srcset="examples/images/extralarge.jpg" media="(min-width: 1000px)">
4
+ <source srcset="examples/images/large.jpg" media="(min-width: 800px)">
5
+ <!--[if IE 9]></video><![endif]-->
6
+ <img srcset="notreal.png" alt="Missing image">
7
+ </picture>
@@ -0,0 +1,11 @@
1
+ <html>
2
+
3
+ <body>
4
+
5
+ <p>Blah blah blah. <a href="http://www.google.com">Working link!</a></p>
6
+
7
+
8
+ <a href="http://www.asdo3IRJ395295jsingrkrg4.com">broken link!</a>
9
+ </body>
10
+
11
+ </html>
@@ -0,0 +1,8 @@
1
+ <html>
2
+
3
+ <body>
4
+
5
+ <a href="http://www.asdo3IRJ395295jsingrkrg4.com">broken link!</a>
6
+ </body>
7
+
8
+ </html>
@@ -0,0 +1,8 @@
1
+ <html>
2
+
3
+ <body>
4
+
5
+ <a href="http://www.asdo3IRJ395295jsingrkrg4.com">broken link!</a>
6
+ </body>
7
+
8
+ </html>
@@ -1 +1 @@
1
- <a href="https://help.github.com/articles/generating-ssh-keys#step-3-add-your-ssh-key-to-github">add ssh</a>
1
+ <a href="https://help.github.com/articlezzz">add ssh</a>
@@ -0,0 +1 @@
1
+ <a href="http://asia.cnet.com/blogs/geekonomics/post.htm?id=63009224">not real</a>
@@ -3,7 +3,6 @@
3
3
  <body>
4
4
 
5
5
  <p>Blah blah blah. <a href="/">I am root.</a></p>
6
- <p>Blah blah blah. <a href="/folder">I am relative to root.</a></p>
7
6
 
8
7
  </body>
9
8
 
@@ -0,0 +1,2 @@
1
+ <a href="erstiebegr%C3%BC%C3%9Fung.html">Erstiebegrüßung</a>
2
+ <a href="erstiebegrüßung.html">Erstiebegrüßung</a>
@@ -0,0 +1,2 @@
1
+ <a href="http://ben.balter.com/2014/09/29/source-disclosed-≠-open-source/">utf8</a>
2
+ <a href="http://ben.balter.com/2014/09/29/source-disclosed-%E2%89%A0-open-source/">another utf8</a>
@@ -0,0 +1 @@
1
+ <html lang="jp">