From: <fwi...@us...> - 2011-03-12 20:13:48
|
Revision: 7220 http://jython.svn.sourceforge.net/jython/?rev=7220&view=rev Author: fwierzbicki Date: 2011-03-12 20:13:35 +0000 (Sat, 12 Mar 2011) Log Message: ----------- Tests added from Python 2.6 - these should be reviewed for deletion after we switch to the 2.6 Lib. Added Paths: ----------- trunk/jython/Lib/test/exception_hierarchy.txt trunk/jython/Lib/test/output/test_global trunk/jython/Lib/test/output/test_grammar trunk/jython/Lib/test/test_asynchat.py trunk/jython/Lib/test/test_base64.py trunk/jython/Lib/test/test_contextlib.py trunk/jython/Lib/test/test_datetime.py trunk/jython/Lib/test/test_email.py trunk/jython/Lib/test/test_email_renamed.py trunk/jython/Lib/test/test_gettext.py trunk/jython/Lib/test/test_global.py trunk/jython/Lib/test/test_threading_local.py trunk/jython/Lib/test/test_wsgiref.py Added: trunk/jython/Lib/test/exception_hierarchy.txt =================================================================== --- trunk/jython/Lib/test/exception_hierarchy.txt (rev 0) +++ trunk/jython/Lib/test/exception_hierarchy.txt 2011-03-12 20:13:35 UTC (rev 7220) @@ -0,0 +1,49 @@ +BaseException + +-- SystemExit + +-- KeyboardInterrupt + +-- GeneratorExit + +-- Exception + +-- StopIteration + +-- StandardError + | +-- ArithmeticError + | | +-- FloatingPointError + | | +-- OverflowError + | | +-- ZeroDivisionError + | +-- AssertionError + | +-- AttributeError + | +-- EnvironmentError + | | +-- IOError + | | +-- OSError + | | +-- WindowsError (Windows) + | | +-- VMSError (VMS) + | +-- EOFError + | +-- ImportError + | +-- LookupError + | | +-- IndexError + | | +-- KeyError + | +-- MemoryError + | +-- NameError + | | +-- UnboundLocalError + | +-- ReferenceError + | +-- RuntimeError + | | +-- NotImplementedError + | +-- SyntaxError + | | +-- IndentationError + | | +-- TabError + | +-- SystemError + | +-- TypeError + | +-- ValueError + | +-- UnicodeError + | +-- UnicodeDecodeError + | +-- UnicodeEncodeError + | +-- UnicodeTranslateError + +-- Warning + +-- DeprecationWarning + +-- PendingDeprecationWarning + +-- RuntimeWarning + +-- SyntaxWarning + +-- UserWarning + +-- FutureWarning + +-- ImportWarning + +-- UnicodeWarning + +-- BytesWarning Added: trunk/jython/Lib/test/output/test_global =================================================================== --- trunk/jython/Lib/test/output/test_global (rev 0) +++ trunk/jython/Lib/test/output/test_global 2011-03-12 20:13:35 UTC (rev 7220) @@ -0,0 +1 @@ +test_global Added: trunk/jython/Lib/test/output/test_grammar =================================================================== --- trunk/jython/Lib/test/output/test_grammar (rev 0) +++ trunk/jython/Lib/test/output/test_grammar 2011-03-12 20:13:35 UTC (rev 7220) @@ -0,0 +1 @@ +test_grammar Added: trunk/jython/Lib/test/test_asynchat.py =================================================================== --- trunk/jython/Lib/test/test_asynchat.py (rev 0) +++ trunk/jython/Lib/test/test_asynchat.py 2011-03-12 20:13:35 UTC (rev 7220) @@ -0,0 +1,93 @@ +# test asynchat -- requires threading + +import thread # If this fails, we can't test this module +import asyncore, asynchat, socket, threading, time +import unittest +from test import test_support + +HOST = "127.0.0.1" +PORT = 54322 + +class echo_server(threading.Thread): + + def run(self): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + global PORT + PORT = test_support.bind_port(sock, HOST) + sock.listen(1) + conn, client = sock.accept() + buffer = "" + while "\n" not in buffer: + data = conn.recv(1) + if not data: + break + buffer = buffer + data + while buffer: + n = conn.send(buffer) + buffer = buffer[n:] + conn.close() + sock.close() + +class echo_client(asynchat.async_chat): + + def __init__(self, terminator): + asynchat.async_chat.__init__(self) + self.contents = None + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.connect((HOST, PORT)) + self.set_terminator(terminator) + self.buffer = "" + + def handle_connect(self): + pass + ##print "Connected" + + def collect_incoming_data(self, data): + self.buffer = self.buffer + data + + def found_terminator(self): + #print "Received:", repr(self.buffer) + self.contents = self.buffer + self.buffer = "" + self.close() + + +class TestAsynchat(unittest.TestCase): + def setUp (self): + pass + + def tearDown (self): + pass + + def test_line_terminator(self): + s = echo_server() + s.start() + time.sleep(1) # Give server time to initialize + c = echo_client('\n') + c.push("hello ") + c.push("world\n") + asyncore.loop() + s.join() + + self.assertEqual(c.contents, 'hello world') + + def test_numeric_terminator(self): + # Try reading a fixed number of bytes + s = echo_server() + s.start() + time.sleep(1) # Give server time to initialize + c = echo_client(6L) + c.push("hello ") + c.push("world\n") + asyncore.loop() + s.join() + + self.assertEqual(c.contents, 'hello ') + + +def test_main(verbose=None): + test_support.run_unittest(TestAsynchat) + +if __name__ == "__main__": + test_main(verbose=True) Added: trunk/jython/Lib/test/test_base64.py =================================================================== --- trunk/jython/Lib/test/test_base64.py (rev 0) +++ trunk/jython/Lib/test/test_base64.py 2011-03-12 20:13:35 UTC (rev 7220) @@ -0,0 +1,190 @@ +import unittest +from test import test_support +import base64 + + + +class LegacyBase64TestCase(unittest.TestCase): + def test_encodestring(self): + eq = self.assertEqual + eq(base64.encodestring("www.python.org"), "d3d3LnB5dGhvbi5vcmc=\n") + eq(base64.encodestring("a"), "YQ==\n") + eq(base64.encodestring("ab"), "YWI=\n") + eq(base64.encodestring("abc"), "YWJj\n") + eq(base64.encodestring(""), "") + eq(base64.encodestring("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789!@#0^&*();:<>,. []{}"), + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" + "RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" + "Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n") + + def test_decodestring(self): + eq = self.assertEqual + eq(base64.decodestring("d3d3LnB5dGhvbi5vcmc=\n"), "www.python.org") + eq(base64.decodestring("YQ==\n"), "a") + eq(base64.decodestring("YWI=\n"), "ab") + eq(base64.decodestring("YWJj\n"), "abc") + eq(base64.decodestring("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" + "RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" + "Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n"), + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789!@#0^&*();:<>,. []{}") + eq(base64.decodestring(''), '') + + def test_encode(self): + eq = self.assertEqual + from cStringIO import StringIO + infp = StringIO('abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + '0123456789!@#0^&*();:<>,. []{}') + outfp = StringIO() + base64.encode(infp, outfp) + eq(outfp.getvalue(), + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE' + 'RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT' + 'Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==\n') + + def test_decode(self): + from cStringIO import StringIO + infp = StringIO('d3d3LnB5dGhvbi5vcmc=') + outfp = StringIO() + base64.decode(infp, outfp) + self.assertEqual(outfp.getvalue(), 'www.python.org') + + + +class BaseXYTestCase(unittest.TestCase): + def test_b64encode(self): + eq = self.assertEqual + # Test default alphabet + eq(base64.b64encode("www.python.org"), "d3d3LnB5dGhvbi5vcmc=") + eq(base64.b64encode('\x00'), 'AA==') + eq(base64.b64encode("a"), "YQ==") + eq(base64.b64encode("ab"), "YWI=") + eq(base64.b64encode("abc"), "YWJj") + eq(base64.b64encode(""), "") + eq(base64.b64encode("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789!@#0^&*();:<>,. []{}"), + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" + "RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT" + "Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==") + # Test with arbitrary alternative characters + eq(base64.b64encode('\xd3V\xbeo\xf7\x1d', altchars='*$'), '01a*b$cd') + # Test standard alphabet + eq(base64.standard_b64encode("www.python.org"), "d3d3LnB5dGhvbi5vcmc=") + eq(base64.standard_b64encode("a"), "YQ==") + eq(base64.standard_b64encode("ab"), "YWI=") + eq(base64.standard_b64encode("abc"), "YWJj") + eq(base64.standard_b64encode(""), "") + eq(base64.standard_b64encode("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789!@#0^&*();:<>,. []{}"), + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" + "RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT" + "Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==") + # Test with 'URL safe' alternative characters + eq(base64.urlsafe_b64encode('\xd3V\xbeo\xf7\x1d'), '01a-b_cd') + + def test_b64decode(self): + eq = self.assertEqual + eq(base64.b64decode("d3d3LnB5dGhvbi5vcmc="), "www.python.org") + eq(base64.b64decode('AA=='), '\x00') + eq(base64.b64decode("YQ=="), "a") + eq(base64.b64decode("YWI="), "ab") + eq(base64.b64decode("YWJj"), "abc") + eq(base64.b64decode("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" + "RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT" + "Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ=="), + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789!@#0^&*();:<>,. []{}") + eq(base64.b64decode(''), '') + # Test with arbitrary alternative characters + eq(base64.b64decode('01a*b$cd', altchars='*$'), '\xd3V\xbeo\xf7\x1d') + # Test standard alphabet + eq(base64.standard_b64decode("d3d3LnB5dGhvbi5vcmc="), "www.python.org") + eq(base64.standard_b64decode("YQ=="), "a") + eq(base64.standard_b64decode("YWI="), "ab") + eq(base64.standard_b64decode("YWJj"), "abc") + eq(base64.standard_b64decode(""), "") + eq(base64.standard_b64decode("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE" + "RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT" + "Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ=="), + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789!@#0^&*();:<>,. []{}") + # Test with 'URL safe' alternative characters + eq(base64.urlsafe_b64decode('01a-b_cd'), '\xd3V\xbeo\xf7\x1d') + + def test_b64decode_error(self): + self.assertRaises(TypeError, base64.b64decode, 'abc') + + def test_b32encode(self): + eq = self.assertEqual + eq(base64.b32encode(''), '') + eq(base64.b32encode('\x00'), 'AA======') + eq(base64.b32encode('a'), 'ME======') + eq(base64.b32encode('ab'), 'MFRA====') + eq(base64.b32encode('abc'), 'MFRGG===') + eq(base64.b32encode('abcd'), 'MFRGGZA=') + eq(base64.b32encode('abcde'), 'MFRGGZDF') + + def test_b32decode(self): + eq = self.assertEqual + eq(base64.b32decode(''), '') + eq(base64.b32decode('AA======'), '\x00') + eq(base64.b32decode('ME======'), 'a') + eq(base64.b32decode('MFRA===='), 'ab') + eq(base64.b32decode('MFRGG==='), 'abc') + eq(base64.b32decode('MFRGGZA='), 'abcd') + eq(base64.b32decode('MFRGGZDF'), 'abcde') + + def test_b32decode_casefold(self): + eq = self.assertEqual + eq(base64.b32decode('', True), '') + eq(base64.b32decode('ME======', True), 'a') + eq(base64.b32decode('MFRA====', True), 'ab') + eq(base64.b32decode('MFRGG===', True), 'abc') + eq(base64.b32decode('MFRGGZA=', True), 'abcd') + eq(base64.b32decode('MFRGGZDF', True), 'abcde') + # Lower cases + eq(base64.b32decode('me======', True), 'a') + eq(base64.b32decode('mfra====', True), 'ab') + eq(base64.b32decode('mfrgg===', True), 'abc') + eq(base64.b32decode('mfrggza=', True), 'abcd') + eq(base64.b32decode('mfrggzdf', True), 'abcde') + # Expected exceptions + self.assertRaises(TypeError, base64.b32decode, 'me======') + # Mapping zero and one + eq(base64.b32decode('MLO23456'), 'b\xdd\xad\xf3\xbe') + eq(base64.b32decode('M1023456', map01='L'), 'b\xdd\xad\xf3\xbe') + eq(base64.b32decode('M1023456', map01='I'), 'b\x1d\xad\xf3\xbe') + + def test_b32decode_error(self): + self.assertRaises(TypeError, base64.b32decode, 'abc') + self.assertRaises(TypeError, base64.b32decode, 'ABCDEF==') + + def test_b16encode(self): + eq = self.assertEqual + eq(base64.b16encode('\x01\x02\xab\xcd\xef'), '0102ABCDEF') + eq(base64.b16encode('\x00'), '00') + + def test_b16decode(self): + eq = self.assertEqual + eq(base64.b16decode('0102ABCDEF'), '\x01\x02\xab\xcd\xef') + eq(base64.b16decode('00'), '\x00') + # Lower case is not allowed without a flag + self.assertRaises(TypeError, base64.b16decode, '0102abcdef') + # Case fold + eq(base64.b16decode('0102abcdef', True), '\x01\x02\xab\xcd\xef') + + + +def test_main(): + test_support.run_unittest(__name__) + +if __name__ == '__main__': + test_main() Added: trunk/jython/Lib/test/test_contextlib.py =================================================================== --- trunk/jython/Lib/test/test_contextlib.py (rev 0) +++ trunk/jython/Lib/test/test_contextlib.py 2011-03-12 20:13:35 UTC (rev 7220) @@ -0,0 +1,337 @@ +"""Unit tests for contextlib.py, and other context managers.""" + +import sys +import os +import decimal +import tempfile +import unittest +import threading +from contextlib import * # Tests __all__ +from test import test_support + +class ContextManagerTestCase(unittest.TestCase): + + def test_contextmanager_plain(self): + state = [] + @contextmanager + def woohoo(): + state.append(1) + yield 42 + state.append(999) + with woohoo() as x: + self.assertEqual(state, [1]) + self.assertEqual(x, 42) + state.append(x) + self.assertEqual(state, [1, 42, 999]) + + def test_contextmanager_finally(self): + state = [] + @contextmanager + def woohoo(): + state.append(1) + try: + yield 42 + finally: + state.append(999) + try: + with woohoo() as x: + self.assertEqual(state, [1]) + self.assertEqual(x, 42) + state.append(x) + raise ZeroDivisionError() + except ZeroDivisionError: + pass + else: + self.fail("Expected ZeroDivisionError") + self.assertEqual(state, [1, 42, 999]) + + def test_contextmanager_no_reraise(self): + @contextmanager + def whee(): + yield + ctx = whee() + ctx.__enter__() + # Calling __exit__ should not result in an exception + self.failIf(ctx.__exit__(TypeError, TypeError("foo"), None)) + + def test_contextmanager_trap_yield_after_throw(self): + @contextmanager + def whoo(): + try: + yield + except: + yield + ctx = whoo() + ctx.__enter__() + self.assertRaises( + RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None + ) + + def test_contextmanager_except(self): + state = [] + @contextmanager + def woohoo(): + state.append(1) + try: + yield 42 + except ZeroDivisionError, e: + state.append(e.args[0]) + self.assertEqual(state, [1, 42, 999]) + with woohoo() as x: + self.assertEqual(state, [1]) + self.assertEqual(x, 42) + state.append(x) + raise ZeroDivisionError(999) + self.assertEqual(state, [1, 42, 999]) + + def test_contextmanager_attribs(self): + def attribs(**kw): + def decorate(func): + for k,v in kw.items(): + setattr(func,k,v) + return func + return decorate + @contextmanager + @attribs(foo='bar') + def baz(spam): + """Whee!""" + self.assertEqual(baz.__name__,'baz') + self.assertEqual(baz.foo, 'bar') + self.assertEqual(baz.__doc__, "Whee!") + +class NestedTestCase(unittest.TestCase): + + # XXX This needs more work + + def test_nested(self): + @contextmanager + def a(): + yield 1 + @contextmanager + def b(): + yield 2 + @contextmanager + def c(): + yield 3 + with nested(a(), b(), c()) as (x, y, z): + self.assertEqual(x, 1) + self.assertEqual(y, 2) + self.assertEqual(z, 3) + + def test_nested_cleanup(self): + state = [] + @contextmanager + def a(): + state.append(1) + try: + yield 2 + finally: + state.append(3) + @contextmanager + def b(): + state.append(4) + try: + yield 5 + finally: + state.append(6) + try: + with nested(a(), b()) as (x, y): + state.append(x) + state.append(y) + 1 // 0 + except ZeroDivisionError: + self.assertEqual(state, [1, 4, 2, 5, 6, 3]) + else: + self.fail("Didn't raise ZeroDivisionError") + + def test_nested_right_exception(self): + state = [] + @contextmanager + def a(): + yield 1 + class b(object): + def __enter__(self): + return 2 + def __exit__(self, *exc_info): + try: + raise Exception() + except: + pass + try: + with nested(a(), b()) as (x, y): + 1 // 0 + except ZeroDivisionError: + self.assertEqual((x, y), (1, 2)) + except Exception: + self.fail("Reraised wrong exception") + else: + self.fail("Didn't raise ZeroDivisionError") + + def test_nested_b_swallows(self): + @contextmanager + def a(): + yield + @contextmanager + def b(): + try: + yield + except: + # Swallow the exception + pass + try: + with nested(a(), b()): + 1 // 0 + except ZeroDivisionError: + self.fail("Didn't swallow ZeroDivisionError") + + def test_nested_break(self): + @contextmanager + def a(): + yield + state = 0 + while True: + state += 1 + with nested(a(), a()): + break + state += 10 + self.assertEqual(state, 1) + + def test_nested_continue(self): + @contextmanager + def a(): + yield + state = 0 + while state < 3: + state += 1 + with nested(a(), a()): + continue + state += 10 + self.assertEqual(state, 3) + + def test_nested_return(self): + @contextmanager + def a(): + try: + yield + except: + pass + def foo(): + with nested(a(), a()): + return 1 + return 10 + self.assertEqual(foo(), 1) + +class ClosingTestCase(unittest.TestCase): + + # XXX This needs more work + + def test_closing(self): + state = [] + class C: + def close(self): + state.append(1) + x = C() + self.assertEqual(state, []) + with closing(x) as y: + self.assertEqual(x, y) + self.assertEqual(state, [1]) + + def test_closing_error(self): + state = [] + class C: + def close(self): + state.append(1) + x = C() + self.assertEqual(state, []) + try: + with closing(x) as y: + self.assertEqual(x, y) + 1 // 0 + except ZeroDivisionError: + self.assertEqual(state, [1]) + else: + self.fail("Didn't raise ZeroDivisionError") + +class FileContextTestCase(unittest.TestCase): + + def testWithOpen(self): + tfn = tempfile.mktemp() + try: + f = None + with open(tfn, "w") as f: + self.failIf(f.closed) + f.write("Booh\n") + self.failUnless(f.closed) + f = None + try: + with open(tfn, "r") as f: + self.failIf(f.closed) + self.assertEqual(f.read(), "Booh\n") + 1 // 0 + except ZeroDivisionError: + self.failUnless(f.closed) + else: + self.fail("Didn't raise ZeroDivisionError") + finally: + try: + os.remove(tfn) + except os.error: + pass + +class LockContextTestCase(unittest.TestCase): + + def boilerPlate(self, lock, locked): + self.failIf(locked()) + with lock: + self.failUnless(locked()) + self.failIf(locked()) + try: + with lock: + self.failUnless(locked()) + 1 // 0 + except ZeroDivisionError: + self.failIf(locked()) + else: + self.fail("Didn't raise ZeroDivisionError") + + def testWithLock(self): + lock = threading.Lock() + self.boilerPlate(lock, lock.locked) + + def testWithRLock(self): + lock = threading.RLock() + self.boilerPlate(lock, lock._is_owned) + + def testWithCondition(self): + lock = threading.Condition() + def locked(): + return lock._is_owned() + self.boilerPlate(lock, locked) + + def testWithSemaphore(self): + lock = threading.Semaphore() + def locked(): + if lock.acquire(False): + lock.release() + return False + else: + return True + self.boilerPlate(lock, locked) + + def testWithBoundedSemaphore(self): + lock = threading.BoundedSemaphore() + def locked(): + if lock.acquire(False): + lock.release() + return False + else: + return True + self.boilerPlate(lock, locked) + +# This is needed to make the test actually run under regrtest.py! +def test_main(): + test_support.run_unittest(__name__) + + +if __name__ == "__main__": + test_main() Added: trunk/jython/Lib/test/test_datetime.py =================================================================== --- trunk/jython/Lib/test/test_datetime.py (rev 0) +++ trunk/jython/Lib/test/test_datetime.py 2011-03-12 20:13:35 UTC (rev 7220) @@ -0,0 +1,3367 @@ +"""Test date/time type. + +See http://www.zope.org/Members/fdrake/DateTimeWiki/TestCases +""" + +import sys +import pickle +import cPickle +import unittest + +from test import test_support + +from datetime import MINYEAR, MAXYEAR +from datetime import timedelta +from datetime import tzinfo +from datetime import time +from datetime import date, datetime + +pickle_choices = [(pickler, unpickler, proto) + for pickler in pickle, cPickle + for unpickler in pickle, cPickle + for proto in range(3)] +assert len(pickle_choices) == 2*2*3 + +# An arbitrary collection of objects of non-datetime types, for testing +# mixed-type comparisons. +OTHERSTUFF = (10, 10L, 34.5, "abc", {}, [], ()) + + +############################################################################# +# module tests + +class TestModule(unittest.TestCase): + + def test_constants(self): + import datetime + self.assertEqual(datetime.MINYEAR, 1) + self.assertEqual(datetime.MAXYEAR, 9999) + +############################################################################# +# tzinfo tests + +class FixedOffset(tzinfo): + def __init__(self, offset, name, dstoffset=42): + if isinstance(offset, int): + offset = timedelta(minutes=offset) + if isinstance(dstoffset, int): + dstoffset = timedelta(minutes=dstoffset) + self.__offset = offset + self.__name = name + self.__dstoffset = dstoffset + def __repr__(self): + return self.__name.lower() + def utcoffset(self, dt): + return self.__offset + def tzname(self, dt): + return self.__name + def dst(self, dt): + return self.__dstoffset + +class PicklableFixedOffset(FixedOffset): + def __init__(self, offset=None, name=None, dstoffset=None): + FixedOffset.__init__(self, offset, name, dstoffset) + +class TestTZInfo(unittest.TestCase): + + def test_non_abstractness(self): + # In order to allow subclasses to get pickled, the C implementation + # wasn't able to get away with having __init__ raise + # NotImplementedError. + useless = tzinfo() + dt = datetime.max + self.assertRaises(NotImplementedError, useless.tzname, dt) + self.assertRaises(NotImplementedError, useless.utcoffset, dt) + self.assertRaises(NotImplementedError, useless.dst, dt) + + def test_subclass_must_override(self): + class NotEnough(tzinfo): + def __init__(self, offset, name): + self.__offset = offset + self.__name = name + self.failUnless(issubclass(NotEnough, tzinfo)) + ne = NotEnough(3, "NotByALongShot") + self.failUnless(isinstance(ne, tzinfo)) + + dt = datetime.now() + self.assertRaises(NotImplementedError, ne.tzname, dt) + self.assertRaises(NotImplementedError, ne.utcoffset, dt) + self.assertRaises(NotImplementedError, ne.dst, dt) + + def test_normal(self): + fo = FixedOffset(3, "Three") + self.failUnless(isinstance(fo, tzinfo)) + for dt in datetime.now(), None: + self.assertEqual(fo.utcoffset(dt), timedelta(minutes=3)) + self.assertEqual(fo.tzname(dt), "Three") + self.assertEqual(fo.dst(dt), timedelta(minutes=42)) + + def test_pickling_base(self): + # There's no point to pickling tzinfo objects on their own (they + # carry no data), but they need to be picklable anyway else + # concrete subclasses can't be pickled. + orig = tzinfo.__new__(tzinfo) + self.failUnless(type(orig) is tzinfo) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + self.failUnless(type(derived) is tzinfo) + + def test_pickling_subclass(self): + # Make sure we can pickle/unpickle an instance of a subclass. + offset = timedelta(minutes=-300) + orig = PicklableFixedOffset(offset, 'cookie') + self.failUnless(isinstance(orig, tzinfo)) + self.failUnless(type(orig) is PicklableFixedOffset) + self.assertEqual(orig.utcoffset(None), offset) + self.assertEqual(orig.tzname(None), 'cookie') + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + self.failUnless(isinstance(derived, tzinfo)) + self.failUnless(type(derived) is PicklableFixedOffset) + self.assertEqual(derived.utcoffset(None), offset) + self.assertEqual(derived.tzname(None), 'cookie') + +############################################################################# +# Base clase for testing a particular aspect of timedelta, time, date and +# datetime comparisons. + +class HarmlessMixedComparison: + # Test that __eq__ and __ne__ don't complain for mixed-type comparisons. + + # Subclasses must define 'theclass', and theclass(1, 1, 1) must be a + # legit constructor. + + def test_harmless_mixed_comparison(self): + me = self.theclass(1, 1, 1) + + self.failIf(me == ()) + self.failUnless(me != ()) + self.failIf(() == me) + self.failUnless(() != me) + + self.failUnless(me in [1, 20L, [], me]) + self.failIf(me not in [1, 20L, [], me]) + + self.failUnless([] in [me, 1, 20L, []]) + self.failIf([] not in [me, 1, 20L, []]) + + def test_harmful_mixed_comparison(self): + me = self.theclass(1, 1, 1) + + self.assertRaises(TypeError, lambda: me < ()) + self.assertRaises(TypeError, lambda: me <= ()) + self.assertRaises(TypeError, lambda: me > ()) + self.assertRaises(TypeError, lambda: me >= ()) + + self.assertRaises(TypeError, lambda: () < me) + self.assertRaises(TypeError, lambda: () <= me) + self.assertRaises(TypeError, lambda: () > me) + self.assertRaises(TypeError, lambda: () >= me) + + self.assertRaises(TypeError, cmp, (), me) + self.assertRaises(TypeError, cmp, me, ()) + +############################################################################# +# timedelta tests + +class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase): + + theclass = timedelta + + def test_constructor(self): + eq = self.assertEqual + td = timedelta + + # Check keyword args to constructor + eq(td(), td(weeks=0, days=0, hours=0, minutes=0, seconds=0, + milliseconds=0, microseconds=0)) + eq(td(1), td(days=1)) + eq(td(0, 1), td(seconds=1)) + eq(td(0, 0, 1), td(microseconds=1)) + eq(td(weeks=1), td(days=7)) + eq(td(days=1), td(hours=24)) + eq(td(hours=1), td(minutes=60)) + eq(td(minutes=1), td(seconds=60)) + eq(td(seconds=1), td(milliseconds=1000)) + eq(td(milliseconds=1), td(microseconds=1000)) + + # Check float args to constructor + eq(td(weeks=1.0/7), td(days=1)) + eq(td(days=1.0/24), td(hours=1)) + eq(td(hours=1.0/60), td(minutes=1)) + eq(td(minutes=1.0/60), td(seconds=1)) + eq(td(seconds=0.001), td(milliseconds=1)) + eq(td(milliseconds=0.001), td(microseconds=1)) + + def test_computations(self): + eq = self.assertEqual + td = timedelta + + a = td(7) # One week + b = td(0, 60) # One minute + c = td(0, 0, 1000) # One millisecond + eq(a+b+c, td(7, 60, 1000)) + eq(a-b, td(6, 24*3600 - 60)) + eq(-a, td(-7)) + eq(+a, td(7)) + eq(-b, td(-1, 24*3600 - 60)) + eq(-c, td(-1, 24*3600 - 1, 999000)) + eq(abs(a), a) + eq(abs(-a), a) + eq(td(6, 24*3600), a) + eq(td(0, 0, 60*1000000), b) + eq(a*10, td(70)) + eq(a*10, 10*a) + eq(a*10L, 10*a) + eq(b*10, td(0, 600)) + eq(10*b, td(0, 600)) + eq(b*10L, td(0, 600)) + eq(c*10, td(0, 0, 10000)) + eq(10*c, td(0, 0, 10000)) + eq(c*10L, td(0, 0, 10000)) + eq(a*-1, -a) + eq(b*-2, -b-b) + eq(c*-2, -c+-c) + eq(b*(60*24), (b*60)*24) + eq(b*(60*24), (60*b)*24) + eq(c*1000, td(0, 1)) + eq(1000*c, td(0, 1)) + eq(a//7, td(1)) + eq(b//10, td(0, 6)) + eq(c//1000, td(0, 0, 1)) + eq(a//10, td(0, 7*24*360)) + eq(a//3600000, td(0, 0, 7*24*1000)) + + def test_disallowed_computations(self): + a = timedelta(42) + + # Add/sub ints, longs, floats should be illegal + for i in 1, 1L, 1.0: + self.assertRaises(TypeError, lambda: a+i) + self.assertRaises(TypeError, lambda: a-i) + self.assertRaises(TypeError, lambda: i+a) + self.assertRaises(TypeError, lambda: i-a) + + # Mul/div by float isn't supported. + x = 2.3 + self.assertRaises(TypeError, lambda: a*x) + self.assertRaises(TypeError, lambda: x*a) + self.assertRaises(TypeError, lambda: a/x) + self.assertRaises(TypeError, lambda: x/a) + self.assertRaises(TypeError, lambda: a // x) + self.assertRaises(TypeError, lambda: x // a) + + # Division of int by timedelta doesn't make sense. + # Division by zero doesn't make sense. + for zero in 0, 0L: + self.assertRaises(TypeError, lambda: zero // a) + self.assertRaises(ZeroDivisionError, lambda: a // zero) + + def test_basic_attributes(self): + days, seconds, us = 1, 7, 31 + td = timedelta(days, seconds, us) + self.assertEqual(td.days, days) + self.assertEqual(td.seconds, seconds) + self.assertEqual(td.microseconds, us) + + def test_carries(self): + t1 = timedelta(days=100, + weeks=-7, + hours=-24*(100-49), + minutes=-3, + seconds=12, + microseconds=(3*60 - 12) * 1e6 + 1) + t2 = timedelta(microseconds=1) + self.assertEqual(t1, t2) + + def test_hash_equality(self): + t1 = timedelta(days=100, + weeks=-7, + hours=-24*(100-49), + minutes=-3, + seconds=12, + microseconds=(3*60 - 12) * 1000000) + t2 = timedelta() + self.assertEqual(hash(t1), hash(t2)) + + t1 += timedelta(weeks=7) + t2 += timedelta(days=7*7) + self.assertEqual(t1, t2) + self.assertEqual(hash(t1), hash(t2)) + + d = {t1: 1} + d[t2] = 2 + self.assertEqual(len(d), 1) + self.assertEqual(d[t1], 2) + + def test_pickling(self): + args = 12, 34, 56 + orig = timedelta(*args) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + self.assertEqual(orig, derived) + + def test_compare(self): + t1 = timedelta(2, 3, 4) + t2 = timedelta(2, 3, 4) + self.failUnless(t1 == t2) + self.failUnless(t1 <= t2) + self.failUnless(t1 >= t2) + self.failUnless(not t1 != t2) + self.failUnless(not t1 < t2) + self.failUnless(not t1 > t2) + self.assertEqual(cmp(t1, t2), 0) + self.assertEqual(cmp(t2, t1), 0) + + for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): + t2 = timedelta(*args) # this is larger than t1 + self.failUnless(t1 < t2) + self.failUnless(t2 > t1) + self.failUnless(t1 <= t2) + self.failUnless(t2 >= t1) + self.failUnless(t1 != t2) + self.failUnless(t2 != t1) + self.failUnless(not t1 == t2) + self.failUnless(not t2 == t1) + self.failUnless(not t1 > t2) + self.failUnless(not t2 < t1) + self.failUnless(not t1 >= t2) + self.failUnless(not t2 <= t1) + self.assertEqual(cmp(t1, t2), -1) + self.assertEqual(cmp(t2, t1), 1) + + for badarg in OTHERSTUFF: + self.assertEqual(t1 == badarg, False) + self.assertEqual(t1 != badarg, True) + self.assertEqual(badarg == t1, False) + self.assertEqual(badarg != t1, True) + + self.assertRaises(TypeError, lambda: t1 <= badarg) + self.assertRaises(TypeError, lambda: t1 < badarg) + self.assertRaises(TypeError, lambda: t1 > badarg) + self.assertRaises(TypeError, lambda: t1 >= badarg) + self.assertRaises(TypeError, lambda: badarg <= t1) + self.assertRaises(TypeError, lambda: badarg < t1) + self.assertRaises(TypeError, lambda: badarg > t1) + self.assertRaises(TypeError, lambda: badarg >= t1) + + def test_str(self): + td = timedelta + eq = self.assertEqual + + eq(str(td(1)), "1 day, 0:00:00") + eq(str(td(-1)), "-1 day, 0:00:00") + eq(str(td(2)), "2 days, 0:00:00") + eq(str(td(-2)), "-2 days, 0:00:00") + + eq(str(td(hours=12, minutes=58, seconds=59)), "12:58:59") + eq(str(td(hours=2, minutes=3, seconds=4)), "2:03:04") + eq(str(td(weeks=-30, hours=23, minutes=12, seconds=34)), + "-210 days, 23:12:34") + + eq(str(td(milliseconds=1)), "0:00:00.001000") + eq(str(td(microseconds=3)), "0:00:00.000003") + + eq(str(td(days=999999999, hours=23, minutes=59, seconds=59, + microseconds=999999)), + "999999999 days, 23:59:59.999999") + + def test_roundtrip(self): + for td in (timedelta(days=999999999, hours=23, minutes=59, + seconds=59, microseconds=999999), + timedelta(days=-999999999), + timedelta(days=1, seconds=2, microseconds=3)): + + # Verify td -> string -> td identity. + s = repr(td) + self.failUnless(s.startswith('datetime.')) + s = s[9:] + td2 = eval(s) + self.assertEqual(td, td2) + + # Verify identity via reconstructing from pieces. + td2 = timedelta(td.days, td.seconds, td.microseconds) + self.assertEqual(td, td2) + + def test_resolution_info(self): + self.assert_(isinstance(timedelta.min, timedelta)) + self.assert_(isinstance(timedelta.max, timedelta)) + self.assert_(isinstance(timedelta.resolution, timedelta)) + self.assert_(timedelta.max > timedelta.min) + self.assertEqual(timedelta.min, timedelta(-999999999)) + self.assertEqual(timedelta.max, timedelta(999999999, 24*3600-1, 1e6-1)) + self.assertEqual(timedelta.resolution, timedelta(0, 0, 1)) + + def test_overflow(self): + tiny = timedelta.resolution + + td = timedelta.min + tiny + td -= tiny # no problem + self.assertRaises(OverflowError, td.__sub__, tiny) + self.assertRaises(OverflowError, td.__add__, -tiny) + + td = timedelta.max - tiny + td += tiny # no problem + self.assertRaises(OverflowError, td.__add__, tiny) + self.assertRaises(OverflowError, td.__sub__, -tiny) + + self.assertRaises(OverflowError, lambda: -timedelta.max) + + def test_microsecond_rounding(self): + td = timedelta + eq = self.assertEqual + + # Single-field rounding. + eq(td(milliseconds=0.4/1000), td(0)) # rounds to 0 + eq(td(milliseconds=-0.4/1000), td(0)) # rounds to 0 + eq(td(milliseconds=0.6/1000), td(microseconds=1)) + eq(td(milliseconds=-0.6/1000), td(microseconds=-1)) + + # Rounding due to contributions from more than one field. + us_per_hour = 3600e6 + us_per_day = us_per_hour * 24 + eq(td(days=.4/us_per_day), td(0)) + eq(td(hours=.2/us_per_hour), td(0)) + eq(td(days=.4/us_per_day, hours=.2/us_per_hour), td(microseconds=1)) + + eq(td(days=-.4/us_per_day), td(0)) + eq(td(hours=-.2/us_per_hour), td(0)) + eq(td(days=-.4/us_per_day, hours=-.2/us_per_hour), td(microseconds=-1)) + + def test_massive_normalization(self): + td = timedelta(microseconds=-1) + self.assertEqual((td.days, td.seconds, td.microseconds), + (-1, 24*3600-1, 999999)) + + def test_bool(self): + self.failUnless(timedelta(1)) + self.failUnless(timedelta(0, 1)) + self.failUnless(timedelta(0, 0, 1)) + self.failUnless(timedelta(microseconds=1)) + self.failUnless(not timedelta(0)) + + def test_subclass_timedelta(self): + + class T(timedelta): + @staticmethod + def from_td(td): + return T(td.days, td.seconds, td.microseconds) + + def as_hours(self): + sum = (self.days * 24 + + self.seconds / 3600.0 + + self.microseconds / 3600e6) + return round(sum) + + t1 = T(days=1) + self.assert_(type(t1) is T) + self.assertEqual(t1.as_hours(), 24) + + t2 = T(days=-1, seconds=-3600) + self.assert_(type(t2) is T) + self.assertEqual(t2.as_hours(), -25) + + t3 = t1 + t2 + self.assert_(type(t3) is timedelta) + t4 = T.from_td(t3) + self.assert_(type(t4) is T) + self.assertEqual(t3.days, t4.days) + self.assertEqual(t3.seconds, t4.seconds) + self.assertEqual(t3.microseconds, t4.microseconds) + self.assertEqual(str(t3), str(t4)) + self.assertEqual(t4.as_hours(), -1) + +############################################################################# +# date tests + +class TestDateOnly(unittest.TestCase): + # Tests here won't pass if also run on datetime objects, so don't + # subclass this to test datetimes too. + + def test_delta_non_days_ignored(self): + dt = date(2000, 1, 2) + delta = timedelta(days=1, hours=2, minutes=3, seconds=4, + microseconds=5) + days = timedelta(delta.days) + self.assertEqual(days, timedelta(1)) + + dt2 = dt + delta + self.assertEqual(dt2, dt + days) + + dt2 = delta + dt + self.assertEqual(dt2, dt + days) + + dt2 = dt - delta + self.assertEqual(dt2, dt - days) + + delta = -delta + days = timedelta(delta.days) + self.assertEqual(days, timedelta(-2)) + + dt2 = dt + delta + self.assertEqual(dt2, dt + days) + + dt2 = delta + dt + self.assertEqual(dt2, dt + days) + + dt2 = dt - delta + self.assertEqual(dt2, dt - days) + +class SubclassDate(date): + sub_var = 1 + +class TestDate(HarmlessMixedComparison, unittest.TestCase): + # Tests here should pass for both dates and datetimes, except for a + # few tests that TestDateTime overrides. + + theclass = date + + def test_basic_attributes(self): + dt = self.theclass(2002, 3, 1) + self.assertEqual(dt.year, 2002) + self.assertEqual(dt.month, 3) + self.assertEqual(dt.day, 1) + + def test_roundtrip(self): + for dt in (self.theclass(1, 2, 3), + self.theclass.today()): + # Verify dt -> string -> date identity. + s = repr(dt) + self.failUnless(s.startswith('datetime.')) + s = s[9:] + dt2 = eval(s) + self.assertEqual(dt, dt2) + + # Verify identity via reconstructing from pieces. + dt2 = self.theclass(dt.year, dt.month, dt.day) + self.assertEqual(dt, dt2) + + def test_ordinal_conversions(self): + # Check some fixed values. + for y, m, d, n in [(1, 1, 1, 1), # calendar origin + (1, 12, 31, 365), + (2, 1, 1, 366), + # first example from "Calendrical Calculations" + (1945, 11, 12, 710347)]: + d = self.theclass(y, m, d) + self.assertEqual(n, d.toordinal()) + fromord = self.theclass.fromordinal(n) + self.assertEqual(d, fromord) + if hasattr(fromord, "hour"): + # if we're checking something fancier than a date, verify + # the extra fields have been zeroed out + self.assertEqual(fromord.hour, 0) + self.assertEqual(fromord.minute, 0) + self.assertEqual(fromord.second, 0) + self.assertEqual(fromord.microsecond, 0) + + # Check first and last days of year spottily across the whole + # range of years supported. + for year in xrange(MINYEAR, MAXYEAR+1, 7): + # Verify (year, 1, 1) -> ordinal -> y, m, d is identity. + d = self.theclass(year, 1, 1) + n = d.toordinal() + d2 = self.theclass.fromordinal(n) + self.assertEqual(d, d2) + # Verify that moving back a day gets to the end of year-1. + if year > 1: + d = self.theclass.fromordinal(n-1) + d2 = self.theclass(year-1, 12, 31) + self.assertEqual(d, d2) + self.assertEqual(d2.toordinal(), n-1) + + # Test every day in a leap-year and a non-leap year. + dim = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + for year, isleap in (2000, True), (2002, False): + n = self.theclass(year, 1, 1).toordinal() + for month, maxday in zip(range(1, 13), dim): + if month == 2 and isleap: + maxday += 1 + for day in range(1, maxday+1): + d = self.theclass(year, month, day) + self.assertEqual(d.toordinal(), n) + self.assertEqual(d, self.theclass.fromordinal(n)) + n += 1 + + def test_extreme_ordinals(self): + a = self.theclass.min + a = self.theclass(a.year, a.month, a.day) # get rid of time parts + aord = a.toordinal() + b = a.fromordinal(aord) + self.assertEqual(a, b) + + self.assertRaises(ValueError, lambda: a.fromordinal(aord - 1)) + + b = a + timedelta(days=1) + self.assertEqual(b.toordinal(), aord + 1) + self.assertEqual(b, self.theclass.fromordinal(aord + 1)) + + a = self.theclass.max + a = self.theclass(a.year, a.month, a.day) # get rid of time parts + aord = a.toordinal() + b = a.fromordinal(aord) + self.assertEqual(a, b) + + self.assertRaises(ValueError, lambda: a.fromordinal(aord + 1)) + + b = a - timedelta(days=1) + self.assertEqual(b.toordinal(), aord - 1) + self.assertEqual(b, self.theclass.fromordinal(aord - 1)) + + def test_bad_constructor_arguments(self): + # bad years + self.theclass(MINYEAR, 1, 1) # no exception + self.theclass(MAXYEAR, 1, 1) # no exception + self.assertRaises(ValueError, self.theclass, MINYEAR-1, 1, 1) + self.assertRaises(ValueError, self.theclass, MAXYEAR+1, 1, 1) + # bad months + self.theclass(2000, 1, 1) # no exception + self.theclass(2000, 12, 1) # no exception + self.assertRaises(ValueError, self.theclass, 2000, 0, 1) + self.assertRaises(ValueError, self.theclass, 2000, 13, 1) + # bad days + self.theclass(2000, 2, 29) # no exception + self.theclass(2004, 2, 29) # no exception + self.theclass(2400, 2, 29) # no exception + self.assertRaises(ValueError, self.theclass, 2000, 2, 30) + self.assertRaises(ValueError, self.theclass, 2001, 2, 29) + self.assertRaises(ValueError, self.theclass, 2100, 2, 29) + self.assertRaises(ValueError, self.theclass, 1900, 2, 29) + self.assertRaises(ValueError, self.theclass, 2000, 1, 0) + self.assertRaises(ValueError, self.theclass, 2000, 1, 32) + + def test_hash_equality(self): + d = self.theclass(2000, 12, 31) + # same thing + e = self.theclass(2000, 12, 31) + self.assertEqual(d, e) + self.assertEqual(hash(d), hash(e)) + + dic = {d: 1} + dic[e] = 2 + self.assertEqual(len(dic), 1) + self.assertEqual(dic[d], 2) + self.assertEqual(dic[e], 2) + + d = self.theclass(2001, 1, 1) + # same thing + e = self.theclass(2001, 1, 1) + self.assertEqual(d, e) + self.assertEqual(hash(d), hash(e)) + + dic = {d: 1} + dic[e] = 2 + self.assertEqual(len(dic), 1) + self.assertEqual(dic[d], 2) + self.assertEqual(dic[e], 2) + + def test_computations(self): + a = self.theclass(2002, 1, 31) + b = self.theclass(1956, 1, 31) + + diff = a-b + self.assertEqual(diff.days, 46*365 + len(range(1956, 2002, 4))) + self.assertEqual(diff.seconds, 0) + self.assertEqual(diff.microseconds, 0) + + day = timedelta(1) + week = timedelta(7) + a = self.theclass(2002, 3, 2) + self.assertEqual(a + day, self.theclass(2002, 3, 3)) + self.assertEqual(day + a, self.theclass(2002, 3, 3)) + self.assertEqual(a - day, self.theclass(2002, 3, 1)) + self.assertEqual(-day + a, self.theclass(2002, 3, 1)) + self.assertEqual(a + week, self.theclass(2002, 3, 9)) + self.assertEqual(a - week, self.theclass(2002, 2, 23)) + self.assertEqual(a + 52*week, self.theclass(2003, 3, 1)) + self.assertEqual(a - 52*week, self.theclass(2001, 3, 3)) + self.assertEqual((a + week) - a, week) + self.assertEqual((a + day) - a, day) + self.assertEqual((a - week) - a, -week) + self.assertEqual((a - day) - a, -day) + self.assertEqual(a - (a + week), -week) + self.assertEqual(a - (a + day), -day) + self.assertEqual(a - (a - week), week) + self.assertEqual(a - (a - day), day) + + # Add/sub ints, longs, floats should be illegal + for i in 1, 1L, 1.0: + self.assertRaises(TypeError, lambda: a+i) + self.assertRaises(TypeError, lambda: a-i) + self.assertRaises(TypeError, lambda: i+a) + self.assertRaises(TypeError, lambda: i-a) + + # delta - date is senseless. + self.assertRaises(TypeError, lambda: day - a) + # mixing date and (delta or date) via * or // is senseless + self.assertRaises(TypeError, lambda: day * a) + self.assertRaises(TypeError, lambda: a * day) + self.assertRaises(TypeError, lambda: day // a) + self.assertRaises(TypeError, lambda: a // day) + self.assertRaises(TypeError, lambda: a * a) + self.assertRaises(TypeError, lambda: a // a) + # date + date is senseless + self.assertRaises(TypeError, lambda: a + a) + + def test_overflow(self): + tiny = self.theclass.resolution + + for delta in [tiny, timedelta(1), timedelta(2)]: + dt = self.theclass.min + delta + dt -= delta # no problem + self.assertRaises(OverflowError, dt.__sub__, delta) + self.assertRaises(OverflowError, dt.__add__, -delta) + + dt = self.theclass.max - delta + dt += delta # no problem + self.assertRaises(OverflowError, dt.__add__, delta) + self.assertRaises(OverflowError, dt.__sub__, -delta) + + def test_fromtimestamp(self): + import time + + # Try an arbitrary fixed value. + year, month, day = 1999, 9, 19 + ts = time.mktime((year, month, day, 0, 0, 0, 0, 0, -1)) + d = self.theclass.fromtimestamp(ts) + self.assertEqual(d.year, year) + self.assertEqual(d.month, month) + self.assertEqual(d.day, day) + + def test_insane_fromtimestamp(self): + # It's possible that some platform maps time_t to double, + # and that this test will fail there. This test should + # exempt such platforms (provided they return reasonable + # results!). + for insane in -1e200, 1e200: + self.assertRaises(ValueError, self.theclass.fromtimestamp, + insane) + + def test_today(self): + import time + + # We claim that today() is like fromtimestamp(time.time()), so + # prove it. + for dummy in range(3): + today = self.theclass.today() + ts = time.time() + todayagain = self.theclass.fromtimestamp(ts) + if today == todayagain: + break + # There are several legit reasons that could fail: + # 1. It recently became midnight, between the today() and the + # time() calls. + # 2. The platform time() has such fine resolution that we'll + # never get the same value twice. + # 3. The platform time() has poor resolution, and we just + # happened to call today() right before a resolution quantum + # boundary. + # 4. The system clock got fiddled between calls. + # In any case, wait a little while and try again. + time.sleep(0.1) + + # It worked or it didn't. If it didn't, assume it's reason #2, and + # let the test pass if they're within half a second of each other. + self.failUnless(today == todayagain or + abs(todayagain - today) < timedelta(seconds=0.5)) + + def test_weekday(self): + for i in range(7): + # March 4, 2002 is a Monday + self.assertEqual(self.theclass(2002, 3, 4+i).weekday(), i) + self.assertEqual(self.theclass(2002, 3, 4+i).isoweekday(), i+1) + # January 2, 1956 is a Monday + self.assertEqual(self.theclass(1956, 1, 2+i).weekday(), i) + self.assertEqual(self.theclass(1956, 1, 2+i).isoweekday(), i+1) + + def test_isocalendar(self): + # Check examples from + # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm + for i in range(7): + d = self.theclass(2003, 12, 22+i) + self.assertEqual(d.isocalendar(), (2003, 52, i+1)) + d = self.theclass(2003, 12, 29) + timedelta(i) + self.assertEqual(d.isocalendar(), (2004, 1, i+1)) + d = self.theclass(2004, 1, 5+i) + self.assertEqual(d.isocalendar(), (2004, 2, i+1)) + d = self.theclass(2009, 12, 21+i) + self.assertEqual(d.isocalendar(), (2009, 52, i+1)) + d = self.theclass(2009, 12, 28) + timedelta(i) + self.assertEqual(d.isocalendar(), (2009, 53, i+1)) + d = self.theclass(2010, 1, 4+i) + self.assertEqual(d.isocalendar(), (2010, 1, i+1)) + + def test_iso_long_years(self): + # Calculate long ISO years and compare to table from + # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm + ISO_LONG_YEARS_TABLE = """ + 4 32 60 88 + 9 37 65 93 + 15 43 71 99 + 20 48 76 + 26 54 82 + + 105 133 161 189 + 111 139 167 195 + 116 144 172 + 122 150 178 + 128 156 184 + + 201 229 257 285 + 207 235 263 291 + 212 240 268 296 + 218 246 274 + 224 252 280 + + 303 331 359 387 + 308 336 364 392 + 314 342 370 398 + 320 348 376 + 325 353 381 + """ + iso_long_years = map(int, ISO_LONG_YEARS_TABLE.split()) + iso_long_years.sort() + L = [] + for i in range(400): + d = self.theclass(2000+i, 12, 31) + d1 = self.theclass(1600+i, 12, 31) + self.assertEqual(d.isocalendar()[1:], d1.isocalendar()[1:]) + if d.isocalendar()[1] == 53: + L.append(i) + self.assertEqual(L, iso_long_years) + + def test_isoformat(self): + t = self.theclass(2, 3, 2) + self.assertEqual(t.isoformat(), "0002-03-02") + + def test_ctime(self): + t = self.theclass(2002, 3, 2) + self.assertEqual(t.ctime(), "Sat Mar 2 00:00:00 2002") + + def test_strftime(self): + t = self.theclass(2005, 3, 2) + self.assertEqual(t.strftime("m:%m d:%d y:%y"), "m:03 d:02 y:05") + self.assertEqual(t.strftime(""), "") # SF bug #761337 + self.assertEqual(t.strftime('x'*1000), 'x'*1000) # SF bug #1556784 + + self.assertRaises(TypeError, t.strftime) # needs an arg + self.assertRaises(TypeError, t.strftime, "one", "two") # too many args + self.assertRaises(TypeError, t.strftime, 42) # arg wrong type + + # test that unicode input is allowed (issue 2782) + self.assertEqual(t.strftime(u"%m"), "03") + + # A naive object replaces %z and %Z w/ empty strings. + self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''") + + #make sure that invalid format specifiers are handled correctly + #self.assertRaises(ValueError, t.strftime, "%e") + #self.assertRaises(ValueError, t.strftime, "%") + #self.assertRaises(ValueError, t.strftime, "%#") + + #oh well, some systems just ignore those invalid ones. + #at least, excercise them to make sure that no crashes + #are generated + for f in ["%e", "%", "%#"]: + try: + t.strftime(f) + except ValueError: + pass + + #check that this standard extension works + t.strftime("%f") + + + def test_format(self): + dt = self.theclass(2007, 9, 10) + self.assertEqual(dt.__format__(''), str(dt)) + + # check that a derived class's __str__() gets called + class A(self.theclass): + def __str__(self): + return 'A' + a = A(2007, 9, 10) + self.assertEqual(a.__format__(''), 'A') + + # check that a derived class's strftime gets called + class B(self.theclass): + def strftime(self, format_spec): + return 'B' + b = B(2007, 9, 10) + self.assertEqual(b.__format__(''), str(dt)) + + for fmt in ["m:%m d:%d y:%y", + "m:%m d:%d y:%y H:%H M:%M S:%S", + "%z %Z", + ]: + self.assertEqual(dt.__format__(fmt), dt.strftime(fmt)) + self.assertEqual(a.__format__(fmt), dt.strftime(fmt)) + self.assertEqual(b.__format__(fmt), 'B') + + def test_resolution_info(self): + self.assert_(isinstance(self.theclass.min, self.theclass)) + self.assert_(isinstance(self.theclass.max, self.theclass)) + self.assert_(isinstance(self.theclass.resolution, timedelta)) + self.assert_(self.theclass.max > self.theclass.min) + + def test_extreme_timedelta(self): + big = self.theclass.max - self.theclass.min + # 3652058 days, 23 hours, 59 minutes, 59 seconds, 999999 microseconds + n = (big.days*24*3600 + big.seconds)*1000000 + big.microseconds + # n == 315537897599999999 ~= 2**58.13 + justasbig = timedelta(0, 0, n) + self.assertEqual(big, justasbig) + self.assertEqual(self.theclass.min + big, self.theclass.max) + self.assertEqual(self.theclass.max - big, self.theclass.min) + + def test_timetuple(self): + for i in range(7): + # January 2, 1956 is a Monday (0) + d = self.theclass(1956, 1, 2+i) + t = d.timetuple() + self.assertEqual(t, (1956, 1, 2+i, 0, 0, 0, i, 2+i, -1)) + # February 1, 1956 is a Wednesday (2) + d = self.theclass(1956, 2, 1+i) + t = d.timetuple() + self.assertEqual(t, (1956, 2, 1+i, 0, 0, 0, (2+i)%7, 32+i, -1)) + # March 1, 1956 is a Thursday (3), and is the 31+29+1 = 61st day + # of the year. + d = self.theclass(1956, 3, 1+i) + t = d.timetuple() + self.assert... [truncated message content] |