diff --git a/lib/html/proofer.rb b/lib/html/proofer.rb index 2c101290..fcbd08ba 100644 --- a/lib/html/proofer.rb +++ b/lib/html/proofer.rb @@ -16,7 +16,7 @@ def run Find.find(@srcDir) do |path| if File.extname(path) == @options[:ext] html = HTML::Proofer.create_nokogiri(path) - check = klass.new(path, html, @options) + check = klass.new(@srcDir, path, html, @options) check.run check.hydra.run self.print_issues(klass, check.issues) diff --git a/lib/html/proofer/check.rb b/lib/html/proofer/check.rb index dbc47f68..c92ffb15 100644 --- a/lib/html/proofer/check.rb +++ b/lib/html/proofer/check.rb @@ -12,7 +12,8 @@ class Check attr_reader :issues, :hydra - def initialize(path, html, opts={}) + def initialize(src, path, html, opts={}) + @src = src @path = path @html = html @options = opts @@ -91,5 +92,35 @@ def self.subclasses classes end + + def resolve_path(path) + + #Strip anchor, not needed to resolve file + path = path.split('#').first + + if path =~ /^\// #path relative to root + base = @src + elsif File.exist? File.join Dir.pwd, @path #relative links, path is a file + base = File.dirname(@path) + else #relative link, path is a directory + base = @path + end + + if path =~ /^#/ #anchor link, no trailing slash + path = "#{base}#{path}" + else # relative path, resolve trailing slashes automatically + path = File.join base, path + end + + # implicit /index.html support, with support for tailing slashes + path = File.join path, "index.html" if File.directory? File.join Dir.pwd, path + + path + end + + # checks if a file exists relative to the current pwd + def file?(path) + File.exist? File.join Dir.pwd, resolve_path(path) + end end end diff --git a/lib/html/proofer/checks/images.rb b/lib/html/proofer/checks/images.rb index be4ac68c..0e18ac4a 100644 --- a/lib/html/proofer/checks/images.rb +++ b/lib/html/proofer/checks/images.rb @@ -9,7 +9,7 @@ def run # check image sources if src && src.length > 0 if !external_href?(src) - self.add_issue("#{@path}".blue + ": internal image #{src} does not exist") unless src[0] != "/" and File.exist?(File.join(File.dirname(@path), src)) + self.add_issue("#{@path}".blue + ": internal image #{src} does not exist") unless file? src else validate_url(src, "#{@path}".blue + ": external image #{src} does not exist") end @@ -19,7 +19,7 @@ def run # check alt tag self.add_issue("#{@path}".blue + ": image #{src} does not have an alt attribute") unless img['alt'] and !img['alt'].empty? - + screenShotRegExp = /Screen(?: |%20)Shot(?: |%20)\d+-\d+-\d+(?: |%20)at(?: |%20)\d+.\d+.\d+/ if src =~ screenShotRegExp diff --git a/lib/html/proofer/checks/links.rb b/lib/html/proofer/checks/links.rb index 31da2fd1..b0b6772f 100644 --- a/lib/html/proofer/checks/links.rb +++ b/lib/html/proofer/checks/links.rb @@ -19,6 +19,7 @@ def run href_split = href.split('#') end if !external_href?(href) + # an internal link, with a hash if href_split && !href_split.empty? href_file = href_split[0] @@ -26,11 +27,10 @@ def run # it's not an internal hash; it's pointing to some other file if href_file.length > 0 - href_location = resolve_path File.join(File.dirname(@path), href_file) - if !File.exist?(href_location) - self.add_issue("#{@path}".blue + ": internal link #{href_location} does not exist") + if !file?(href_file) + self.add_issue("#{@path}".blue + ": internal link #{href_file} does not exist") else - href_html = HTML::Proofer.create_nokogiri(href_location) + href_html = HTML::Proofer.create_nokogiri(resolve_path(href_file)) found_hash_match = false unless hash_check(href_html, href_hash) self.add_issue("#{@path}".blue + ": linking to #{href}, but #{href_hash} does not exist") @@ -44,8 +44,7 @@ def run end # internal link, no hash else - href_location = resolve_path File.join(File.dirname(@path), href) - self.add_issue("#{@path}".blue + ": internally linking to #{href_location}, which does not exist") unless File.exist?(href_location) + self.add_issue("#{@path}".blue + ": internally linking to #{href}, which does not exist") unless file?(href) end else validate_url(href, "#{@path}".blue + ": externally linking to #{href}, which does not exist") @@ -60,9 +59,4 @@ def hash_check(html, href_hash) html.xpath("//*[@id='#{href_hash}']", "//*[@name='#{href_hash}']").length > 0 end - #support for implicit /index.html in URLs - def resolve_path(path) - path << "index.html" if File.directory? path - path - end end diff --git a/spec/html/proofer/fixtures/folder/anchorLink.html b/spec/html/proofer/fixtures/folder/anchorLink.html new file mode 100644 index 00000000..e69de29b diff --git a/spec/html/proofer/fixtures/index.html b/spec/html/proofer/fixtures/index.html index 0ce99707..8ec61e2d 100644 --- a/spec/html/proofer/fixtures/index.html +++ b/spec/html/proofer/fixtures/index.html @@ -1 +1 @@ -root. +

