diff options
author | Ethan Furman <ethan@stoneleaf.us> | 2021-04-21 17:20:44 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-21 17:20:44 (GMT) |
commit | a02cb474f9c097c83cd444a47e9fb5f99b4aaf45 (patch) | |
tree | c9ebd2e0b7762ad1ca1f986966cb2ca02ea7fa6d /Lib/test | |
parent | 56c95dfe271b1242bdc8163d4677e311552c00cb (diff) | |
download | cpython-a02cb474f9c097c83cd444a47e9fb5f99b4aaf45.zip cpython-a02cb474f9c097c83cd444a47e9fb5f99b4aaf45.tar.gz cpython-a02cb474f9c097c83cd444a47e9fb5f99b4aaf45.tar.bz2 |
bpo-38659: [Enum] add _simple_enum decorator (GH-25497)
add:
* `_simple_enum` decorator to transform a normal class into an enum
* `_test_simple_enum` function to compare
* `_old_convert_` to enable checking `_convert_` generated enums
`_simple_enum` takes a normal class and converts it into an enum:
@simple_enum(Enum)
class Color:
RED = 1
GREEN = 2
BLUE = 3
`_old_convert_` works much like` _convert_` does, using the original logic:
# in a test file
import socket, enum
CheckedAddressFamily = enum._old_convert_(
enum.IntEnum, 'AddressFamily', 'socket',
lambda C: C.isupper() and C.startswith('AF_'),
source=_socket,
)
`_test_simple_enum` takes a traditional enum and a simple enum and
compares the two:
# in the REPL or the same module as Color
class CheckedColor(Enum):
RED = 1
GREEN = 2
BLUE = 3
_test_simple_enum(CheckedColor, Color)
_test_simple_enum(CheckedAddressFamily, socket.AddressFamily)
Any important differences will raise a TypeError
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_ast.py | 30 | ||||
-rw-r--r-- | Lib/test/test_enum.py | 61 | ||||
-rw-r--r-- | Lib/test/test_httplib.py | 145 | ||||
-rw-r--r-- | Lib/test/test_pstats.py | 20 | ||||
-rw-r--r-- | Lib/test/test_signal.py | 27 | ||||
-rwxr-xr-x | Lib/test/test_socket.py | 35 | ||||
-rw-r--r-- | Lib/test/test_ssl.py | 153 | ||||
-rw-r--r-- | Lib/test/test_unicode.py | 9 | ||||
-rwxr-xr-x | Lib/test/test_uuid.py | 8 |
9 files changed, 478 insertions, 10 deletions
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 6824958..80d24e9 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1,6 +1,7 @@ import ast import builtins import dis +import enum import os import sys import types @@ -698,6 +699,35 @@ class AST_Tests(unittest.TestCase): with self.assertRaisesRegex(ValueError, f"Name node can't be used with '{constant}' constant"): compile(expr, "<test>", "eval") + def test_precedence_enum(self): + class _Precedence(enum.IntEnum): + """Precedence table that originated from python grammar.""" + TUPLE = enum.auto() + YIELD = enum.auto() # 'yield', 'yield from' + TEST = enum.auto() # 'if'-'else', 'lambda' + OR = enum.auto() # 'or' + AND = enum.auto() # 'and' + NOT = enum.auto() # 'not' + CMP = enum.auto() # '<', '>', '==', '>=', '<=', '!=', + # 'in', 'not in', 'is', 'is not' + EXPR = enum.auto() + BOR = EXPR # '|' + BXOR = enum.auto() # '^' + BAND = enum.auto() # '&' + SHIFT = enum.auto() # '<<', '>>' + ARITH = enum.auto() # '+', '-' + TERM = enum.auto() # '*', '@', '/', '%', '//' + FACTOR = enum.auto() # unary '+', '-', '~' + POWER = enum.auto() # '**' + AWAIT = enum.auto() # 'await' + ATOM = enum.auto() + def next(self): + try: + return self.__class__(self + 1) + except ValueError: + return self + enum._test_simple_enum(_Precedence, ast._Precedence) + class ASTHelpers_Test(unittest.TestCase): maxDiff = None diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index b9d7f96..d946dd5 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -8,7 +8,7 @@ import unittest import threading from collections import OrderedDict from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto -from enum import STRICT, CONFORM, EJECT, KEEP +from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum from io import StringIO from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL from test import support @@ -2511,10 +2511,13 @@ class TestFlag(unittest.TestCase): d = 6 # self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7) + # self.assertIs(Water(7), Water.ONE|Water.TWO) self.assertIs(Water(~9), Water.TWO) + # self.assertEqual(Space(7), 7) self.assertTrue(type(Space(7)) is int) + # self.assertEqual(list(Bizarre), [Bizarre.c]) self.assertIs(Bizarre(3), Bizarre.b) self.assertIs(Bizarre(6), Bizarre.d) @@ -3053,16 +3056,20 @@ class TestIntFlag(unittest.TestCase): EIGHT = 8 self.assertIs(Space._boundary_, EJECT) # + # class Bizarre(IntFlag, boundary=KEEP): b = 3 c = 4 d = 6 # self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5) + # self.assertIs(Water(7), Water.ONE|Water.TWO) self.assertIs(Water(~9), Water.TWO) + # self.assertEqual(Space(7), 7) self.assertTrue(type(Space(7)) is int) + # self.assertEqual(list(Bizarre), [Bizarre.c]) self.assertIs(Bizarre(3), Bizarre.b) self.assertIs(Bizarre(6), Bizarre.d) @@ -3577,6 +3584,41 @@ class TestStdLib(unittest.TestCase): if failed: self.fail("result does not equal expected, see print above") + def test_test_simple_enum(self): + @_simple_enum(Enum) + class SimpleColor: + RED = 1 + GREEN = 2 + BLUE = 3 + class CheckedColor(Enum): + RED = 1 + GREEN = 2 + BLUE = 3 + self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None) + SimpleColor.GREEN._value_ = 9 + self.assertRaisesRegex( + TypeError, "enum mismatch", + _test_simple_enum, CheckedColor, SimpleColor, + ) + class CheckedMissing(IntFlag, boundary=KEEP): + SIXTY_FOUR = 64 + ONE_TWENTY_EIGHT = 128 + TWENTY_FORTY_EIGHT = 2048 + ALL = 2048 + 128 + 64 + 12 + CM = CheckedMissing + self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT]) + # + @_simple_enum(IntFlag, boundary=KEEP) + class Missing: + SIXTY_FOUR = 64 + ONE_TWENTY_EIGHT = 128 + TWENTY_FORTY_EIGHT = 2048 + ALL = 2048 + 128 + 64 + 12 + M = Missing + self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT]) + # + _test_simple_enum(CheckedMissing, Missing) + class MiscTestCase(unittest.TestCase): def test__all__(self): @@ -3592,6 +3634,13 @@ CONVERT_TEST_NAME_A = 5 # This one should sort first. CONVERT_TEST_NAME_E = 5 CONVERT_TEST_NAME_F = 5 +CONVERT_STRING_TEST_NAME_D = 5 +CONVERT_STRING_TEST_NAME_C = 5 +CONVERT_STRING_TEST_NAME_B = 5 +CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first. +CONVERT_STRING_TEST_NAME_E = 5 +CONVERT_STRING_TEST_NAME_F = 5 + class TestIntEnumConvert(unittest.TestCase): def test_convert_value_lookup_priority(self): test_type = enum.IntEnum._convert_( @@ -3639,14 +3688,16 @@ class TestIntEnumConvert(unittest.TestCase): filter=lambda x: x.startswith('CONVERT_TEST_')) def test_convert_repr_and_str(self): + # reset global constants, as previous tests could have converted the + # integer values to enums module = ('test.test_enum', '__main__')[__name__=='__main__'] test_type = enum.IntEnum._convert_( 'UnittestConvert', module, - filter=lambda x: x.startswith('CONVERT_TEST_')) - self.assertEqual(repr(test_type.CONVERT_TEST_NAME_A), '%s.CONVERT_TEST_NAME_A' % module) - self.assertEqual(str(test_type.CONVERT_TEST_NAME_A), 'CONVERT_TEST_NAME_A') - self.assertEqual(format(test_type.CONVERT_TEST_NAME_A), '5') + filter=lambda x: x.startswith('CONVERT_STRING_TEST_')) + self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module) + self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A') + self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5') # global names for StrEnum._convert_ test CONVERT_STR_TEST_2 = 'goodbye' diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 5fb4592..438c2eb 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1,3 +1,4 @@ +import enum import errno from http import client, HTTPStatus import io @@ -524,6 +525,150 @@ class BasicTest(TestCase): # see issue40084 self.assertTrue({'description', 'name', 'phrase', 'value'} <= set(dir(HTTPStatus(404)))) + def test_simple_httpstatus(self): + class CheckedHTTPStatus(enum.IntEnum): + """HTTP status codes and reason phrases + + Status codes from the following RFCs are all observed: + + * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616 + * RFC 6585: Additional HTTP Status Codes + * RFC 3229: Delta encoding in HTTP + * RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518 + * RFC 5842: Binding Extensions to WebDAV + * RFC 7238: Permanent Redirect + * RFC 2295: Transparent Content Negotiation in HTTP + * RFC 2774: An HTTP Extension Framework + * RFC 7725: An HTTP Status Code to Report Legal Obstacles + * RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2) + * RFC 2324: Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0) + * RFC 8297: An HTTP Status Code for Indicating Hints + * RFC 8470: Using Early Data in HTTP + """ + def __new__(cls, value, phrase, description=''): + obj = int.__new__(cls, value) + obj._value_ = value + + obj.phrase = phrase + obj.description = description + return obj + # informational + CONTINUE = 100, 'Continue', 'Request received, please continue' + SWITCHING_PROTOCOLS = (101, 'Switching Protocols', + 'Switching to new protocol; obey Upgrade header') + PROCESSING = 102, 'Processing' + EARLY_HINTS = 103, 'Early Hints' + # success + OK = 200, 'OK', 'Request fulfilled, document follows' + CREATED = 201, 'Created', 'Document created, URL follows' + ACCEPTED = (202, 'Accepted', + 'Request accepted, processing continues off-line') + NON_AUTHORITATIVE_INFORMATION = (203, + 'Non-Authoritative Information', 'Request fulfilled from cache') + NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows' + RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input' + PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows' + MULTI_STATUS = 207, 'Multi-Status' + ALREADY_REPORTED = 208, 'Already Reported' + IM_USED = 226, 'IM Used' + # redirection + MULTIPLE_CHOICES = (300, 'Multiple Choices', + 'Object has several resources -- see URI list') + MOVED_PERMANENTLY = (301, 'Moved Permanently', + 'Object moved permanently -- see URI list') + FOUND = 302, 'Found', 'Object moved temporarily -- see URI list' + SEE_OTHER = 303, 'See Other', 'Object moved -- see Method and URL list' + NOT_MODIFIED = (304, 'Not Modified', + 'Document has not changed since given time') + USE_PROXY = (305, 'Use Proxy', + 'You must use proxy specified in Location to access this resource') + TEMPORARY_REDIRECT = (307, 'Temporary Redirect', + 'Object moved temporarily -- see URI list') + PERMANENT_REDIRECT = (308, 'Permanent Redirect', + 'Object moved permanently -- see URI list') + # client error + BAD_REQUEST = (400, 'Bad Request', + 'Bad request syntax or unsupported method') + UNAUTHORIZED = (401, 'Unauthorized', + 'No permission -- see authorization schemes') + PAYMENT_REQUIRED = (402, 'Payment Required', + 'No payment -- see charging schemes') + FORBIDDEN = (403, 'Forbidden', + 'Request forbidden -- authorization will not help') + NOT_FOUND = (404, 'Not Found', + 'Nothing matches the given URI') + METHOD_NOT_ALLOWED = (405, 'Method Not Allowed', + 'Specified method is invalid for this resource') + NOT_ACCEPTABLE = (406, 'Not Acceptable', + 'URI not available in preferred format') + PROXY_AUTHENTICATION_REQUIRED = (407, + 'Proxy Authentication Required', + 'You must authenticate with this proxy before proceeding') + REQUEST_TIMEOUT = (408, 'Request Timeout', + 'Request timed out; try again later') + CONFLICT = 409, 'Conflict', 'Request conflict' + GONE = (410, 'Gone', + 'URI no longer exists and has been permanently removed') + LENGTH_REQUIRED = (411, 'Length Required', + 'Client must specify Content-Length') + PRECONDITION_FAILED = (412, 'Precondition Failed', + 'Precondition in headers is false') + REQUEST_ENTITY_TOO_LARGE = (413, 'Request Entity Too Large', + 'Entity is too large') + REQUEST_URI_TOO_LONG = (414, 'Request-URI Too Long', + 'URI is too long') + UNSUPPORTED_MEDIA_TYPE = (415, 'Unsupported Media Type', + 'Entity body in unsupported format') + REQUESTED_RANGE_NOT_SATISFIABLE = (416, + 'Requested Range Not Satisfiable', + 'Cannot satisfy request range') + EXPECTATION_FAILED = (417, 'Expectation Failed', + 'Expect condition could not be satisfied') + IM_A_TEAPOT = (418, 'I\'m a Teapot', + 'Server refuses to brew coffee because it is a teapot.') + MISDIRECTED_REQUEST = (421, 'Misdirected Request', + 'Server is not able to produce a response') + UNPROCESSABLE_ENTITY = 422, 'Unprocessable Entity' + LOCKED = 423, 'Locked' + FAILED_DEPENDENCY = 424, 'Failed Dependency' + TOO_EARLY = 425, 'Too Early' + UPGRADE_REQUIRED = 426, 'Upgrade Required' + PRECONDITION_REQUIRED = (428, 'Precondition Required', + 'The origin server requires the request to be conditional') + TOO_MANY_REQUESTS = (429, 'Too Many Requests', + 'The user has sent too many requests in ' + 'a given amount of time ("rate limiting")') + REQUEST_HEADER_FIELDS_TOO_LARGE = (431, + 'Request Header Fields Too Large', + 'The server is unwilling to process the request because its header ' + 'fields are too large') + UNAVAILABLE_FOR_LEGAL_REASONS = (451, + 'Unavailable For Legal Reasons', + 'The server is denying access to the ' + 'resource as a consequence of a legal demand') + # server errors + INTERNAL_SERVER_ERROR = (500, 'Internal Server Error', + 'Server got itself in trouble') + NOT_IMPLEMENTED = (501, 'Not Implemented', + 'Server does not support this operation') + BAD_GATEWAY = (502, 'Bad Gateway', + 'Invalid responses from another server/proxy') + SERVICE_UNAVAILABLE = (503, 'Service Unavailable', + 'The server cannot process the request due to a high load') + GATEWAY_TIMEOUT = (504, 'Gateway Timeout', + 'The gateway server did not receive a timely response') + HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported', + 'Cannot fulfill request') + VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates' + INSUFFICIENT_STORAGE = 507, 'Insufficient Storage' + LOOP_DETECTED = 508, 'Loop Detected' + NOT_EXTENDED = 510, 'Not Extended' + NETWORK_AUTHENTICATION_REQUIRED = (511, + 'Network Authentication Required', + 'The client needs to authenticate to gain network access') + enum._test_simple_enum(CheckedHTTPStatus, HTTPStatus) + + def test_status_lines(self): # Test HTTP status lines diff --git a/Lib/test/test_pstats.py b/Lib/test/test_pstats.py index 4f78b99..acc2fa5 100644 --- a/Lib/test/test_pstats.py +++ b/Lib/test/test_pstats.py @@ -3,6 +3,7 @@ import unittest from test import support from io import StringIO from pstats import SortKey +from enum import StrEnum, _test_simple_enum import pstats import cProfile @@ -67,6 +68,25 @@ class StatsTestCase(unittest.TestCase): self.assertEqual( self.stats.sort_type, self.stats.sort_arg_dict_default[member.value][-1]) + class CheckedSortKey(StrEnum): + CALLS = 'calls', 'ncalls' + CUMULATIVE = 'cumulative', 'cumtime' + FILENAME = 'filename', 'module' + LINE = 'line' + NAME = 'name' + NFL = 'nfl' + PCALLS = 'pcalls' + STDNAME = 'stdname' + TIME = 'time', 'tottime' + def __new__(cls, *values): + value = values[0] + obj = str.__new__(cls, value) + obj._value_ = value + for other_value in values[1:]: + cls._value2member_map_[other_value] = obj + obj._all_values = values + return obj + _test_simple_enum(CheckedSortKey, SortKey) def test_sort_starts_mix(self): self.assertRaises(TypeError, self.stats.sort_stats, diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 8f943be..06b644e 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -1,3 +1,4 @@ +import enum import errno import os import random @@ -33,6 +34,32 @@ class GenericTests(unittest.TestCase): self.assertIsInstance(sig, signal.Signals) self.assertEqual(sys.platform, "win32") + CheckedSignals = enum._old_convert_( + enum.IntEnum, 'Signals', 'signal', + lambda name: + name.isupper() + and (name.startswith('SIG') and not name.startswith('SIG_')) + or name.startswith('CTRL_'), + source=signal, + ) + enum._test_simple_enum(CheckedSignals, signal.Signals) + + CheckedHandlers = enum._old_convert_( + enum.IntEnum, 'Handlers', 'signal', + lambda name: name in ('SIG_DFL', 'SIG_IGN'), + source=signal, + ) + enum._test_simple_enum(CheckedHandlers, signal.Handlers) + + Sigmasks = getattr(signal, 'Sigmasks', None) + if Sigmasks is not None: + CheckedSigmasks = enum._old_convert_( + enum.IntEnum, 'Sigmasks', 'signal', + lambda name: name in ('SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK'), + source=signal, + ) + enum._test_simple_enum(CheckedSigmasks, Sigmasks) + @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class PosixTests(unittest.TestCase): diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index f91e000..43a1d5b 100755 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1941,6 +1941,41 @@ class GeneralModuleTests(unittest.TestCase): fileno=afile.fileno()) self.assertEqual(cm.exception.errno, errno.ENOTSOCK) + def test_addressfamily_enum(self): + import _socket, enum + CheckedAddressFamily = enum._old_convert_( + enum.IntEnum, 'AddressFamily', 'socket', + lambda C: C.isupper() and C.startswith('AF_'), + source=_socket, + ) + enum._test_simple_enum(CheckedAddressFamily, socket.AddressFamily) + + def test_socketkind_enum(self): + import _socket, enum + CheckedSocketKind = enum._old_convert_( + enum.IntEnum, 'SocketKind', 'socket', + lambda C: C.isupper() and C.startswith('SOCK_'), + source=_socket, + ) + enum._test_simple_enum(CheckedSocketKind, socket.SocketKind) + + def test_msgflag_enum(self): + import _socket, enum + CheckedMsgFlag = enum._old_convert_( + enum.IntFlag, 'MsgFlag', 'socket', + lambda C: C.isupper() and C.startswith('MSG_'), + source=_socket, + ) + enum._test_simple_enum(CheckedMsgFlag, socket.MsgFlag) + + def test_addressinfo_enum(self): + import _socket, enum + CheckedAddressInfo = enum._old_convert_( + enum.IntFlag, 'AddressInfo', 'socket', + lambda C: C.isupper() and C.startswith('AI_'), + source=_socket) + enum._test_simple_enum(CheckedAddressInfo, socket.AddressInfo) + @unittest.skipUnless(HAVE_SOCKET_CAN, 'SocketCan required for this test.') class BasicCANTest(unittest.TestCase): diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 697971e..0b8cef6 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -12,6 +12,8 @@ from test.support import warnings_helper import socket import select import time +import datetime +import enum import gc import os import errno @@ -31,7 +33,7 @@ except ImportError: ssl = import_helper.import_module("ssl") -from ssl import TLSVersion, _TLSContentType, _TLSMessageType +from ssl import TLSVersion, _TLSContentType, _TLSMessageType, _TLSAlertType Py_DEBUG = hasattr(sys, 'gettotalrefcount') Py_DEBUG_WIN32 = Py_DEBUG and sys.platform == 'win32' @@ -4697,6 +4699,155 @@ class TestSSLDebug(unittest.TestCase): s.connect((HOST, server.port)) +class TestEnumerations(unittest.TestCase): + + def test_tlsversion(self): + class CheckedTLSVersion(enum.IntEnum): + MINIMUM_SUPPORTED = _ssl.PROTO_MINIMUM_SUPPORTED + SSLv3 = _ssl.PROTO_SSLv3 + TLSv1 = _ssl.PROTO_TLSv1 + TLSv1_1 = _ssl.PROTO_TLSv1_1 + TLSv1_2 = _ssl.PROTO_TLSv1_2 + TLSv1_3 = _ssl.PROTO_TLSv1_3 + MAXIMUM_SUPPORTED = _ssl.PROTO_MAXIMUM_SUPPORTED + enum._test_simple_enum(CheckedTLSVersion, TLSVersion) + + def test_tlscontenttype(self): + class Checked_TLSContentType(enum.IntEnum): + """Content types (record layer) + + See RFC 8446, section B.1 + """ + CHANGE_CIPHER_SPEC = 20 + ALERT = 21 + HANDSHAKE = 22 + APPLICATION_DATA = 23 + # pseudo content types + HEADER = 0x100 + INNER_CONTENT_TYPE = 0x101 + enum._test_simple_enum(Checked_TLSContentType, _TLSContentType) + + def test_tlsalerttype(self): + class Checked_TLSAlertType(enum.IntEnum): + """Alert types for TLSContentType.ALERT messages + + See RFC 8466, section B.2 + """ + CLOSE_NOTIFY = 0 + UNEXPECTED_MESSAGE = 10 + BAD_RECORD_MAC = 20 + DECRYPTION_FAILED = 21 + RECORD_OVERFLOW = 22 + DECOMPRESSION_FAILURE = 30 + HANDSHAKE_FAILURE = 40 + NO_CERTIFICATE = 41 + BAD_CERTIFICATE = 42 + UNSUPPORTED_CERTIFICATE = 43 + CERTIFICATE_REVOKED = 44 + CERTIFICATE_EXPIRED = 45 + CERTIFICATE_UNKNOWN = 46 + ILLEGAL_PARAMETER = 47 + UNKNOWN_CA = 48 + ACCESS_DENIED = 49 + DECODE_ERROR = 50 + DECRYPT_ERROR = 51 + EXPORT_RESTRICTION = 60 + PROTOCOL_VERSION = 70 + INSUFFICIENT_SECURITY = 71 + INTERNAL_ERROR = 80 + INAPPROPRIATE_FALLBACK = 86 + USER_CANCELED = 90 + NO_RENEGOTIATION = 100 + MISSING_EXTENSION = 109 + UNSUPPORTED_EXTENSION = 110 + CERTIFICATE_UNOBTAINABLE = 111 + UNRECOGNIZED_NAME = 112 + BAD_CERTIFICATE_STATUS_RESPONSE = 113 + BAD_CERTIFICATE_HASH_VALUE = 114 + UNKNOWN_PSK_IDENTITY = 115 + CERTIFICATE_REQUIRED = 116 + NO_APPLICATION_PROTOCOL = 120 + enum._test_simple_enum(Checked_TLSAlertType, _TLSAlertType) + + def test_tlsmessagetype(self): + class Checked_TLSMessageType(enum.IntEnum): + """Message types (handshake protocol) + + See RFC 8446, section B.3 + """ + HELLO_REQUEST = 0 + CLIENT_HELLO = 1 + SERVER_HELLO = 2 + HELLO_VERIFY_REQUEST = 3 + NEWSESSION_TICKET = 4 + END_OF_EARLY_DATA = 5 + HELLO_RETRY_REQUEST = 6 + ENCRYPTED_EXTENSIONS = 8 + CERTIFICATE = 11 + SERVER_KEY_EXCHANGE = 12 + CERTIFICATE_REQUEST = 13 + SERVER_DONE = 14 + CERTIFICATE_VERIFY = 15 + CLIENT_KEY_EXCHANGE = 16 + FINISHED = 20 + CERTIFICATE_URL = 21 + CERTIFICATE_STATUS = 22 + SUPPLEMENTAL_DATA = 23 + KEY_UPDATE = 24 + NEXT_PROTO = 67 + MESSAGE_HASH = 254 + CHANGE_CIPHER_SPEC = 0x0101 + enum._test_simple_enum(Checked_TLSMessageType, _TLSMessageType) + + def test_sslmethod(self): + Checked_SSLMethod = enum._old_convert_( + enum.IntEnum, '_SSLMethod', 'ssl', + lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23', + source=ssl._ssl, + ) + enum._test_simple_enum(Checked_SSLMethod, ssl._SSLMethod) + + def test_options(self): + CheckedOptions = enum._old_convert_( + enum.FlagEnum, 'Options', 'ssl', + lambda name: name.startswith('OP_'), + source=ssl._ssl, + ) + enum._test_simple_enum(CheckedOptions, ssl.Options) + + + def test_alertdescription(self): + CheckedAlertDescription = enum._old_convert_( + enum.IntEnum, 'AlertDescription', 'ssl', + lambda name: name.startswith('ALERT_DESCRIPTION_'), + source=ssl._ssl, + ) + enum._test_simple_enum(CheckedAlertDescription, ssl.AlertDescription) + + def test_sslerrornumber(self): + Checked_SSLMethod = enum._old_convert_( + enum.IntEnum, '_SSLMethod', 'ssl', + lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23', + source=ssl._ssl, + ) + enum._test_simple_enum(Checked_SSLMethod, ssl._SSLMethod) + + def test_verifyflags(self): + CheckedVerifyFlags = enum._old_convert_( + enum.FlagEnum, 'VerifyFlags', 'ssl', + lambda name: name.startswith('VERIFY_'), + source=ssl._ssl, + ) + enum._test_simple_enum(CheckedVerifyFlags, ssl.VerifyFlags) + + def test_verifymode(self): + CheckedVerifyMode = enum._old_convert_( + enum.IntEnum, 'VerifyMode', 'ssl', + lambda name: name.startswith('CERT_'), + source=ssl._ssl, + ) + enum._test_simple_enum(CheckedVerifyMode, ssl.VerifyMode) + def test_main(verbose=False): if support.verbose: plats = { diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index d47cf28..0e6cbb6 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -1463,20 +1463,21 @@ class UnicodeTest(string_tests.CommonTest, PI = 3.1415926 class Int(enum.IntEnum): IDES = 15 - class Str(str, enum.Enum): + class Str(enum.StrEnum): + # StrEnum uses the value and not the name for %s etc. ABC = 'abc' # Testing Unicode formatting strings... self.assertEqual("%s, %s" % (Str.ABC, Str.ABC), - 'ABC, ABC') + 'abc, abc') self.assertEqual("%s, %s, %d, %i, %u, %f, %5.2f" % (Str.ABC, Str.ABC, Int.IDES, Int.IDES, Int.IDES, Float.PI, Float.PI), - 'ABC, ABC, 15, 15, 15, 3.141593, 3.14') + 'abc, abc, 15, 15, 15, 3.141593, 3.14') # formatting jobs delegated from the string implementation: self.assertEqual('...%(foo)s...' % {'foo':Str.ABC}, - '...ABC...') + '...abc...') self.assertEqual('...%(foo)s...' % {'foo':Int.IDES}, '...IDES...') self.assertEqual('...%(foo)i...' % {'foo':Int.IDES}, diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index d6a8333..3f56192 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -4,6 +4,7 @@ from test.support import import_helper import builtins import contextlib import copy +import enum import io import os import pickle @@ -31,6 +32,13 @@ def mock_get_command_stdout(data): class BaseTestUUID: uuid = None + def test_safe_uuid_enum(self): + class CheckedSafeUUID(enum.Enum): + safe = 0 + unsafe = -1 + unknown = None + enum._test_simple_enum(CheckedSafeUUID, py_uuid.SafeUUID) + def test_UUID(self): equal = self.assertEqual ascending = [] |