# vim:fileencoding=utf-8
# License: BSD
# Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
# globals: assrt

import encodings
ae = assrt.equal

# Test literals

ae(r'\n', '\\n')
ae('\n'.charCodeAt(0), 10)
ae('\'', "'")
ae('\76'.charCodeAt(0), 62)  # octal escapes
ae('\x2a'.charCodeAt(0), 0x2a)  # hex escapes
ae('\u2028'.charCodeAt(0), 0x2028)
ae("\U0001F431", '🐱')
ae("\U0001F431", '🐱')
ae("\N{nbsp}", '\u00a0')
ae("\N{NBSp}", '\u00a0')
for qs, aval in [['a', True], ['A', False]]:
    ae(str.islower(qs), aval)
    ae(str.islower(new String(qs)), aval)
    ae(str.isupper(qs), aval ^ True)
    ae(str.isupper(new String(qs)), aval ^ True)

# Test format()

def test():
    args = Array.prototype.slice.call(arguments, 1)
    ae(arguments[0], str.format.apply(None, args))

def test_throws():
    args = Array.prototype.slice.call(arguments)
    def f():
        return str.format.apply(None, args[1:])
    assrt.throws(f, args[0])

def test_interpolation():
    a, b, c = 1, ['x'], 30000
    ae(f'{a}', '1')
    ae(f'0{a}', '01')
    ae(f'0{a}2', '012')
    ae(f'{a}{b[-1]}', '1x')
    ae(f'{c:,d}', (30000).toLocaleString())
    ae(f'\n', '\n')
    ae(f'{a}\\{b[0]}', '1\\x')
    ae(f'x\n\ny', 'x\n\ny')
    ae(f'{a=}', 'a=1')
    somevar = {'x': 1}
    ae(f'{somevar.x=}', 'somevar.x=1')
    # Test consecutive f-string concatenation
    ae(f'a'f'b', 'ab')
    ae(f'a' f'b', 'ab')
    ae(f'a'f'{a}', 'a1')
    ae(f'{a}'   f'b', '1b')
    ae(f'{a}'f'{a}', '11')
    ae(f'a''b', 'ab')
    ae(f'{a}''b', '1b')
    # Test plain string followed by f-string (regression: was parsed as a call expression)
    ae('a' f'b', 'ab')
    ae('a' f'{a}', 'a1')
    ae('prefix ' f'{a}', 'prefix 1')
    ae('a'  f'{a}', 'a1')
    ae('a' f'{a}' 'b', 'a1b')
    ae('a' f'{a}' f'{a}', 'a11')
    ae(rf'raw{a}' f' and {a}', 'raw1 and 1')
    # Test f-string + string concatenation across newlines inside brackets
    ae(f'{a}'
       "b", '1b')
    ae(f'{a}'
       f'{a}', '11')
    ae('a'
       f'{a}', 'a1')
    ae(f'{a}'
       "b"
       f'{a}', '1b1')

