documentation updated

git-svn-id: https://linkchecker.svn.sourceforge.net/svnroot/linkchecker/trunk/linkchecker@2161 e7d03fd6-7b0d-0410-9947-9c21f3af8025
This commit is contained in:
calvin 2005-01-19 14:38:01 +00:00
parent b008747f39
commit a91183afa5
34 changed files with 889 additions and 307 deletions

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""define standard test support classes funtional for LinkChecker tests"""
"""
Define standard test support classes funtional for LinkChecker tests.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -31,11 +33,15 @@ import linkcheck.logger
class TestLogger (linkcheck.logger.Logger):
"""Output logger for automatic regression tests"""
"""
Output logger for automatic regression tests.
"""
def __init__ (self, **kwargs):
"""kwargs must have "expected" keyword with the expected logger
output lines"""
"""
The kwargs must have "expected" keyword with the expected logger
output lines.
"""
super(TestLogger, self).__init__(**kwargs)
# list of expected output lines
self.expected = kwargs['expected']
@ -45,11 +51,15 @@ class TestLogger (linkcheck.logger.Logger):
self.diff = []
def start_output (self):
"""nothing to do here"""
"""
Nothing to do here.
"""
pass
def new_url (self, url_data):
"""append logger output to self.result"""
"""
Append logger output to self.result.
"""
if self.has_field('url'):
url = u"url %s" % url_data.base_url
if url_data.cached:
@ -75,7 +85,9 @@ class TestLogger (linkcheck.logger.Logger):
# platform dependent
def end_output (self, linknumber=-1):
"""stores differences between expected and result in self.diff"""
"""
Stores differences between expected and result in self.diff.
"""
for line in difflib.unified_diff(self.expected, self.result):
if not isinstance(line, unicode):
line = unicode(line, "iso8859-1", "ignore")
@ -83,7 +95,9 @@ class TestLogger (linkcheck.logger.Logger):
def get_test_consumer (confargs, logargs):
"""initialize a test configuration object"""
"""
Initialize a test configuration object.
"""
config = linkcheck.configuration.Configuration()
config.logger_add('test', TestLogger)
config['recursionlevel'] = 1
@ -97,27 +111,35 @@ def get_test_consumer (confargs, logargs):
class StandardTest (unittest.TestCase):
"""functional test class with ability to test local files"""
"""
Functional test class with ability to test local files.
"""
def setUp (self):
"""check resources, using the provided function
check_resources() from test.py
"""
Check resources, using the provided function check_resources()
from test.py.
"""
super(StandardTest, self).setUp()
if hasattr(self, "needed_resources"):
self.check_resources(self.needed_resources)
def norm (self, url):
"""helper function to norm a url"""
"""
Helper function to norm a url.
"""
return linkcheck.url.url_norm(url)[0]
def get_file (self, filename):
"""get file name located within 'data' directory"""
"""
Get file name located within 'data' directory.
"""
return unicode(os.path.join("linkcheck", "ftests", "data", filename))
def get_resultlines (self, filename):
"""return contents of file, as list of lines without line endings,
ignoring empty lines and lines starting with a hash sign (#).
"""
Return contents of file, as list of lines without line endings,
ignoring empty lines and lines starting with a hash sign (#).
"""
resultfile = self.get_file(filename+".result")
f = codecs.open(resultfile, "r", "iso8859-1")
@ -128,7 +150,9 @@ class StandardTest (unittest.TestCase):
return resultlines
def file_test (self, filename):
"""check <filename> with expected result in <filename>.result"""
"""
Check <filename> with expected result in <filename>.result.
"""
url = self.get_file(filename)
confargs = {}
logargs = {'expected': self.get_resultlines(filename)}
@ -144,7 +168,9 @@ class StandardTest (unittest.TestCase):
self.fail(l.encode("iso8859-1", "ignore"))
def direct (self, url, resultlines, fields=None, recursionlevel=0):
"""check url with expected result"""
"""
Check url with expected result.
"""
assert isinstance(url, unicode), repr(url)
confargs = {'recursionlevel': recursionlevel}
logargs = {'expected': resultlines}

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""define http test support classes for LinkChecker tests"""
"""
Define http test support classes for LinkChecker tests.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -25,59 +27,83 @@ import linkcheck.ftests
class StoppableHttpRequestHandler (SimpleHTTPServer.SimpleHTTPRequestHandler, object):
"""http request handler with QUIT stopping the server"""
"""
Http request handler with QUIT stopping the server.
"""
def do_QUIT (self):
"""send 200 OK response, and set server.stop to True"""
"""
Send 200 OK response, and set server.stop to True.
"""
self.send_response(200)
self.end_headers()
self.server.stop = True
def log_message (self, format, *args):
"""logging is disabled"""
"""
Logging is disabled.
"""
pass
class StoppableHttpServer (BaseHTTPServer.HTTPServer, object):
"""http server that reacts to self.stop flag"""
"""
Http server that reacts to self.stop flag.
"""
def serve_forever (self):
"""Handle one request at a time until stopped."""
"""
Handle one request at a time until stopped.
"""
self.stop = False
while not self.stop:
self.handle_request()
class NoQueryHttpRequestHandler (StoppableHttpRequestHandler):
"""handler ignoring the query part of requests"""
"""
Handler ignoring the query part of requests.
"""
def remove_path_query (self):
"""remove everything after a question mark"""
"""
Remove everything after a question mark.
"""
i = self.path.find('?')
if i != -1:
self.path = self.path[:i]
def do_GET (self):
"""removes query part of GET request"""
"""
Removes query part of GET request.
"""
self.remove_path_query()
super(NoQueryHttpRequestHandler, self).do_GET()
def do_HEAD (self):
"""removes query part of HEAD request"""
"""
Removes query part of HEAD request.
"""
self.remove_path_query()
super(NoQueryHttpRequestHandler, self).do_HEAD()
class HttpServerTest (linkcheck.ftests.StandardTest):
"""start/stop an HTTP server that can be used for testing"""
"""
Start/stop an HTTP server that can be used for testing.
"""
def __init__ (self, methodName='runTest'):
"""init test class and store default http server port"""
"""
Init test class and store default http server port.
"""
super(HttpServerTest, self).__init__(methodName=methodName)
self.port = 8001
def start_server (self, handler=NoQueryHttpRequestHandler):
"""start a new HTTP server in a new thread"""
"""
Start a new HTTP server in a new thread.
"""
try:
import threading
except ImportError:
@ -88,14 +114,18 @@ class HttpServerTest (linkcheck.ftests.StandardTest):
time.sleep(3)
def stop_server (self):
"""send QUIT request to http server"""
"""
Send QUIT request to http server.
"""
conn = httplib.HTTPConnection("localhost:%d"%self.port)
conn.request("QUIT", "/")
conn.getresponse()
def start_server (port, handler):
"""start an HTTP server on given port"""
"""
Start an HTTP server on given port.
"""
ServerClass = StoppableHttpServer
server_address = ('', port)
handler.protocol_version = "HTTP/1.0"

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test html anchor parsing and checking"""
"""
Test html anchor parsing and checking.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -22,15 +24,21 @@ import linkcheck.ftests
class TestAnchor (linkcheck.ftests.StandardTest):
"""test anchor checking of HTML pages"""
"""
Test anchor checking of HTML pages.
"""
def test_anchor (self):
"""test anchors"""
"""
Test anchors.
"""
self.file_test("anchor.html")
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAnchor))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test html <base> tag parsing"""
"""
Test html <base> tag parsing.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -21,23 +23,33 @@ import unittest
import linkcheck.ftests
class TestBase (linkcheck.ftests.StandardTest):
"""test links of base*.html files"""
"""
Test links of base*.html files.
"""
def test_base1 (self):
"""test links of base1.html"""
"""
Test links of base1.html.
"""
self.file_test("base1.html")
def test_base2 (self):
"""test links of base2.html"""
"""
Test links of base2.html.
"""
self.file_test("base2.html")
def test_base3 (self):
"""test links of base3.html"""
"""
Test links of base3.html.
"""
self.file_test("base3.html")
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestBase))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test error checking"""
"""
Test error checking.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -23,10 +25,14 @@ import linkcheck.url
class TestError (linkcheck.ftests.StandardTest):
"""test unrecognized or syntactically wrong links"""
"""
Test unrecognized or syntactically wrong links.
"""
def test_unrecognized (self):
"""unrecognized scheme test"""
"""
Unrecognized scheme test.
"""
url = u"hutzli:"
nurl = self.norm(url)
resultlines = [
@ -38,7 +44,9 @@ class TestError (linkcheck.ftests.StandardTest):
self.direct(url, resultlines)
def test_leading_whitespace (self):
"""leading whitespace test"""
"""
Leading whitespace test.
"""
url = u" http://www.heise.de/"
nurl = self.norm(url)
resultlines = [
@ -59,7 +67,9 @@ class TestError (linkcheck.ftests.StandardTest):
self.direct(url, resultlines)
def test_trailing_whitespace (self):
"""trailing whitespace test"""
"""
Trailing whitespace test.
"""
url = u"http://www.heise.de/ "
nurl = self.norm(url)
resultlines = [
@ -82,7 +92,9 @@ class TestError (linkcheck.ftests.StandardTest):
self.direct(url, resultlines)
def test_invalid (self):
"""invalid syntax test"""
"""
Invalid syntax test.
"""
# invalid scheme chars
url = u"äöü?:"
nurl = self.norm(url)
@ -116,7 +128,9 @@ class TestError (linkcheck.ftests.StandardTest):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestError))
return suite

View file

@ -1,14 +1,20 @@
# -*- coding: iso-8859-1 -*-
"""test container routines"""
"""
Test container routines.
"""
import unittest
import os
class TestFcgi (unittest.TestCase):
"""test FastCGI request parsing routines"""
"""
Test FastCGI request parsing routines.
"""
def _test_fcgi (self):
"""test FastCGI request parsing routines"""
"""
Test FastCGI request parsing routines.
"""
# XXX inactive
counter = 0
try:
@ -62,7 +68,9 @@ class TestFcgi (unittest.TestCase):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestFcgi))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test file parsing"""
"""
Test file parsing.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -23,30 +25,44 @@ import linkcheck.ftests
class TestFile (linkcheck.ftests.StandardTest):
"""test file:// link checking (and file content parsing)"""
"""
Test file:// link checking (and file content parsing).
"""
def test_html (self):
"""test links of file.html"""
"""
Test links of file.html.
"""
self.file_test("file.html")
def test_text (self):
"""test links of file.txt"""
"""
Test links of file.txt.
"""
self.file_test("file.txt")
def test_asc (self):
"""test links of file.asc"""
"""
Test links of file.asc.
"""
self.file_test("file.asc")
def test_css (self):
"""test links of file.css"""
"""
Test links of file.css.
"""
self.file_test("file.css")
def test_urllist (self):
"""test url list parsing"""
"""
Test url list parsing.
"""
self.file_test("urllist.txt")
def test_files (self):
"""test some direct file links"""
"""
Test some direct file links.
"""
attrs = {'curdir': os.getcwd(),
'datadir': 'linkcheck/ftests/data',
}
@ -91,7 +107,9 @@ class TestFile (linkcheck.ftests.StandardTest):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestFile))
return suite

