From 49ce06858b51ef98c31431436b28d32dd3bd99cd Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Tue, 1 Nov 2011 12:56:14 +0100 Subject: Strengthen the tests for format '%Y', in relation with issue #13305. --- Lib/test/datetimetester.py | 12 +++++++-- Lib/test/test_time.py | 66 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index f91e8fc..85036aa 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1291,8 +1291,16 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase): def test_strftime_y2k(self): for y in (1, 49, 70, 99, 100, 999, 1000, 1970): - self.assertIn(self.theclass(y, 1, 1).strftime("%Y"), - [str(y),'%04d' % y]) + d = self.theclass(y, 1, 1) + # Issue 13305: For years < 1000, the value is not always + # padded to 4 digits across platforms. The C standard + # assumes year >= 1900, so it does not specify the number + # of digits. + if d.strftime("%Y") != '%04d' % y: + # Year 42 returns '42', not padded + self.assertEqual(d.strftime("%Y"), '%d' % y) + # '0042' is obtained anyway + self.assertEqual(d.strftime("%4Y"), '%04d' % y) def test_replace(self): cls = self.theclass diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 73c53b3..9e2e68d 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -70,28 +70,35 @@ class TimeTestCase(unittest.TestCase): with self.assertRaises(ValueError): time.strftime('%f') - def _bounds_checking(self, func=time.strftime): + def _bounds_checking(self, func): # Make sure that strftime() checks the bounds of the various parts - #of the time tuple (0 is valid for *all* values). + # of the time tuple (0 is valid for *all* values). # The year field is tested by other test cases above # Check month [1, 12] + zero support + func((1900, 0, 1, 0, 0, 0, 0, 1, -1)) + func((1900, 12, 1, 0, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, func, (1900, -1, 1, 0, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, func, (1900, 13, 1, 0, 0, 0, 0, 1, -1)) # Check day of month [1, 31] + zero support + func((1900, 1, 0, 0, 0, 0, 0, 1, -1)) + func((1900, 1, 31, 0, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, func, (1900, 1, -1, 0, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, func, (1900, 1, 32, 0, 0, 0, 0, 1, -1)) # Check hour [0, 23] + func((1900, 1, 1, 0, 0, 0, 0, 1, -1)) + func((1900, 1, 1, 23, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, func, (1900, 1, 1, -1, 0, 0, 0, 1, -1)) self.assertRaises(ValueError, func, (1900, 1, 1, 24, 0, 0, 0, 1, -1)) # Check minute [0, 59] + func((1900, 1, 1, 0, 59, 0, 0, 1, -1)) self.assertRaises(ValueError, func, (1900, 1, 1, 0, -1, 0, 0, 1, -1)) self.assertRaises(ValueError, func, @@ -101,15 +108,21 @@ class TimeTestCase(unittest.TestCase): (1900, 1, 1, 0, 0, -1, 0, 1, -1)) # C99 only requires allowing for one leap second, but Python's docs say # allow two leap seconds (0..61) + func((1900, 1, 1, 0, 0, 60, 0, 1, -1)) + func((1900, 1, 1, 0, 0, 61, 0, 1, -1)) self.assertRaises(ValueError, func, (1900, 1, 1, 0, 0, 62, 0, 1, -1)) # No check for upper-bound day of week; # value forced into range by a ``% 7`` calculation. # Start check at -2 since gettmarg() increments value before taking # modulo. + self.assertEqual(func((1900, 1, 1, 0, 0, 0, -1, 1, -1)), + func((1900, 1, 1, 0, 0, 0, +6, 1, -1))) self.assertRaises(ValueError, func, (1900, 1, 1, 0, 0, 0, -2, 1, -1)) # Check day of the year [1, 366] + zero support + func((1900, 1, 1, 0, 0, 0, 0, 0, -1)) + func((1900, 1, 1, 0, 0, 0, 0, 366, -1)) self.assertRaises(ValueError, func, (1900, 1, 1, 0, 0, 0, 0, -1, -1)) self.assertRaises(ValueError, func, @@ -299,6 +312,8 @@ class _BaseYearTest(unittest.TestCase): raise NotImplementedError() class _TestAsctimeYear: + _format = '%d' + def yearstr(self, y): return time.asctime((y,) + (0,) * 8).split()[-1] @@ -308,8 +323,41 @@ class _TestAsctimeYear: self.assertEqual(self.yearstr(123456789), '123456789') class _TestStrftimeYear: + + # Issue 13305: For years < 1000, the value is not always + # padded to 4 digits across platforms. The C standard + # assumes year >= 1900, so it does not specify the number + # of digits. + + if time.strftime('%Y', (1,) + (0,) * 8) == '0001': + _format = '%04d' + else: + _format = '%d' + def yearstr(self, y): - return time.strftime('%Y', (y,) + (0,) * 8).split()[-1] + return time.strftime('%Y', (y,) + (0,) * 8) + + def test_4dyear(self): + # Check that we can return the zero padded value. + if self._format == '%04d': + self.test_year('%04d') + else: + def year4d(y): + return time.strftime('%4Y', (y,) + (0,) * 8) + self.test_year('%04d', func=year4d) + +class _Test4dYear(_BaseYearTest): + _format = '%d' + + def test_year(self, fmt=None, func=None): + fmt = fmt or self._format + func = func or self.yearstr + self.assertEqual(func(1), fmt % 1) + self.assertEqual(func(68), fmt % 68) + self.assertEqual(func(69), fmt % 69) + self.assertEqual(func(99), fmt % 99) + self.assertEqual(func(999), fmt % 999) + self.assertEqual(func(9999), fmt % 9999) def test_large_year(self): # Check that it doesn't crash for year > 9999 @@ -321,23 +369,13 @@ class _TestStrftimeYear: self.assertEqual(text, '12345') self.assertEqual(self.yearstr(123456789), '123456789') -class _Test4dYear(_BaseYearTest): - - def test_year(self): - self.assertIn(self.yearstr(1), ('1', '0001')) - self.assertIn(self.yearstr(68), ('68', '0068')) - self.assertIn(self.yearstr(69), ('69', '0069')) - self.assertIn(self.yearstr(99), ('99', '0099')) - self.assertIn(self.yearstr(999), ('999', '0999')) - self.assertEqual(self.yearstr(9999), '9999') - def test_negative(self): try: text = self.yearstr(-1) except ValueError: # strftime() is limited to [1; 9999] with Visual Studio return - self.assertIn(text, ('-1', '-001')) + self.assertEqual(text, self._format % -1) self.assertEqual(self.yearstr(-1234), '-1234') self.assertEqual(self.yearstr(-123456), '-123456') -- cgit v0.12 117 118 119 120 121 122 123
/*
 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
 * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#ifndef PluginStream_H
#define PluginStream_H

#include "CString.h"
#include "FileSystem.h"
#include "KURL.h"
#include "NetscapePlugInStreamLoader.h"
#include "PlatformString.h"
#include "PluginQuirkSet.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "StringHash.h"
#include "Timer.h"
#include "npruntime_internal.h"
#include <wtf/HashMap.h>
#include <wtf/OwnPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>

namespace WebCore {
    class Frame;
    class PluginStream;

    enum PluginStreamState { StreamBeforeStarted, StreamStarted, StreamStopped };

    class PluginStreamClient {
    public:
        virtual ~PluginStreamClient() {}
        virtual void streamDidFinishLoading(PluginStream*) {}
    };

    class PluginStream : public RefCounted<PluginStream>, private NetscapePlugInStreamLoaderClient {
    public:
        static PassRefPtr<PluginStream> create(PluginStreamClient* client, Frame* frame, const ResourceRequest& request, bool sendNotification, void* notifyData, const NPPluginFuncs* functions, NPP instance, const PluginQuirkSet& quirks)
        {
            return adoptRef(new PluginStream(client, frame, request, sendNotification, notifyData, functions, instance, quirks));
        }
        virtual ~PluginStream();
        
        void start();
        void stop();

        void startStream();

        void setLoadManually(bool loadManually) { m_loadManually = loadManually; }

        void sendJavaScriptStream(const KURL& requestURL, const CString& resultString);
        void cancelAndDestroyStream(NPReason);

        static NPP ownerForStream(NPStream*);

        // NetscapePlugInStreamLoaderClient
        virtual void didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse&);
        virtual void didReceiveData(NetscapePlugInStreamLoader*, const char*, int);
        virtual void didFail(NetscapePlugInStreamLoader*, const ResourceError&);
        virtual void didFinishLoading(NetscapePlugInStreamLoader*);
        virtual bool wantsAllStreams() const;

    private:
        PluginStream(PluginStreamClient*, Frame*, const ResourceRequest&, bool sendNotification, void* notifyData, const NPPluginFuncs*, NPP instance, const PluginQuirkSet&);

        void deliverData();
        void destroyStream(NPReason);
        void destroyStream();

        ResourceRequest m_resourceRequest;
        ResourceResponse m_resourceResponse;

        PluginStreamClient* m_client;
        Frame* m_frame;
        RefPtr<NetscapePlugInStreamLoader> m_loader;
        void* m_notifyData;
        bool m_sendNotification;
        PluginStreamState m_streamState;
        bool m_loadManually;

        Timer<PluginStream> m_delayDeliveryTimer;
        void delayDeliveryTimerFired(Timer<PluginStream>*);

        OwnPtr< Vector<char> > m_deliveryData;

        PlatformFileHandle m_tempFileHandle;

        const NPPluginFuncs* m_pluginFuncs;
        NPP m_instance;
        uint16 m_transferMode;
        int32 m_offset;
        CString m_headers;
        CString m_path;
        NPReason m_reason;
        NPStream m_stream;
        PluginQuirkSet m_quirks;
    };

} // namespace WebCore

#endif