somevar = 33
test('somevar=33', '{somevar=}', somevar=somevar)
somevar = {'v': 'x'}
test('somevar.v=x', '{somevar.v=}', somevar=somevar)
test(' 1 2', ' {} {}', 1, 2)
test('{ a ', '{{ {0} ', 'a')
test('11', '{0}{0}', 1)
test('12', '{a}{b}', a=1, b=2)
test('12', '{a}{0}', 2, a=1)
test('1', '{0[0]}', [1])
test('1', '{0.a.b}', {'a':{'b':1}})
test('1', '{0[a][b]}', {'a':{'b':1}})
test('x', '{}', def (): return 'x';)
test('11', '{:b}', 3)
test('0b11', '{:#b}', 3)
test((30000).toLocaleString(), '{:,d}', 30000)
# in e.g. the indian number system, this is 3,00,000
test((300000).toLocaleString(), '{:,d}', 300000)
test('1.234568e+8', '{:e}', 123456789)
test('1.23E+8', '{:.2E}', 123456789)
test('12.35%', '{:.2%}', .123456789)
test((1234).toLocaleString(), '{:,}', 1234)
test('1_234', '{:_d}', 1234)
# 6 is the default: 1234.000000% or 1234,000000%
test((1234).toLocaleString(undefined, {'minimumFractionDigits': 6}), '{:,f}', 1234)
# 1234.0% or 1234,0%
test((1234).toLocaleString(undefined, {'minimumFractionDigits': 1}) + '%', '{:,.1%}', 12.34)
test((1234.57).toLocaleString(), '{:,g}', 1234.567)
test((1234).toLocaleString(), '{:,g}', 1234)
fnum = 1234
ae(f'{fnum:,}', (1234).toLocaleString())
test('left aligned                  ', '{:<30}', 'left aligned')
test('                 right aligned', '{:>30}', 'right aligned')
test('           centered           ', '{:^30}', 'centered')
test('***********centered***********', '{:*^30}', 'centered')
test('+3.140000; -3.140000', '{:+f}; {:+f}', 3.14, -3.14)
test('3.140000; -3.140000', '{:-f}; {:-f}', 3.14, -3.14)
test(' 3.140000; -3.140000', '{: f}; {: f}', 3.14, -3.14)
test('int: 42;  hex: 2a;  oct: 52;  bin: 101010', "int: {0:d};  hex: {0:x};  oct: {0:o};  bin: {0:b}", 42)
test('int: 42;  hex: 0x2a;  oct: 0o52;  bin: 0b101010', "int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}", 42)
test('100', '{:{fill}{align}3}', 1, fill=0, align='<')
test_throws(AttributeError, '{0.a}', {})
test_throws(KeyError, '{a}', b=1)
test_throws(IndexError, '{} {}', 1)
test_throws(IndexError, '{1} {2}', 1)
test_throws(ValueError, '{1')
test_interpolation()

# Test miscellaneous services
ae('Abc', str.capitalize('aBC'))
ae(' 1 ', str.center('1', 3))
ae(2, str.count('xyx', 'x'))
ae(1, str.count('xyx', 'x', 2))
ae(True, str.endswith('a', ''))
ae(True, str.endswith('', ''))
ae(False, str.endswith('a', 'ab'))
ae(True, str.endswith('e', ['f', 'e']))
ae(True, str.startswith('a', ''))
ae(True, str.startswith('', ''))
ae(False, str.startswith('a', 'ab'))
ae(True, str.startswith('e', ['f', 'e']))
ae(1, str.find('ab', 'b'))
ae(2, str.rfind('abbc', 'b'))
ae(1, str.index('ab', 'b'))
ae(-1, str.find('abcd', 'b', 2))
ae(-1, str.find('abcd', 'b', 0, 1))
ae(-1, str.find('abcd', 'bcd', 0, 2))
ae(-1, str.rfind('abcd', 'b', 2))
ae(-1, str.rfind('abcd', 'b', 0, 1))
ae(3, str.rfind('abcd', 'd'))
ae('1,2', str.join(',', [1, 2]))
ae('1,2', str.join(',', iter([1, 2])))
ae('a  ', str.ljust('a', 3))
ae('  a', str.rjust('a', 3))
ae('A', str.upper('a'))
ae('a', str.lower('A'))
ae('a', str.lstrip('  a'))
ae('a', str.lstrip('a'))
ae('a', str.rstrip('a   '))
ae('a', str.rstrip('a'))
ae('a', str.strip('  a   '))
ae('', str.strip(' '))
ae('', str.lstrip(' '))
ae('', str.rstrip(' '))
assrt.deepEqual(['1', ',', '2,3'], str.partition('1,2,3', ','))
assrt.deepEqual(['1,2,3', '', ''], str.partition('1,2,3', ' '))
assrt.deepEqual(['1,2', ',', '3'], str.rpartition('1,2,3', ','))
assrt.deepEqual(['', '', '1,2,3'], str.rpartition('1,2,3', ' '))
assrt.deepEqual(['1', ',2'], str.split('1,,2', ',', 1))
assrt.deepEqual(['1', '2', '3'], str.split('1  2 3'))
assrt.deepEqual(['1', '2 3'], str.split('1  2 3', None, 1))
assrt.deepEqual(['1', '2 \t3'], str.split('1 2 \t3', None, 1))
assrt.deepEqual(['-a--b-c', ''], str.rsplit('-a--b-c-', '-', 1))
assrt.deepEqual(['', 'a', 'b'], str.rsplit(',a,b', ','))
assrt.deepEqual([',a', 'b'], str.rsplit(',a,b', ',', 1))
assrt.deepEqual(['x,a', 'b'], str.rsplit('x,a,b', ',', 1))
assrt.deepEqual([' a b', 'c'], str.rsplit(' a b c ', None, 1))
assrt.deepEqual([' a bx', 'c'], str.rsplit(' a bx c ', None, 1))
for x in ['a\nb', 'a\r\nb', 'a\rb']:
    assrt.deepEqual(['a', 'b'], str.splitlines(x))