View file

@ -21,15 +21,21 @@ import unittest
import linkcheck.ftests
class TestFrames (linkcheck.ftests.StandardTest):
"""test link checking of HTML framesets"""
"""
Test link checking of HTML framesets.
"""
def test_frames (self):
"""test links of frames.html"""
"""
Test links of frames.html.
"""
self.file_test("frames.html")
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestFrames))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test ftp checking"""
"""
Test ftp checking.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -22,12 +24,16 @@ import linkcheck.ftests
class TestFtp (linkcheck.ftests.StandardTest):
"""test ftp: link checking"""
"""
Test ftp: link checking.
"""
needed_resources = ['network']
def test_ftp (self):
"""test ftp link"""
"""
Test ftp link.
"""
# ftp two slashes
url = u"ftp://ftp.debian.org/"
resultlines = [
@ -39,7 +45,9 @@ class TestFtp (linkcheck.ftests.StandardTest):
self.direct(url, resultlines)
def test_ftp_slashes (self):
"""test ftp links with missing slashes"""
"""
Test ftp links with missing slashes.
"""
# ftp one slash
url = u"ftp:/ftp.debian.org/"
nurl = self.norm(url)
@ -75,7 +83,9 @@ class TestFtp (linkcheck.ftests.StandardTest):
self.direct(url, resultlines)
def test_ftp_many_slashes (self):
"""test ftp links with too many slashes"""
"""
Test ftp links with too many slashes.
"""
# ftp two dir slashes
url = u"ftp://ftp.debian.org//debian/"
nurl = self.norm(url)
@ -110,7 +120,9 @@ class TestFtp (linkcheck.ftests.StandardTest):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestFtp))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test http checking"""
"""
Test http checking.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -23,7 +25,9 @@ import linkcheck.ftests.httptest
class TestHttp (linkcheck.ftests.httptest.HttpServerTest):
"""test http:// link checking"""
"""
Test http:// link checking.
"""
def test_html (self):
self.start_server(handler=RedirectHttpRequestHandler)
@ -49,10 +53,14 @@ class TestHttp (linkcheck.ftests.httptest.HttpServerTest):
class RedirectHttpRequestHandler (linkcheck.ftests.httptest.NoQueryHttpRequestHandler):
"""handler redirecting certain requests"""
"""
Handler redirecting certain requests.
"""
def redirect (self):
"""redirect request"""
"""
Redirect request.
"""
path = self.path.replace("redirect", "newurl")
self.send_response(302)
self.send_header("Location", path)
@ -60,7 +68,9 @@ class RedirectHttpRequestHandler (linkcheck.ftests.httptest.NoQueryHttpRequestHa
def do_GET (self):
"""removes query part of GET request"""
"""
Removes query part of GET request.
"""
if "redirect" in self.path:
self.redirect()
else:
@ -74,7 +84,9 @@ class RedirectHttpRequestHandler (linkcheck.ftests.httptest.NoQueryHttpRequestHa
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestHttp))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test news checking"""
"""
Test news checking.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -21,12 +23,16 @@ import unittest
import linkcheck.ftests
class TestHttps (linkcheck.ftests.StandardTest):
"""test https: link checking"""
"""
Test https: link checking.
"""
needed_resources = ['network']
def test_https (self):
"""test some https links"""
"""
Test some https links.
"""
url = u"https://sourceforge.net/"
resultlines = [
u"url %s" % url,
@ -38,7 +44,9 @@ class TestHttps (linkcheck.ftests.StandardTest):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestHttps))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test mail checking"""
"""
Test mail checking.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -21,12 +23,16 @@ import unittest
import linkcheck.ftests
class TestMail (linkcheck.ftests.StandardTest):
"""test mailto: link checking"""
"""
Test mailto: link checking.
"""
needed_resources = ['network']
def test_good_mail (self):
"""test some good mailto addrs"""
"""
Test some good mailto addrs.
"""
url = self.norm(u"mailto:Dude <calvin@users.sf.net> , "\
"Killer <calvin@users.sourceforge.net>?subject=bla")
resultlines = [
@ -99,7 +105,9 @@ class TestMail (linkcheck.ftests.StandardTest):
self.direct(url, resultlines)
def test_warn_mail (self):
"""test some mailto addrs with warnings"""
"""
Test some mailto addrs with warnings.
"""
# contains non-quoted characters
url = u"mailto:calvin@users.sf.net?subject=äöü"
qurl = self.norm(url)
@ -134,7 +142,9 @@ class TestMail (linkcheck.ftests.StandardTest):
self.direct(url, resultlines)
def test_bad_mail (self):
"""test some mailto addrs with bad syntax"""
"""
Test some mailto addrs with bad syntax.
"""
# ? extension forbidden in <> construct
url = self.norm(u"mailto:Bastian Kleineidam "\
"<calvin@users.sf.net?foo=bar>")
@ -148,7 +158,9 @@ class TestMail (linkcheck.ftests.StandardTest):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestMail))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test news checking"""
"""
Test news checking.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -23,7 +25,9 @@ import linkcheck.url
class TestNews (linkcheck.ftests.StandardTest):
"""test nntp: and news: link checking"""
"""
Test nntp: and news: link checking.
"""
needed_resources = ['network']
@ -32,7 +36,9 @@ class TestNews (linkcheck.ftests.StandardTest):
self.direct(url, resultlines, fields=fields)
def test_news (self):
"""test news: link"""
"""
Test news: link.
"""
# news testing
url = u"news:comp.os.linux.misc"
resultlines = [
@ -55,7 +61,9 @@ class TestNews (linkcheck.ftests.StandardTest):
self.newstest(url, resultlines)
def test_snews (self):
"""test snews: link"""
"""
Test snews: link.
"""
url = u"snews:de.comp.os.unix.linux.misc"
nurl = self.norm(url)
resultlines = [
@ -83,7 +91,9 @@ class TestNews (linkcheck.ftests.StandardTest):
self.newstest(url, resultlines)
def test_nntp (self):
"""nttp scheme with host"""
"""
Nttp scheme with host.
"""
url = u"nntp://news.yaako.com/comp.lang.python"
resultlines = [
u"url %s" % url,
@ -94,7 +104,9 @@ class TestNews (linkcheck.ftests.StandardTest):
self.newstest(url, resultlines)
def test_article_span (self):
"""article span"""
"""
Article span.
"""
url = u"nntp://news.yaako.com/comp.lang.python/1-5"
resultlines = [
u"url %s" % url,
@ -114,7 +126,9 @@ class TestNews (linkcheck.ftests.StandardTest):
self.newstest(url, resultlines)
def test_host_no_group (self):
"""host but no group"""
"""
Host but no group.
"""
url = u"nntp://news.yaako.com/"
resultlines = [
u"url %s" % url,
@ -127,7 +141,9 @@ class TestNews (linkcheck.ftests.StandardTest):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestNews))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test HTML robots.txt parsing"""
"""
Test HTML robots.txt parsing.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -23,15 +25,21 @@ import linkcheck.ftests
class TestRobotsTxt (linkcheck.ftests.StandardTest):
"""test robots.txt directive parsing in HTML files"""
"""
Test robots.txt directive parsing in HTML files.
"""
def test_norobot (self):
"""test links of norobot.html"""
"""
Test links of norobot.html.
"""
self.file_test("norobots.html")
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestRobotsTxt))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test telnet checking"""
"""
Test telnet checking.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -22,7 +24,9 @@ import linkcheck.ftests
class TestTelnet (linkcheck.ftests.StandardTest):
"""test telnet: link checking"""
"""
Test telnet: link checking.
"""
def test_telnet (self):
url = u"telnet:"
@ -62,7 +66,9 @@ class TestTelnet (linkcheck.ftests.StandardTest):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestTelnet))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""Output logging support for different formats"""
"""
Output logging support for different formats.
"""
# Copyright (C) 2000-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -42,10 +44,14 @@ Fields = dict(
del _
class Logger (object):
"""basic logger class enabling logging of checked urls"""
"""
Basic logger class enabling logging of checked urls.
"""
def __init__ (self, **args):
"""initialize a logger, looking for field restrictions in kwargs"""
"""
Initialize a logger, looking for field restrictions in kwargs.
"""
# what log fields should be in output
self.logfields = None # log all fields
if args.has_key('fields'):
@ -62,7 +68,9 @@ class Logger (object):
self.output_encoding = args.get("encoding", "iso-8859-1")
def init_fileoutput (self, args):
"""initialize self.fd file descriptor from args"""
"""
Initialize self.fd file descriptor from args.
"""
if args.get('fileoutput'):
fname = args['filename']
path = os.path.dirname(fname)
@ -78,29 +86,39 @@ class Logger (object):
self.close_fd = False
def encode (self, s):
"""Encode string with configured output encoding. Encoding
errors are ignored.
"""
Encode string with configured output encoding. Encoding
errors are ignored.
@return encoded string
@param s: string to encode
@type s: c{unicode}
@return: encoded string
@rtype: c{string}
"""
if not isinstance(s, unicode):
raise ValueError("tried to encode non-unicode string %r" % s)
return s.encode(self.output_encoding, "ignore")
def check_date (self):
"""check for special dates"""
"""
Check for special dates.
"""
now = datetime.date.today()
if now.day == 7 and now.month == 1:
msg = _("Happy birthday for LinkChecker, I'm %d years old today!")
self.comment(msg % (now.year - 2000))
def comment (self, s, **args):
"""Print a comment and a newline. This method just prints
the given string."""
"""
Print a comment and a newline. This method just prints
the given string.
"""
self.writeln(s=s, **args)
def wrap (self, lines, width):
"""Return wrapped version of given lines."""
"""
Return wrapped version of given lines.
"""
sep = os.linesep+os.linesep
text = sep.join(lines)
return linkcheck.strformat.wrap(text, width,
@ -108,33 +126,45 @@ class Logger (object):
initial_indent=" "*self.max_indent).lstrip()
def write (self, s, **args):
"""Write string to output descriptor."""
"""
Write string to output descriptor.
"""
if self.fd is None:
raise ValueError("write to non-file")
self.fd.write(self.encode(s), **args)
def writeln (self, s=u"", **args):
"""Write string to output descriptor plus a newline."""
"""
Write string to output descriptor plus a newline.
"""
self.write(s)
self.write(unicode(os.linesep), **args)
def has_field (self, name):
"""See if given field name will be logged."""
"""
See if given field name will be logged.
"""
if self.logfields is None:
# log all fields
return True
return name in self.logfields
def field (self, name):
"""return translated field name"""
"""
Return translated field name.
"""
return _(Fields[name])
def spaces (self, name):
"""return indent of spaces for given field name"""
"""
Return indent of spaces for given field name.
"""
return self.logspaces[name]
def start_output (self):
"""start log output"""
"""
Start log output.
"""
# map with spaces between field name and value
if self.logfields is None:
fields = Fields.keys()
@ -148,25 +178,34 @@ class Logger (object):
self.logspaces[key] = u" " * numspaces
def new_url (self, url_data):
"""log a new url with this logger"""
"""
Log a new url with this logger.
"""
raise NotImplementedError, "abstract function"
def end_output (self, linknumber=-1):
"""end of output, used for cleanup (eg output buffer flushing)"""
"""
End of output, used for cleanup (eg output buffer flushing).
"""
raise NotImplementedError, "abstract function"
def __str__ (self):
"""return class name"""
"""
Return class name.
"""
return self.__class__.__name__
def __repr__ (self):
"""return class name"""
"""
Return class name.
"""
return repr(self.__class__.__name__)
def flush (self):
"""If the logger has internal buffers, flush them.
Ignore flush I/O errors since we are not responsible for proper
flushing of log output streams.
"""
If the logger has internal buffers, flush them.
Ignore flush I/O errors since we are not responsible for proper
flushing of log output streams.
"""
if hasattr(self, "fd"):
try:

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""a blacklist logger"""
"""
A blacklist logger.
"""
# Copyright (C) 2000-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -24,13 +26,16 @@ import linkcheck.logger
class BlacklistLogger (linkcheck.logger.Logger):
"""Updates a blacklist of wrong links. If a link on the blacklist
"""
Updates a blacklist of wrong links. If a link on the blacklist
is working (again), it is removed from the list. So after n days
we have only links on the list which failed for n days.
"""
def __init__ (self, **args):
"""intialize with old blacklist data (if found, else not)"""
"""
Intialize with old blacklist data (if found, else not).
"""
super(BlacklistLogger, self).__init__(**args)
self.blacklist = {}
if args.get('fileoutput'):
@ -46,11 +51,15 @@ class BlacklistLogger (linkcheck.logger.Logger):
self.fd = sys.stdout
def comment (self, s, **args):
"""Print nothing."""
"""
Print nothing.
"""
pass
def new_url (self, url_data):
"""put invalid url in blacklist, delete valid url from blacklist"""
"""
Put invalid url in blacklist, delete valid url from blacklist.
"""
if not url_data.cached:
key = url_data.getCacheKey()
if key in self.blacklist:
@ -63,11 +72,15 @@ class BlacklistLogger (linkcheck.logger.Logger):
self.blacklist[key] = 1
def end_output (self, linknumber=-1):
"""write blacklist file"""
"""
Write blacklist file.
"""
self.write_blacklist()
def read_blacklist (self, fd):
"""read a previously stored blacklist from file fd"""
"""
Read a previously stored blacklist from file fd.
"""
for line in fd:
line = line.rstrip()
if line.startswith('#') or not line:
@ -77,7 +90,9 @@ class BlacklistLogger (linkcheck.logger.Logger):
fd.close()
def write_blacklist (self):
"""write the blacklist"""
"""
Write the blacklist.
"""
oldmask = os.umask(0077)
for key, value in self.blacklist.items():
self.fd.write("%d %s" % (value, key))

View file

@ -25,22 +25,30 @@ import linkcheck.configuration
class CSVLogger (linkcheck.logger.Logger):
"""CSV output, consisting of one line per entry. Entries are
separated by a semicolon.
"""
CSV output, consisting of one line per entry. Entries are
separated by a semicolon.
"""
def __init__ (self, **args):
"""store default separator and (os dependent) line terminator"""
"""
Store default separator and (os dependent) line terminator.
"""
super(CSVLogger, self).__init__(**args)
self.init_fileoutput(args)
self.separator = args['separator']
def comment (self, s, **args):
"""Print CSV comment."""
"""
Print CSV comment.
"""
self.write(u"# ")
self.writeln(s=s, **args)
def start_output (self):
"""print checking start info as csv comment"""
"""
Print checking start info as csv comment.
"""
super(CSVLogger, self).start_output()
if self.fd is None:
return
@ -81,7 +89,9 @@ class CSVLogger (linkcheck.logger.Logger):
self.writer.writerow(row)
def new_url (self, url_data):
"""print csv formatted url check info"""
"""
Print csv formatted url check info.
"""
if self.fd is None:
return
row = []
@ -103,7 +113,9 @@ class CSVLogger (linkcheck.logger.Logger):
self.flush()
def end_output (self, linknumber=-1):
"""print end of checking info as csv comment"""
"""
Print end of checking info as csv comment.
"""
if self.fd is None:
return
self.stoptime = time.time()

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""a gml logger"""
"""
A gml logger.
"""
# Copyright (C) 2000-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -23,19 +25,24 @@ import linkcheck.configuration
class GMLLogger (linkcheck.logger.Logger):
"""GML means Graph Modeling Language. Use a GML tool to see
"""
GML means Graph Modeling Language. Use a GML tool to see
your sitemap graph.
"""
def __init__ (self, **args):
"""initialize graph node list and internal id counter"""
"""
Initialize graph node list and internal id counter.
"""
super(GMLLogger, self).__init__(**args)
self.init_fileoutput(args)
self.nodes = {}
self.nodeid = 0
def start_output (self):
"""print start of checking info as gml comment"""
"""
Print start of checking info as gml comment.
"""
super(GMLLogger, self).start_output()
if self.fd is None:
return
@ -55,12 +62,16 @@ class GMLLogger (linkcheck.logger.Logger):
self.flush()
def comment (self, s, **args):
"""Print GML comment."""
"""
Print GML comment.
"""
self.write(u"# ")
self.writeln(s=s, **args)
def new_url (self, url_data):
"""write one node and all possible edges"""
"""
Write one node and all possible edges.
"""
if self.fd is None:
return
node = url_data
@ -84,8 +95,9 @@ class GMLLogger (linkcheck.logger.Logger):
self.write_edges()
def write_edges (self):
"""write all edges we can find in the graph in a brute-force
manner. Better would be a mapping of parent urls.
"""
Write all edges we can find in the graph in a brute-force
manner. Better would be a mapping of parent urls.
"""
for node in self.nodes.values():
if self.nodes.has_key(node.parent_url):
@ -101,7 +113,9 @@ class GMLLogger (linkcheck.logger.Logger):
self.flush()
def end_output (self, linknumber=-1):
"""print end of checking info as gml comment"""
"""
Print end of checking info as gml comment.
"""
if self.fd is None:
return
self.writeln(u"]")

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""a html logger"""
"""
A HTML logger.
"""
# Copyright (C) 2000-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -52,10 +54,14 @@ HTML_HEADER = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"""
class HtmlLogger (linkcheck.logger.Logger):
"""Logger with HTML output"""
"""
Logger with HTML output.
"""
def __init__ (self, **args):
"""initialize default HTML color values"""
"""
Initialize default HTML color values.
"""
super(HtmlLogger, self).__init__(**args)
self.init_fileoutput(args)
self.colorbackground = args['colorbackground']
@ -67,17 +73,23 @@ class HtmlLogger (linkcheck.logger.Logger):
self.colorok = args['colorok']
def field (self, name):
"""return non-space-breakable field name"""
"""
Return non-space-breakable field name.
"""
return super(HtmlLogger, self).field(name).replace(" ", "&nbsp;")
def comment (self, s, **args):
"""Print HTML comment."""
"""
Print HTML comment.
"""
self.write(u"<!-- ")
self.write(s, **args)
self.write(u" -->")
def start_output (self):
"""print start of checking info"""
"""
Print start of checking info.
"""
super(HtmlLogger, self).start_output()
if self.fd is None:
return
@ -96,7 +108,9 @@ class HtmlLogger (linkcheck.logger.Logger):
self.flush()
def new_url (self, url_data):
"""print url checking info as HTML"""
"""
Print url checking info as HTML.
"""
if self.fd is None:
return
self.write_table_start()
@ -126,7 +140,9 @@ class HtmlLogger (linkcheck.logger.Logger):
self.flush()
def write_table_start (self):
"""start html table"""
"""
Start html table.
"""
self.writeln(u"<br clear=\"all\"><br>")
self.writeln(u"<table align=\"left\" border=\"0\" cellspacing=\"0\""+
u" cellpadding=\"1\"")
@ -140,11 +156,15 @@ class HtmlLogger (linkcheck.logger.Logger):
self.colorbackground+u"\">")
def write_table_end (self):
"""end html table"""
"""
End html table.
"""
self.write(u"</table></td></tr></table><br clear=\"all\">")
def write_url (self, url_data):
"""write url_data.base_url"""
"""
Write url_data.base_url.
"""
self.writeln(u"<tr>")
self.writeln(u"<td bgcolor=\""+self.colorurl+u"\">"+
self.field("url")+u"</td>")
@ -155,12 +175,16 @@ class HtmlLogger (linkcheck.logger.Logger):
self.writeln(u"</td></tr>")
def write_name (self, url_data):
"""write url_data.name"""
"""
Write url_data.name.
"""
self.writeln(u"<tr><td>"+self.field("name")+u"</td><td>"+
cgi.escape(repr(url_data.name)[1:])+u"</td></tr>")
def write_parent (self, url_data):
"""write url_data.parent_url"""
"""
Write url_data.parent_url.
"""
self.write(u"<tr><td>"+self.field("parenturl")+
u'</td><td><a target="top" href="'+
url_data.parent_url+u'">'+
@ -177,42 +201,56 @@ class HtmlLogger (linkcheck.logger.Logger):
self.writeln(u"</td></tr>")
def write_base (self, url_data):
"""write url_data.base_ref"""
"""
Write url_data.base_ref.
"""
self.writeln(u"<tr><td>"+self.field("base")+u"</td><td>"+
cgi.escape(url_data.base_ref)+u"</td></tr>")
def write_real (self, url_data):
"""write url_data.url"""
"""
Write url_data.url.
"""
self.writeln("<tr><td>"+self.field("realurl")+u"</td><td>"+
u'<a target="top" href="'+url_data.url+
u'">'+cgi.escape(url_data.url)+u"</a></td></tr>")
def write_dltime (self, url_data):
"""write url_data.dltime"""
"""
Write url_data.dltime.
"""
self.writeln(u"<tr><td>"+self.field("dltime")+u"</td><td>"+
(_("%.3f seconds") % url_data.dltime)+
u"</td></tr>")
def write_dlsize (self, url_data):
"""write url_data.dlsize"""
"""
Write url_data.dlsize.
"""
self.writeln(u"<tr><td>"+self.field("dlsize")+u"</td><td>"+
linkcheck.strformat.strsize(url_data.dlsize)+
u"</td></tr>")
def write_checktime (self, url_data):
"""write url_data.checktime"""
"""
Write url_data.checktime.
"""
self.writeln(u"<tr><td>"+self.field("checktime")+u"</td><td>"+
(_("%.3f seconds") % url_data.checktime)+u"</td></tr>")
def write_info (self, url_data):
"""write url_data.info"""
"""
Write url_data.info.
"""
text = os.linesep.join(url_data.info)
self.writeln(u"<tr><td valign=\"top\">"+self.field("info")+
u"</td><td>"+cgi.escape(text).replace(os.linesep, "<br>")+
u"</td></tr>")
def write_warning (self, url_data):
"""write url_data.warning"""
"""
Write url_data.warning.
"""
sep = u"<br>"+os.linesep
text = sep.join([cgi.escape(x) for x in url_data.warning])
self.writeln(u"<tr><td bgcolor=\""+self.colorwarning+u"\" "+
@ -221,7 +259,9 @@ class HtmlLogger (linkcheck.logger.Logger):
text+u"</td></tr>")
def write_result (self, url_data):
"""write url_data.result"""
"""
Write url_data.result.
"""
if url_data.valid:
self.write(u"<tr><td bgcolor=\""+self.colorok+u"\">"+
self.field("result")+u"</td><td bgcolor=\""+self.colorok+u"\">")
@ -236,7 +276,9 @@ class HtmlLogger (linkcheck.logger.Logger):
self.writeln(u"</td></tr>")
def end_output (self, linknumber=-1):
"""print end of checking info as HTML"""
"""
Print end of checking info as HTML.
"""
if self.fd is None:
return
if self.has_field("outro"):

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""an dummy logger"""
"""
A dummy logger.
"""
# Copyright (C) 2000-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -20,20 +22,30 @@ import linkcheck.logger
class NoneLogger (linkcheck.logger.Logger):
"""Dummy logger printing nothing."""
"""
Dummy logger printing nothing.
"""
def comment (self, s, **args):
"""Do nothing."""
"""
Do nothing.
"""
pass
def start_output (self):
"""do nothing"""
"""
Do nothing.
"""
pass
def new_url (self, url_data):
"""do nothing"""
"""
Do nothing.
"""
pass
def end_output (self, linknumber=-1):
"""do nothing"""
"""
Do nothing.
"""
pass

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""an sql logger"""
"""
A SQL logger.
"""
# Copyright (C) 2000-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -24,35 +26,53 @@ import linkcheck.logger
def sqlify (s):
"""escape special SQL chars and strings"""
"""
Escape special SQL chars and strings.
"""
if not s:
return "NULL"
return "'%s'" % s.replace("'", "''")
def intify (s):
if not s:
return 0
return 1
"""
Coerce a truth value to 0/1.
@param s: an object (usually a string)
@type s: c{object}
@return: 1 if object truth value is True, else 0
@rtype: c{number}
"""
if s:
return 1
return 0
class SQLLogger (linkcheck.logger.Logger):
"""SQL output for PostgreSQL, not tested"""
"""
SQL output, should work with any SQL database (not tested).
"""
def __init__ (self, **args):
"""initialize database access data"""
"""
Initialize database access data.
"""
super(SQLLogger, self).__init__(**args)
self.init_fileoutput(args)
self.dbname = args['dbname']
self.separator = args['separator']
def comment (self, s, **args):
"""Print SQL comment."""
"""
Print SQL comment.
"""
self.write(u"-- ")
self.writeln(s=s, **args)
def start_output (self):
"""print start of checking info as sql comment"""
"""
Print start of checking info as sql comment.
"""
linkcheck.logger.Logger.start_output(self)
if self.fd is None:
return
@ -70,7 +90,9 @@ class SQLLogger (linkcheck.logger.Logger):
self.flush()
def new_url (self, url_data):
"""store url check info into the database"""
"""
Store url check info into the database.
"""
if self.fd is None:
return
self.writeln(u"insert into %(table)s(urlname,recursionlevel,"
@ -115,7 +137,9 @@ class SQLLogger (linkcheck.logger.Logger):
self.flush()
def end_output (self, linknumber=-1):
"""print end of checking info as sql comment"""
"""
Print end of checking info as sql comment.
"""
if self.fd is None:
return
if self.has_field("outro"):

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""the default logger"""
"""
The default text logger.
"""
# Copyright (C) 2000-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -28,7 +30,8 @@ import linkcheck.configuration
class TextLogger (linkcheck.logger.Logger):
"""A text logger, colorizing the output if possible.
"""
A text logger, colorizing the output if possible.
Every Logger has to implement the following functions:
start_output (self)
@ -62,7 +65,9 @@ class TextLogger (linkcheck.logger.Logger):
"""
def __init__ (self, **args):
"""initialize error counter and optional file output"""
"""
Initialize error counter and optional file output.
"""
super(TextLogger, self).__init__(**args)
self.init_fileoutput(args)
self.fd = linkcheck.ansicolor.Colorizer(self.fd)
@ -80,7 +85,9 @@ class TextLogger (linkcheck.logger.Logger):
self.colorreset = args['colorreset']
def start_output (self):
"""print generic start checking info"""
"""
Print generic start checking info.
"""
super(TextLogger, self).start_output()
if self.fd is None:
return
@ -99,7 +106,9 @@ class TextLogger (linkcheck.logger.Logger):
self.flush()
def new_url (self, url_data):
"""print url checking info"""
"""
Print url checking info.
"""
if self.fd is None:
return
if self.has_field('url'):
@ -127,7 +136,9 @@ class TextLogger (linkcheck.logger.Logger):
self.flush()
def write_url (self, url_data):
"""write url_data.base_url"""
"""
Write url_data.base_url.
"""
self.writeln()
self.write(self.field('url') + self.spaces('url'))
txt = unicode(repr(url_data.base_url)[1:])
@ -136,12 +147,16 @@ class TextLogger (linkcheck.logger.Logger):
self.writeln(txt, color=self.colorurl)
def write_name (self, url_data):
"""write url_data.name"""
"""
Write url_data.name.
"""
self.write(self.field("name") + self.spaces("name"))
self.writeln(unicode(repr(url_data.name)[1:]), color=self.colorname)
def write_parent (self, url_data):
"""write url_data.parent_url"""
"""
Write url_data.parent_url.
"""
self.write(self.field('parenturl') + self.spaces("parenturl"))
txt = url_data.parent_url
txt += _(", line %d") % url_data.line
@ -149,45 +164,61 @@ class TextLogger (linkcheck.logger.Logger):
self.writeln(txt, color=self.colorparent)
def write_base (self, url_data):
"""write url_data.base_ref"""
"""
Write url_data.base_ref.
"""
self.write(self.field("base") + self.spaces("base"))
self.writeln(url_data.base_ref, color=self.colorbase)
def write_real (self, url_data):
"""write url_data.url"""
"""
Write url_data.url.
"""
self.write(self.field("realurl") + self.spaces("realurl"))
self.writeln(unicode(url_data.url), color=self.colorreal)
def write_dltime (self, url_data):
"""write url_data.dltime"""
"""
Write url_data.dltime.
"""
self.write(self.field("dltime") + self.spaces("dltime"))
self.writeln(_("%.3f seconds") % url_data.dltime,
color=self.colordltime)
def write_dlsize (self, url_data):
"""write url_data.dlsize"""
"""
Write url_data.dlsize.
"""
self.write(self.field("dlsize") + self.spaces("dlsize"))
self.writeln(linkcheck.strformat.strsize(url_data.dlsize),
color=self.colordlsize)
def write_checktime (self, url_data):
"""write url_data.checktime"""
"""
Write url_data.checktime.
"""
self.write(self.field("checktime") + self.spaces("checktime"))
self.writeln(_("%.3f seconds") % url_data.checktime,
color=self.colordltime)
def write_info (self, url_data):
"""write url_data.info"""
"""
Write url_data.info.
"""
self.write(self.field("info") + self.spaces("info"))
self.writeln(self.wrap(url_data.info, 65), color=self.colorinfo)
def write_warning (self, url_data):
"""write url_data.warning"""
"""
Write url_data.warning.
"""
self.write(self.field("warning") + self.spaces("warning"))
self.writeln(self.wrap(url_data.warning, 65), color=self.colorwarning)
def write_result (self, url_data):
"""write url_data.result"""
"""
Write url_data.result.
"""
self.write(self.field("result") + self.spaces("result"))
if url_data.valid:
color = self.colorvalid
@ -201,7 +232,9 @@ class TextLogger (linkcheck.logger.Logger):
self.writeln()
def end_output (self, linknumber=-1):
"""print end of output info, and flush all output buffers"""
"""
Print end of output info, and flush all output buffers.
"""
if self.fd is None:
return
if self.has_field('outro'):

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""an xml logger"""
"""
An xml logger.
"""
# Copyright (C) 2000-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -33,44 +35,60 @@ xmlattr_entities = {
def xmlquote (s):
"""quote characters for XML"""
"""
Quote characters for XML.
"""
return xml.sax.saxutils.escape(s)
def xmlquoteattr (s):
"""quote XML attribute, ready for inclusion with double quotes"""
"""
Quote XML attribute, ready for inclusion with double quotes.
"""
return xml.sax.saxutils.escape(s, xmlattr_entities)
def xmlunquote (s):
"""unquote characters from XML"""
"""
Unquote characters from XML.
"""
return xml.sax.saxutils.unescape(s)
def xmlunquoteattr (s):
"""unquote attributes from XML"""
"""
Unquote attributes from XML.
"""
return xml.sax.saxutils.unescape(s, xmlattr_entities)
class XMLLogger (linkcheck.logger.Logger):
"""XML output mirroring the GML structure. Easy to parse with any XML
tool."""
"""
XML output mirroring the GML structure. Easy to parse with any XML
tool.
"""
def __init__ (self, **args):
"""initialize graph node list and internal id counter"""
"""
Initialize graph node list and internal id counter.
"""
super(XMLLogger, self).__init__(**args)
self.init_fileoutput(args)
self.nodes = {}
self.nodeid = 0
def comment (self, s, **args):
"""Print HTML comment."""
"""
Print HTML comment.
"""
self.write(u"<!-- ")
self.write(s, **args)
self.writeln(u" -->")
def start_output (self):
"""print start of checking info as xml comment"""
"""
Print start of checking info as xml comment.
"""
linkcheck.logger.Logger.start_output(self)
if self.fd is None:
return
@ -91,7 +109,9 @@ class XMLLogger (linkcheck.logger.Logger):
self.flush()
def new_url (self, url_data):
"""write one node and all possible edges"""
"""
Write one node and all possible edges.
"""
if self.fd is None:
return
node = url_data
@ -118,8 +138,9 @@ class XMLLogger (linkcheck.logger.Logger):
self.write_edges()
def write_edges (self):
"""write all edges we can find in the graph in a brute-force
manner. Better would be a mapping of parent urls.
"""
Write all edges we can find in the graph in a brute-force
manner. Better would be a mapping of parent urls.
"""
for node in self.nodes.values():
if self.nodes.has_key(node.parent_url):
@ -138,8 +159,8 @@ class XMLLogger (linkcheck.logger.Logger):
self.flush()
def end_output (self, linknumber=-1):
"""Finish graph output, and print end of checking info as xml
comment.
"""
Finish graph output, and print end of checking info as xml comment.
"""
if self.fd is None:
return

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""unit tests for the linkcheck module"""
"""
Unit tests for the linkcheck module.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test cgi form routines"""
"""
Test cgi form routines.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -20,25 +22,35 @@ import unittest
import linkcheck.lc_cgi
class Store (object):
"""value storing class implementing FieldStorage interface"""
"""
Value storing class implementing FieldStorage interface.
"""
def __init__ (self, value):
"""store given value"""
"""
Store given value.
"""
self.value = value
class TestCgi (unittest.TestCase):
"""test cgi routines"""
"""
Test cgi routines.
"""
def test_form_valid_url (self):
"""check url validity"""
"""
Check url validity.
"""
form = {"url": Store("http://www.heise.de/"),
"level": Store("0"),
}
linkcheck.lc_cgi.checkform(form)
def test_form_empty_url (self):
"""check with empty url"""
"""
Check with empty url.
"""
form = {"url": Store(""),
"level": Store("0"),
}
@ -46,7 +58,9 @@ class TestCgi (unittest.TestCase):
linkcheck.lc_cgi.checkform, form)
def test_form_default_url (self):
"""check with default url"""
"""
Check with default url.
"""
form = {"url": Store("http://"),
"level": Store("0"),
}
@ -54,7 +68,9 @@ class TestCgi (unittest.TestCase):
linkcheck.lc_cgi.checkform, form)
def test_form_invalid_url (self):
"""check url (in)validity"""
"""
Check url (in)validity.
"""
form = {"url": Store("http://www.foo bar/"),
"level": Store("0"),
}
@ -62,7 +78,9 @@ class TestCgi (unittest.TestCase):
linkcheck.lc_cgi.checkform, form)
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestCgi))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test container routines"""
"""
Test container routines.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -22,14 +24,20 @@ import linkcheck.containers
class TestListDict (unittest.TestCase):
"""test list dictionary routines"""
"""
Test list dictionary routines.
"""
def setUp (self):
"""set up self.d as empty listdict"""
"""
Set up self.d as empty listdict.
"""
self.d = linkcheck.containers.ListDict()
def test_insert (self):
"""test insertion order"""
"""
Test insertion order.
"""
self.assert_(not self.d)
self.d[2] = 1
self.d[1] = 2
@ -37,7 +45,9 @@ class TestListDict (unittest.TestCase):
self.assert_(1 in self.d)
def test_delete (self):
"""test deletion order"""
"""
Test deletion order.
"""
self.assert_(not self.d)
self.d[2] = 1
self.d[1] = 2
@ -46,7 +56,9 @@ class TestListDict (unittest.TestCase):
self.assert_(1 not in self.d)
def test_update (self):
"""test update order"""
"""
Test update order.
"""
self.assert_(not self.d)
self.d[2] = 1
self.d[1] = 2
@ -54,7 +66,9 @@ class TestListDict (unittest.TestCase):
self.assertEqual(self.d[1], 1)
def test_sorting (self):
"""test sorting"""
"""
Test sorting.
"""
self.assert_(not self.d)
toinsert = random.sample(xrange(10000000), 60)
for x in toinsert:
@ -64,21 +78,29 @@ class TestListDict (unittest.TestCase):
class TestSetList (unittest.TestCase):
"""test set list routines"""
"""
Test set list routines.
"""
def setUp (self):
"""set up self.l as empty setlist"""
"""
Set up self.l as empty setlist.
"""
self.l = linkcheck.containers.SetList()
def test_append (self):
"""test append and equal elements"""
"""
Test append and equal elements.
"""
self.assert_(not self.l)
self.l.append(1)
self.l.append(1)
self.assertEqual(len(self.l), 1)
def test_append2 (self):
"""test append and equal elements 2"""
"""
Test append and equal elements 2.
"""
self.assert_(not self.l)
self.l.append(1)
self.l.append(2)
@ -86,7 +108,9 @@ class TestSetList (unittest.TestCase):
self.assertEqual(len(self.l), 2)
def test_extend (self):
"""test extend and equal elements"""
"""
Test extend and equal elements.
"""
self.assert_(not self.l)
self.l.extend([1, 2, 1])
self.assertEqual(len(self.l), 2)
@ -94,7 +118,9 @@ class TestSetList (unittest.TestCase):
self.assertEqual(self.l[1], 2)
def test_setitem (self):
"""test setting of equal elements"""
"""
Test setting of equal elements.
"""
self.assert_(not self.l)
self.l.extend([1, 2, 3])
self.l[1] = 3
@ -104,15 +130,21 @@ class TestSetList (unittest.TestCase):
class TestLRU (unittest.TestCase):
"""test routines of LRU queue"""
"""
Test routines of LRU queue.
"""
def setUp (self):
"""set up self.lru as empty LRU queue"""
"""
Set up self.lru as empty LRU queue.
"""
self.count = 4
self.lru = linkcheck.containers.LRU(self.count)
def test_len (self):
"""test LRU length correctness"""
"""
Test LRU length correctness.
"""
self.assertEqual(len(self.lru), 0)
for i in range(self.count):
self.lru[str(i)] = str(i)
@ -122,7 +154,9 @@ class TestLRU (unittest.TestCase):
self.assertEqual(len(self.lru), self.count)
def test_overflow (self):
"""test LRU capacity overflow"""
"""
Test LRU capacity overflow.
"""
for i in range(self.count):
self.lru[str(i)] = str(i)
# overflow (inserting (self.count+1)th element
@ -132,7 +166,9 @@ class TestLRU (unittest.TestCase):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestListDict))
suite.addTest(unittest.makeSuite(TestSetList))

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test filename routines"""
"""
Test filename routines.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -22,7 +24,9 @@ from linkcheck.checker.fileurl import get_nt_filename
class TestFilenames (unittest.TestCase):
"""test filename routines"""
"""
Test filename routines.
"""
def test_nt_filename (self):
path = os.getcwd()
@ -35,7 +39,9 @@ class TestFilenames (unittest.TestCase):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestFilenames))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test linkname routines"""
"""
Test linkname routines.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -20,23 +22,33 @@ import unittest
import linkcheck.linkname
class TestLinkname (unittest.TestCase):
"""test href and image name parsing"""
"""
Test href and image name parsing.
"""
def image_name_test (self, txt, expected):
"""helper function calling linkname.image_name()"""
"""
Helper function calling linkname.image_name().
"""
self.assertEqual(linkcheck.linkname.image_name(txt), expected)
def href_name_test (self, txt, expected):
"""helper function calling linkname.href_name()"""
"""
Helper function calling linkname.href_name().
"""
self.assertEqual(linkcheck.linkname.href_name(txt), expected)
def test_image_name (self):
"""test image name parsing"""
"""
Test image name parsing.
"""
self.image_name_test("<img src='' alt=''></a>", '')
self.image_name_test("<img src alt=abc></a>", 'abc')
def test_href_name (self):
"""test href name parsing"""
"""
Test href name parsing.
"""
self.href_name_test("<b>guru guru</a>", 'guru guru')
self.href_name_test("a\njo</a>", "a\njo")
self.href_name_test("test<</a>", "test<")
@ -51,7 +63,9 @@ class TestLinkname (unittest.TestCase):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLinkname))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test html parsing"""
"""
Test html parsing.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -133,15 +135,21 @@ flushtests = [
class TestParser (unittest.TestCase):
"""test html parser"""
"""
Test html parser.
"""
def setUp (self):
"""initialize two internal html parser to be used for testing"""
"""
Initialize two internal html parsers to be used for testing.
"""
self.htmlparser = linkcheck.HtmlParser.htmlsax.parser()
self.htmlparser2 = linkcheck.HtmlParser.htmlsax.parser()
def test_parse (self):
"""parse all test patterns in one go"""
"""
Parse all test patterns in one go.
"""
for _in, _out in parsetests:
out = StringIO.StringIO()
self.htmlparser.handler = \
@ -153,7 +161,9 @@ class TestParser (unittest.TestCase):
self.htmlparser.reset()
def test_feed (self):
"""parse all test patterns sequentially"""
"""
Parse all test patterns sequentially.
"""
for _in, _out in parsetests:
out = StringIO.StringIO()
self.htmlparser.handler = \
@ -166,7 +176,9 @@ class TestParser (unittest.TestCase):
self.htmlparser.reset()
def test_interwoven (self):
"""parse all test patterns on two parsers interwoven"""
"""
Parse all test patterns on two parsers interwoven.
"""
for _in, _out in parsetests:
out = StringIO.StringIO()
out2 = StringIO.StringIO()
@ -186,7 +198,9 @@ class TestParser (unittest.TestCase):
self.htmlparser.reset()
def test_flush (self):
"""test parser flushing"""
"""
Test parser flushing.
"""
for _in, _out in flushtests:
out = StringIO.StringIO()
self.htmlparser.handler = \
@ -198,14 +212,18 @@ class TestParser (unittest.TestCase):
self.htmlparser.reset()
def test_entities (self):
"""test entity resolving"""
"""
Test entity resolving.
"""
for c in "abcdefghijklmnopqrstuvwxyz":
self.assertEqual(
linkcheck.HtmlParser.resolve_entities("&#%d;" % ord(c)), c)
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestParser))
return suite

View file

@ -21,18 +21,24 @@ import linkcheck.robotparser2
class TestRobotParser (unittest.TestCase):
"""test robots.txt parser (needs internet access)"""
"""
Test robots.txt parser (needs internet access).
"""
needed_resources = ['network']
def setUp (self):
"""initialize self.rp as a robots.txt parser"""
"""
Initialize self.rp as a robots.txt parser.
"""
if hasattr(self, "needed_resources"):
self.check_resources(self.needed_resources)
self.rp = linkcheck.robotparser2.RobotFileParser()
def check (self, a, b):
"""helper function comparing two results a and b"""
"""
Helper function comparing two results a and b.
"""
if not b:
ac = "access denied"
else:
@ -41,7 +47,9 @@ class TestRobotParser (unittest.TestCase):
self.fail("%s != %s (%s)" % (a, b, ac))
def test_existing_robots (self):
"""test parsing and access of an existing robots.txt file"""
"""
Test parsing and access of an existing robots.txt file.
"""
# robots.txt that exists, gotten to by redirection
self.rp.set_url('http://www.musi-cal.com/robots.txt')
self.rp.read()
@ -78,7 +86,9 @@ class TestRobotParser (unittest.TestCase):
'http://www.musi-cal.com/'), True)
def test_nonexisting_robots (self):
"""test access of a non-existing robots.txt file"""
"""
Test access of a non-existing robots.txt file.
"""
# robots.txt that does not exist
self.rp.set_url('http://www.lycos.com/robots.txt')
self.rp.read()
@ -87,7 +97,9 @@ class TestRobotParser (unittest.TestCase):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestRobotParser))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test string formatting operations"""
"""
Test string formatting operations.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -23,10 +25,14 @@ import linkcheck.strformat
class TestStrFormat (unittest.TestCase):
"""test string formatting routines"""
"""
Test string formatting routines.
"""
def test_unquote (self):
"""test quote stripping"""
"""
Test quote stripping.
"""
self.assertEquals(linkcheck.strformat.unquote(""), "")
self.assertEquals(linkcheck.strformat.unquote(None), None)
self.assertEquals(linkcheck.strformat.unquote("'"), "'")
@ -43,7 +49,9 @@ class TestStrFormat (unittest.TestCase):
self.assertEquals(linkcheck.strformat.unquote("\"a'"), "a")
def test_wrap (self):
"""test line wrapping"""
"""
Test line wrapping.
"""
s = "11%(sep)s22%(sep)s33%(sep)s44%(sep)s55" % {'sep': os.linesep}
# testing width <= 0
self.assertEquals(linkcheck.strformat.wrap(s, -1), s)
@ -58,14 +66,18 @@ class TestStrFormat (unittest.TestCase):
self.assertEquals(linkcheck.strformat.wrap(s, 4+l), s2)
def test_remove_markup (self):
"""test markup removing"""
"""
Test markup removing.
"""
self.assertEquals(linkcheck.strformat.remove_markup("<a>"), "")
self.assertEquals(linkcheck.strformat.remove_markup("<>"), "")
self.assertEquals(linkcheck.strformat.remove_markup("<<>"), "")
self.assertEquals(linkcheck.strformat.remove_markup("a < b"), "a < b")
def test_strsize (self):
"""test byte size strings"""
"""
Test byte size strings.
"""
self.assertRaises(ValueError, linkcheck.strformat.strsize, -1)
self.assertEquals(linkcheck.strformat.strsize(0), "0 Bytes")
self.assertEquals(linkcheck.strformat.strsize(1), "1 Byte")
@ -75,7 +87,9 @@ class TestStrFormat (unittest.TestCase):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestStrFormat))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test url routines"""
"""
Test url routines.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -39,17 +41,23 @@ def url_norm (url):
class TestUrl (unittest.TestCase):
"""test url norming and quoting"""
"""
Test url norming and quoting.
"""
def test_pathattack (self):
"""windows winamp path attack prevention"""
"""
Windows winamp path attack prevention.
"""
url = "http://server/..%5c..%5c..%5c..%5c..%5c..%5c..%5c.."\
"%5ccskin.zip"
nurl = "http://server/cskin.zip"
self.assertEquals(linkcheck.url.url_quote(url_norm(url)), nurl)
def test_norm_quote (self):
"""test url norm quoting"""
"""
Test url norm quoting.
"""
url = "http://groups.google.com/groups?hl=en&lr&ie=UTF-8&"\
"threadm=3845B54D.E546F9BD%40monmouth.com&rnum=2&"\
"prev=/groups%3Fq%3Dlogitech%2Bwingman%2Bextreme%2Bdigital"\
@ -83,7 +91,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_case_sensitivity (self):
"""test url norm case sensitivity"""
"""
Test url norm case sensitivity.
"""
# Always provide the URI scheme in lowercase characters.
url = "HTTP://example.com/"
nurl = "http://example.com/"
@ -97,7 +107,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_defaultport (self):
"""test url norm default port recognition"""
"""
Test url norm default port recognition.
"""
# For schemes that define a port, use an empty port if the default
# is desired
url = "http://example.com:80/"
@ -108,7 +120,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_host_dot (self):
"""test url norm host dot removal"""
"""
Test url norm host dot removal.
"""
url = "http://example.com./"
nurl = "http://example.com/"
self.assertEqual(url_norm(url), nurl)
@ -117,14 +131,18 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_fragment (self):
"""test url norm fragment preserving"""
"""
Test url norm fragment preserving.
"""
# Empty fragment identifiers must be preserved:
url = "http://www.w3.org/2000/01/rdf-schema#"
nurl = url
self.assertEqual(url_norm(url), nurl)
def test_norm_empty_path (self):
"""test url norm empty path handling"""
"""
Test url norm empty path handling.
"""
# For schemes that define an empty path to be equivalent to a
# path of "/", use "/".
url = "http://example.com"
@ -135,7 +153,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_path_backslashes (self):
"""test url norm backslash path handling"""
"""
Test url norm backslash path handling.
"""
# note: this is not RFC conform (see url.py for more info)
url = r"http://example.com\test.html"
nurl = "http://example.com/test.html"
@ -151,7 +171,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_path_slashes (self):
"""test url norm slashes in path handling"""
"""
Test url norm slashes in path handling.
"""
# reduce duplicate slashes
url = "http://example.com//a/test.html"
nurl = "http://example.com/a/test.html"
@ -161,7 +183,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_path_dots (self):
"""test url norm dots in path handling"""
"""
Test url norm dots in path handling.
"""
# Prevent dot-segments appearing in non-relative URI paths.
url = "http://example.com/a/./b"
nurl = "http://example.com/a/b"
@ -170,7 +194,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_path_relative_dots (self):
"""test url norm relative path handling with dots"""
"""
Test url norm relative path handling with dots.
"""
# normalize redundant path segments
url = '/foo/bar/.'
nurl = '/foo/bar/'
@ -249,7 +275,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_path_relative_slashes (self):
"""test url norm relative path handling with slashes"""
"""
Test url norm relative path handling with slashes.
"""
url = '/foo//'
nurl = '/foo/'
self.assertEqual(url_norm(url), nurl)
@ -258,7 +286,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_mail_url (self):
"""test mailto urls"""
"""
Test mailto urls.
"""
# no netloc and no path
url = 'mailto:'
nurl = url
@ -273,7 +303,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_other (self):
"""test norming of other schemes"""
"""
Test norming of other schemes.
"""
# using netloc
# no netloc and no path
url = 'news:'
@ -295,7 +327,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_norm_with_auth (self):
"""test norming of urls with authentication tokens"""
"""
Test norming of urls with authentication tokens.
"""
url = "telnet://user@www.imadoofus.org"
nurl = url
self.assertEqual(url_norm(url), nurl)
@ -307,7 +341,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(url_norm(url), nurl)
def test_fixing (self):
"""test url fix method"""
"""
Test url fix method.
"""
url = "http//www.imadoofus.org"
nurl = "http://www.imadoofus.org"
self.assertEqual(linkcheck.url.url_fix_common_typos(url), nurl)
@ -316,7 +352,9 @@ class TestUrl (unittest.TestCase):
self.assertEqual(linkcheck.url.url_fix_common_typos(url), nurl)
def test_valid (self):
"""test url validity functions"""
"""
Test url validity functions.
"""
u = "http://www.imadoofus.com"
self.assert_(linkcheck.url.is_safe_url(u), u)
u = "http://www.imadoofus.com/"
@ -333,7 +371,9 @@ class TestUrl (unittest.TestCase):
self.assert_(linkcheck.url.is_safe_js_url(u), u)
def test_needs_quoting (self):
"""test url quoting necessity"""
"""
Test url quoting necessity.
"""
url = "mailto:<calvin@debian.org>?subject=Halli Hallo"
self.assert_(linkcheck.url.url_needs_quoting(url), repr(url))
url = " http://www.imadoofus.com/"
@ -365,7 +405,9 @@ class TestUrl (unittest.TestCase):
self.assert_(not linkcheck.url.url_needs_quoting(url))
def test_idn_encoding (self):
"""test idna encoding"""
"""
Test idna encoding.
"""
url = u'www.öko.de'
encurl, is_idn = linkcheck.url.idna_encode(url)
self.assert_(is_idn)
@ -375,13 +417,17 @@ class TestUrl (unittest.TestCase):
self.assert_(not encurl)
def test_match_host (self):
"""test host matching"""
"""
Test host matching.
"""
self.assert_(not linkcheck.url.match_host("localhost", [".localhost"]))
self.assert_(linkcheck.url.match_host("a.localhost", [".localhost"]))
self.assert_(linkcheck.url.match_host("localhost", ["localhost"]))
def test_splitparam (self):
"""path parameter split test"""
"""
Path parameter split test.
"""
p = [
("", ("", "")),
("/", ("/", "")),
@ -397,7 +443,9 @@ class TestUrl (unittest.TestCase):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestUrl))
return suite

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*-
"""test url build method from url data objects"""
"""
Test url build method from url data objects.
"""
# Copyright (C) 2004-2005 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
@ -20,7 +22,9 @@ import unittest
import linkcheck.checker.httpurl
class TestUrlBuild (unittest.TestCase):
"""test url building"""
"""
Test url building.
"""
def test_http_build (self):
parent_url = "http://localhost:8001/linkcheck/ftests/data/http.html"
@ -34,7 +38,9 @@ class TestUrlBuild (unittest.TestCase):
def test_suite ():
"""build and return a TestSuite"""
"""
Build and return a TestSuite.
"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestUrlBuild))
return suite