1# 2# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions 6# are met: 7# 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26# 27 28 29# Generate PEP-3101 format strings. 30 31 32import os, sys, locale, random 33import platform, subprocess 34from test.support import import_fresh_module 35from distutils.spawn import find_executable 36 37C = import_fresh_module('decimal', fresh=['_decimal']) 38P = import_fresh_module('decimal', blocked=['_decimal']) 39 40 41windows_lang_strings = [ 42 "chinese", "chinese-simplified", "chinese-traditional", "czech", "danish", 43 "dutch", "belgian", "english", "australian", "canadian", "english-nz", 44 "english-uk", "english-us", "finnish", "french", "french-belgian", 45 "french-canadian", "french-swiss", "german", "german-austrian", 46 "german-swiss", "greek", "hungarian", "icelandic", "italian", "italian-swiss", 47 "japanese", "korean", "norwegian", "norwegian-bokmal", "norwegian-nynorsk", 48 "polish", "portuguese", "portuguese-brazil", "russian", "slovak", "spanish", 49 "spanish-mexican", "spanish-modern", "swedish", "turkish", 50] 51 52preferred_encoding = { 53 'cs_CZ': 'ISO8859-2', 54 'cs_CZ.iso88592': 'ISO8859-2', 55 'czech': 'ISO8859-2', 56 'eesti': 'ISO8859-1', 57 'estonian': 'ISO8859-1', 58 'et_EE': 'ISO8859-15', 59 'et_EE.ISO-8859-15': 'ISO8859-15', 60 'et_EE.iso885915': 'ISO8859-15', 61 'et_EE.iso88591': 'ISO8859-1', 62 'fi_FI.iso88591': 'ISO8859-1', 63 'fi_FI': 'ISO8859-15', 64 'fi_FI@euro': 'ISO8859-15', 65 'fi_FI.iso885915@euro': 'ISO8859-15', 66 'finnish': 'ISO8859-1', 67 'lv_LV': 'ISO8859-13', 68 'lv_LV.iso885913': 'ISO8859-13', 69 'nb_NO': 'ISO8859-1', 70 'nb_NO.iso88591': 'ISO8859-1', 71 'bokmal': 'ISO8859-1', 72 'nn_NO': 'ISO8859-1', 73 'nn_NO.iso88591': 'ISO8859-1', 74 'no_NO': 'ISO8859-1', 75 'norwegian': 'ISO8859-1', 76 'nynorsk': 'ISO8859-1', 77 'ru_RU': 'ISO8859-5', 78 'ru_RU.iso88595': 'ISO8859-5', 79 'russian': 'ISO8859-5', 80 'ru_RU.KOI8-R': 'KOI8-R', 81 'ru_RU.koi8r': 'KOI8-R', 82 'ru_RU.CP1251': 'CP1251', 83 'ru_RU.cp1251': 'CP1251', 84 'sk_SK': 'ISO8859-2', 85 'sk_SK.iso88592': 'ISO8859-2', 86 'slovak': 'ISO8859-2', 87 'sv_FI': 'ISO8859-1', 88 'sv_FI.iso88591': 'ISO8859-1', 89 'sv_FI@euro': 'ISO8859-15', 90 'sv_FI.iso885915@euro': 'ISO8859-15', 91 'uk_UA': 'KOI8-U', 92 'uk_UA.koi8u': 'KOI8-U' 93} 94 95integers = [ 96 "", 97 "1", 98 "12", 99 "123", 100 "1234", 101 "12345", 102 "123456", 103 "1234567", 104 "12345678", 105 "123456789", 106 "1234567890", 107 "12345678901", 108 "123456789012", 109 "1234567890123", 110 "12345678901234", 111 "123456789012345", 112 "1234567890123456", 113 "12345678901234567", 114 "123456789012345678", 115 "1234567890123456789", 116 "12345678901234567890", 117 "123456789012345678901", 118 "1234567890123456789012", 119] 120 121numbers = [ 122 "0", "-0", "+0", 123 "0.0", "-0.0", "+0.0", 124 "0e0", "-0e0", "+0e0", 125 ".0", "-.0", 126 ".1", "-.1", 127 "1.1", "-1.1", 128 "1e1", "-1e1" 129] 130 131# Get the list of available locales. 132if platform.system() == 'Windows': 133 locale_list = windows_lang_strings 134else: 135 locale_list = ['C'] 136 if os.path.isfile("/var/lib/locales/supported.d/local"): 137 # On Ubuntu, `locale -a` gives the wrong case for some locales, 138 # so we get the correct names directly: 139 with open("/var/lib/locales/supported.d/local") as f: 140 locale_list = [loc.split()[0] for loc in f.readlines() \ 141 if not loc.startswith('#')] 142 elif find_executable('locale'): 143 locale_list = subprocess.Popen(["locale", "-a"], 144 stdout=subprocess.PIPE).communicate()[0] 145 try: 146 locale_list = locale_list.decode() 147 except UnicodeDecodeError: 148 # Some distributions insist on using latin-1 characters 149 # in their locale names. 150 locale_list = locale_list.decode('latin-1') 151 locale_list = locale_list.split('\n') 152try: 153 locale_list.remove('') 154except ValueError: 155 pass 156 157# Debian 158if os.path.isfile("/etc/locale.alias"): 159 with open("/etc/locale.alias") as f: 160 while 1: 161 try: 162 line = f.readline() 163 except UnicodeDecodeError: 164 continue 165 if line == "": 166 break 167 if line.startswith('#'): 168 continue 169 x = line.split() 170 if len(x) == 2: 171 if x[0] in locale_list: 172 locale_list.remove(x[0]) 173 174# FreeBSD 175if platform.system() == 'FreeBSD': 176 # http://www.freebsd.org/cgi/query-pr.cgi?pr=142173 177 # en_GB.US-ASCII has 163 as the currency symbol. 178 for loc in ['it_CH.ISO8859-1', 'it_CH.ISO8859-15', 'it_CH.UTF-8', 179 'it_IT.ISO8859-1', 'it_IT.ISO8859-15', 'it_IT.UTF-8', 180 'sl_SI.ISO8859-2', 'sl_SI.UTF-8', 181 'en_GB.US-ASCII']: 182 try: 183 locale_list.remove(loc) 184 except ValueError: 185 pass 186 187# Print a testcase in the format of the IBM tests (for runtest.c): 188def get_preferred_encoding(): 189 loc = locale.setlocale(locale.LC_CTYPE) 190 if loc in preferred_encoding: 191 return preferred_encoding[loc] 192 else: 193 return locale.getpreferredencoding() 194 195def printit(testno, s, fmt, encoding=None): 196 if not encoding: 197 encoding = get_preferred_encoding() 198 try: 199 result = format(P.Decimal(s), fmt) 200 fmt = str(fmt.encode(encoding))[2:-1] 201 result = str(result.encode(encoding))[2:-1] 202 if "'" in result: 203 sys.stdout.write("xfmt%d format %s '%s' -> \"%s\"\n" 204 % (testno, s, fmt, result)) 205 else: 206 sys.stdout.write("xfmt%d format %s '%s' -> '%s'\n" 207 % (testno, s, fmt, result)) 208 except Exception as err: 209 sys.stderr.write("%s %s %s\n" % (err, s, fmt)) 210 211 212# Check if an integer can be converted to a valid fill character. 213def check_fillchar(i): 214 try: 215 c = chr(i) 216 c.encode('utf-8').decode() 217 format(P.Decimal(0), c + '<19g') 218 return c 219 except: 220 return None 221 222# Generate all unicode characters that are accepted as 223# fill characters by decimal.py. 224def all_fillchars(): 225 for i in range(0, 0x110002): 226 c = check_fillchar(i) 227 if c: yield c 228 229# Return random fill character. 230def rand_fillchar(): 231 while 1: 232 i = random.randrange(0, 0x110002) 233 c = check_fillchar(i) 234 if c: return c 235 236# Generate random format strings 237# [[fill]align][sign][#][0][width][.precision][type] 238def rand_format(fill, typespec='EeGgFfn%'): 239 active = sorted(random.sample(range(7), random.randrange(8))) 240 have_align = 0 241 s = '' 242 for elem in active: 243 if elem == 0: # fill+align 244 s += fill 245 s += random.choice('<>=^') 246 have_align = 1 247 elif elem == 1: # sign 248 s += random.choice('+- ') 249 elif elem == 2 and not have_align: # zeropad 250 s += '0' 251 elif elem == 3: # width 252 s += str(random.randrange(1, 100)) 253 elif elem == 4: # thousands separator 254 s += ',' 255 elif elem == 5: # prec 256 s += '.' 257 s += str(random.randrange(100)) 258 elif elem == 6: 259 if 4 in active: c = typespec.replace('n', '') 260 else: c = typespec 261 s += random.choice(c) 262 return s 263 264# Partially brute force all possible format strings containing a thousands 265# separator. Fall back to random where the runtime would become excessive. 266# [[fill]align][sign][#][0][width][,][.precision][type] 267def all_format_sep(): 268 for align in ('', '<', '>', '=', '^'): 269 for fill in ('', 'x'): 270 if align == '': fill = '' 271 for sign in ('', '+', '-', ' '): 272 for zeropad in ('', '0'): 273 if align != '': zeropad = '' 274 for width in ['']+[str(y) for y in range(1, 15)]+['101']: 275 for prec in ['']+['.'+str(y) for y in range(15)]: 276 # for type in ('', 'E', 'e', 'G', 'g', 'F', 'f', '%'): 277 type = random.choice(('', 'E', 'e', 'G', 'g', 'F', 'f', '%')) 278 yield ''.join((fill, align, sign, zeropad, width, ',', prec, type)) 279 280# Partially brute force all possible format strings with an 'n' specifier. 281# [[fill]align][sign][#][0][width][,][.precision][type] 282def all_format_loc(): 283 for align in ('', '<', '>', '=', '^'): 284 for fill in ('', 'x'): 285 if align == '': fill = '' 286 for sign in ('', '+', '-', ' '): 287 for zeropad in ('', '0'): 288 if align != '': zeropad = '' 289 for width in ['']+[str(y) for y in range(1, 20)]+['101']: 290 for prec in ['']+['.'+str(y) for y in range(1, 20)]: 291 yield ''.join((fill, align, sign, zeropad, width, prec, 'n')) 292 293# Generate random format strings with a unicode fill character 294# [[fill]align][sign][#][0][width][,][.precision][type] 295def randfill(fill): 296 active = sorted(random.sample(range(5), random.randrange(6))) 297 s = '' 298 s += str(fill) 299 s += random.choice('<>=^') 300 for elem in active: 301 if elem == 0: # sign 302 s += random.choice('+- ') 303 elif elem == 1: # width 304 s += str(random.randrange(1, 100)) 305 elif elem == 2: # thousands separator 306 s += ',' 307 elif elem == 3: # prec 308 s += '.' 309 s += str(random.randrange(100)) 310 elif elem == 4: 311 if 2 in active: c = 'EeGgFf%' 312 else: c = 'EeGgFfn%' 313 s += random.choice(c) 314 return s 315 316# Generate random format strings with random locale setting 317# [[fill]align][sign][#][0][width][,][.precision][type] 318def rand_locale(): 319 try: 320 loc = random.choice(locale_list) 321 locale.setlocale(locale.LC_ALL, loc) 322 except locale.Error as err: 323 pass 324 active = sorted(random.sample(range(5), random.randrange(6))) 325 s = '' 326 have_align = 0 327 for elem in active: 328 if elem == 0: # fill+align 329 s += chr(random.randrange(32, 128)) 330 s += random.choice('<>=^') 331 have_align = 1 332 elif elem == 1: # sign 333 s += random.choice('+- ') 334 elif elem == 2 and not have_align: # zeropad 335 s += '0' 336 elif elem == 3: # width 337 s += str(random.randrange(1, 100)) 338 elif elem == 4: # prec 339 s += '.' 340 s += str(random.randrange(100)) 341 s += 'n' 342 return s 343