root. diff --git a/spec/html/proofer/fixtures/missingImageDirPrefix.html b/spec/html/proofer/fixtures/missingImageDirPrefix.html deleted file mode 100644 index 45319f6e..00000000 --- a/spec/html/proofer/fixtures/missingImageDirPrefix.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - -

Blah blah blah. A broken image, due to dir prefix

- - - - \ No newline at end of file diff --git a/spec/html/proofer/fixtures/relativeLinks.html b/spec/html/proofer/fixtures/relativeLinks.html new file mode 100644 index 00000000..08d061eb --- /dev/null +++ b/spec/html/proofer/fixtures/relativeLinks.html @@ -0,0 +1,4 @@ +Relative to root +Relative to self +Folder relative to self +Anchor relative to self diff --git a/spec/html/proofer/fixtures/rootLink.html b/spec/html/proofer/fixtures/rootLink.html index d3c31558..f22c5732 100644 --- a/spec/html/proofer/fixtures/rootLink.html +++ b/spec/html/proofer/fixtures/rootLink.html @@ -3,6 +3,7 @@

Blah blah blah. I am root.

+

Blah blah blah. I am relative to root.

diff --git a/spec/html/proofer/images_spec.rb b/spec/html/proofer/images_spec.rb index d3faadfa..0bf12213 100644 --- a/spec/html/proofer/images_spec.rb +++ b/spec/html/proofer/images_spec.rb @@ -3,35 +3,28 @@ describe "Image tests" do it "passes for existing external images" do externalImageFilepath = "#{FIXTURES_DIR}/existingImageExternal.html" - @imageCheck = Images.new(externalImageFilepath, HTML::Proofer.create_nokogiri(externalImageFilepath)) + @imageCheck = Images.new("#{FIXTURES_DIR}", externalImageFilepath, HTML::Proofer.create_nokogiri(externalImageFilepath)) @imageCheck.run @imageCheck.issues[0].should eq(nil) end it "fails for image without alt attribute" do missingAltFilepath = "#{FIXTURES_DIR}/missingImageAlt.html" - @imageCheck = Images.new(missingAltFilepath, HTML::Proofer.create_nokogiri(missingAltFilepath)) + @imageCheck = Images.new("#{FIXTURES_DIR}", missingAltFilepath, HTML::Proofer.create_nokogiri(missingAltFilepath)) @imageCheck.run @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageAlt.html".blue + ": image ./gpl.png does not have an alt attribute") end it "fails for image with an empty alt attribute" do missingAltFilepath = "#{FIXTURES_DIR}/missingImageAltText.html" - @imageCheck = Images.new(missingAltFilepath, HTML::Proofer.create_nokogiri(missingAltFilepath)) + @imageCheck = Images.new("#{FIXTURES_DIR}", missingAltFilepath, HTML::Proofer.create_nokogiri(missingAltFilepath)) @imageCheck.run @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageAltText.html".blue + ": image ./gpl.png does not have an alt attribute") end - it "fails for image without a dir prefix" do - missingImageDirPrefixFilepath = "#{FIXTURES_DIR}/missingImageDirPrefix.html" - @imageCheck = Images.new(missingImageDirPrefixFilepath, HTML::Proofer.create_nokogiri(missingImageDirPrefixFilepath)) - @imageCheck.run - @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageDirPrefix.html".blue + ": internal image /gpl.png does not exist") - end - it "fails for missing external images" do externalImageFilepath = "#{FIXTURES_DIR}/missingImageExternal.html" - @imageCheck = Images.new(externalImageFilepath, HTML::Proofer.create_nokogiri(externalImageFilepath)) + @imageCheck = Images.new("#{FIXTURES_DIR}", externalImageFilepath, HTML::Proofer.create_nokogiri(externalImageFilepath)) @imageCheck.run @imageCheck.hydra.run @imageCheck.issues[0].sub!(/ #/, "") @@ -40,21 +33,21 @@ it "fails for missing internal images" do internalImageFilepath = "#{FIXTURES_DIR}/missingImageInternal.html" - @imageCheck = Images.new(internalImageFilepath, HTML::Proofer.create_nokogiri(internalImageFilepath)) + @imageCheck = Images.new("#{FIXTURES_DIR}", internalImageFilepath, HTML::Proofer.create_nokogiri(internalImageFilepath)) @imageCheck.run @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageInternal.html".blue + ": internal image ./doesnotexist.png does not exist") end it "fails for image with no src" do imageSrcFilepath = "#{FIXTURES_DIR}/missingImageSrc.html" - @imageCheck = Images.new(imageSrcFilepath, HTML::Proofer.create_nokogiri(imageSrcFilepath)) + @imageCheck = Images.new("#{FIXTURES_DIR}", imageSrcFilepath, HTML::Proofer.create_nokogiri(imageSrcFilepath)) @imageCheck.run @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageSrc.html".blue + ": image has no src attribute") end it "fails for image with default mac filename" do terribleImageName = "#{FIXTURES_DIR}/terribleImageName.html" - @imageCheck = Images.new(terribleImageName, HTML::Proofer.create_nokogiri(terribleImageName)) + @imageCheck = Images.new("#{FIXTURES_DIR}", terribleImageName, HTML::Proofer.create_nokogiri(terribleImageName)) @imageCheck.run @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/terribleImageName.html".blue + ": image has a terrible filename (./Screen Shot 2012-08-09 at 7.51.18 AM.png)") end diff --git a/spec/html/proofer/links_spec.rb b/spec/html/proofer/links_spec.rb index 5cf5195a..7331521f 100644 --- a/spec/html/proofer/links_spec.rb +++ b/spec/html/proofer/links_spec.rb @@ -4,21 +4,21 @@ it "fails for broken external hash (even if the file exists)" do brokenHashExternalFilepath = "#{FIXTURES_DIR}/brokenHashExternal.html" - @linkCheck = Links.new(brokenHashExternalFilepath, HTML::Proofer.create_nokogiri(brokenHashExternalFilepath)) + @linkCheck = Links.new("#{FIXTURES_DIR}", brokenHashExternalFilepath, HTML::Proofer.create_nokogiri(brokenHashExternalFilepath)) @linkCheck.run @linkCheck.issues[1].should eq("spec/html/proofer/fixtures/brokenHashExternal.html".blue + ": linking to ./missingImageAlt.html#asdfasfdkafl, but asdfasfdkafl does not exist") end it "fails for broken internal hash" do brokenHashInternalFilepath = "#{FIXTURES_DIR}/brokenHashInternal.html" - @linkCheck = Links.new(brokenHashInternalFilepath, HTML::Proofer.create_nokogiri(brokenHashInternalFilepath)) + @linkCheck = Links.new("#{FIXTURES_DIR}", brokenHashInternalFilepath, HTML::Proofer.create_nokogiri(brokenHashInternalFilepath)) @linkCheck.run @linkCheck.issues[0].should eq("spec/html/proofer/fixtures/brokenHashInternal.html".blue + ": linking to an internal hash called noHash that does not exist") end it "fails for broken external links" do brokenLinkExternalFilepath = "#{FIXTURES_DIR}/brokenLinkExternal.html" - @linkCheck = Links.new(brokenLinkExternalFilepath, HTML::Proofer.create_nokogiri(brokenLinkExternalFilepath)) + @linkCheck = Links.new("#{FIXTURES_DIR}", brokenLinkExternalFilepath, HTML::Proofer.create_nokogiri(brokenLinkExternalFilepath)) @linkCheck.run @linkCheck.hydra.run @linkCheck.issues[0].sub!(/ #/, "") @@ -27,49 +27,56 @@ it "fails for broken internal links" do brokenLinkInternalFilepath = "#{FIXTURES_DIR}/brokenLinkInternal.html" - @linkCheck = Links.new(brokenLinkInternalFilepath, HTML::Proofer.create_nokogiri(brokenLinkInternalFilepath)) + @linkCheck = Links.new("#{FIXTURES_DIR}", brokenLinkInternalFilepath, HTML::Proofer.create_nokogiri(brokenLinkInternalFilepath)) @linkCheck.run - @linkCheck.issues[0].should eq("spec/html/proofer/fixtures/brokenLinkInternal.html".blue + ": internally linking to spec/html/proofer/fixtures/./notreal.html, which does not exist") + @linkCheck.issues[0].should eq("spec/html/proofer/fixtures/brokenLinkInternal.html".blue + ": internally linking to ./notreal.html, which does not exist") end it "fails for link with no href" do missingLinkHrefFilepath = "#{FIXTURES_DIR}/missingLinkHref.html" - @linkCheck = Links.new(missingLinkHrefFilepath, HTML::Proofer.create_nokogiri(missingLinkHrefFilepath)) + @linkCheck = Links.new("#{FIXTURES_DIR}", missingLinkHrefFilepath, HTML::Proofer.create_nokogiri(missingLinkHrefFilepath)) @linkCheck.run @linkCheck.issues[0].should eq("spec/html/proofer/fixtures/missingLinkHref.html".blue + ": link has no href attribute") end it "should follow redirects" do linkWithRedirectFilepath = "#{FIXTURES_DIR}/linkWithRedirect.html" - @linkCheck = Links.new(linkWithRedirectFilepath, HTML::Proofer.create_nokogiri(linkWithRedirectFilepath)) + @linkCheck = Links.new("#{FIXTURES_DIR}", linkWithRedirectFilepath, HTML::Proofer.create_nokogiri(linkWithRedirectFilepath)) @linkCheck.run @linkCheck.issues[0].should eq(nil) end it "should understand https" do linkWithHttpsFilepath = "#{FIXTURES_DIR}/linkWithHttps.html" - @linkCheck = Links.new(linkWithHttpsFilepath, HTML::Proofer.create_nokogiri(linkWithHttpsFilepath)) + @linkCheck = Links.new("#{FIXTURES_DIR}", linkWithHttpsFilepath, HTML::Proofer.create_nokogiri(linkWithHttpsFilepath)) @linkCheck.run @linkCheck.issues[0].should eq(nil) end it "fails for broken hash links with status code numbers" do brokenLinkWithNumberFilepath = "#{FIXTURES_DIR}/brokenLinkWithNumber.html" - @linkCheck = Links.new(brokenLinkWithNumberFilepath, HTML::Proofer.create_nokogiri(brokenLinkWithNumberFilepath)) + @linkCheck = Links.new("#{FIXTURES_DIR}", brokenLinkWithNumberFilepath, HTML::Proofer.create_nokogiri(brokenLinkWithNumberFilepath)) @linkCheck.run @linkCheck.issues[0].should eq(nil) end it 'properly resolves implicit /index.html in link paths' do linkToFolder = "#{FIXTURES_DIR}/linkToFolder.html" - @linkCheck = Links.new(linkToFolder, HTML::Proofer.create_nokogiri(linkToFolder)) + @linkCheck = Links.new("#{FIXTURES_DIR}", linkToFolder, HTML::Proofer.create_nokogiri(linkToFolder)) @linkCheck.run @linkCheck.issues[0].should eq(nil) end it 'properly checks links to root' do rootLink = "#{FIXTURES_DIR}/rootLink.html" - @linkCheck = Links.new(rootLink, HTML::Proofer.create_nokogiri(rootLink)) + @linkCheck = Links.new("#{FIXTURES_DIR}", rootLink, HTML::Proofer.create_nokogiri(rootLink)) + @linkCheck.run + @linkCheck.issues[0].should eq(nil) + end + + it 'properly checks relative links' do + relativeLinks = "#{FIXTURES_DIR}/relativeLinks.html" + @linkCheck = Links.new("#{FIXTURES_DIR}", relativeLinks, HTML::Proofer.create_nokogiri(relativeLinks)) @linkCheck.run @linkCheck.issues[0].should eq(nil) end