assrt.deepEqual(['a', '', 'b'], str.splitlines('a\n\rb'))
assrt.deepEqual(['a\n', 'b'], str.splitlines('a\nb', True))
assrt.deepEqual(['a\r\n', 'b'], str.splitlines('a\r\nb', True))
assrt.deepEqual(['s', "🐱", 'a', '\u2028'], list(str.uchrs('s🐱a\u2028')))
assrt.deepEqual([[0, 's'], [1, "🐱"], [3, 'a'], [4, '\u2028']], list(str.uchrs('s🐱a\u2028', True)))
ae('bbb', str.replace('aaa', 'a', 'b'))
ae('baa', str.replace('aaa', 'a', 'b', 1))
ae('bba', str.replace('aaa', 'a', 'b', 2))
ae('aaa', str.replace('aaa', 'a', 'a'))
ae('', str.replace('aaa', 'a', ''))
ae('a1B', str.swapcase('A1b'))
ae('001', str.zfill('1', 3))
ae('111', str.zfill('111', 2))
ae('a\u2028', str.uslice('s🐱a\u2028', 2))
ae(4, str.ulen('s🐱a\u2028', 2))

for f in (str, repr):
    ae(f(True), 'True')
    ae(f(False), 'False')
    ae(f(None), 'None')
    ae(f(1), '1')
    ae(f([1,'2']), '[1, "2"]')
    ae(f({1:[1, '2']}), '{"1":[1, "2"]}')
    ae(f({1:'a', 2:'b'}), '{"1":"a", "2":"b"}')
ae(str('a'), 'a')
ae(repr('a'), '"a"')

bytes = list(range(256))
assrt.deepEqual(bytes, list(encodings.base64decode(encodings.base64encode(bytes))))
assrt.deepEqual(bytes, list(encodings.unhexlify(encodings.hexlify(bytes))))
for k in ['abc', "mūs", '', 's🐱a\u2028']:
    bytes = encodings.utf8_encode(k)
    ae(encodings.utf8_decode(bytes), k)
    ae(encodings.utf8_decode(encodings.utf8_encode_js(k)), k)
    assrt.deepEqual(list(bytes), list(encodings.base64decode(encodings.base64encode(bytes))))

from pythonize import strings
strings()
ae('{0} {a}'.format(1, a=2), str.format('{0} {a}', 1, a=2))
ae(' x '.strip(), str.strip(' x '))
ae(','.join([1,2,3]), str.join(',', [1,2,3]))
ae('11111'.count('1', start=1, end=1), str.count('11111', '1', start=1, end=1))
ae('{{}}'.format(), '{}')
ae('{x}}}'.format(x=1), '1}')
a = 1
ae(f'{{ {a} }}', '{ 1 }')
