
semver = require 'semver'
should = require 'should'
printf = require '../lib/printf'

describe 'sprintf', ->
  
  it 'Specifier: b', ->
    printf('%b', 123).should.eql '1111011'

  it 'Flag: (space)', ->
    printf('% d', 42).should.eql    ' 42'
    printf('% d', -42).should.eql   '-42'
    printf('% 5d', 42).should.eql   '   42'
    printf('% 5d', -42).should.eql  '  -42'
    printf('% 15d', 42).should.eql  '             42'
    printf('% 15d', -42).should.eql '            -42'

  it 'Flag: +', ->
    printf('%+d', 42).should.eql    '+42'
    printf('%+d', -42).should.eql   '-42'
    printf('%+5d', 42).should.eql   '  +42'
    printf('%+5d', -42).should.eql  '  -42'
    printf('%+15d', 42).should.eql  '            +42'
    printf('%+15d', -42).should.eql '            -42'

  it 'Flag: 0', ->
    printf('%0d', 42).should.eql    '42'
    printf('%0d', -42).should.eql   '-42'
    printf('%05d', 42).should.eql   '00042'
    printf('%05d', -42).should.eql  '-00042'
    printf('%015d', 42).should.eql  '000000000000042'
    printf('%015d', -42).should.eql '-000000000000042'

  it 'Flag: -', ->
    printf('%-d', 42).should.eql     '42'
    printf('%-d', -42).should.eql    '-42'
    printf('%-5d', 42).should.eql    '42   '
    printf('%-5d', -42).should.eql   '-42  '
    printf('%-15d', 42).should.eql   '42             '
    printf('%-15d', -42).should.eql  '-42            '
    printf('%-0d', 42).should.eql    '42'
    printf('%-0d', -42).should.eql   '-42'
    printf('%-05d', 42).should.eql   '42   '
    printf('%-05d', -42).should.eql  '-42  '
    printf('%-015d', 42).should.eql  '42             '
    printf('%-015d', -42).should.eql '-42            '
    printf('%0-d', 42).should.eql    '42'
    printf('%0-d', -42).should.eql   '-42'
    printf('%0-5d', 42).should.eql   '42   '
    printf('%0-5d', -42).should.eql  '-42  '
    printf('%0-15d', 42).should.eql  '42             '
    printf('%0-15d', -42).should.eql '-42            '

  it 'Precision', ->
    printf('%d', 42.8952).should.eql     '42'
    printf('%.2d', 42.8952).should.eql   '42' # Note: the %d format is an int
    printf('%.2i', 42.8952).should.eql   '42'
    printf('%.2f', 42.8952).should.eql   '42.90'
    printf('%.2F', 42.8952).should.eql   '42.90'
    printf('%.10f', 42.8952).should.eql  '42.8952000000'
    printf('%1.2f', 42.8952).should.eql  '42.90'
    printf('%6.2f', 42.8952).should.eql  ' 42.90'
    printf('%06.2f', 42.8952).should.eql '042.90'
    printf('%+6.2f', 42.8952).should.eql '+42.90'
    printf('%5.10f', 42.8952).should.eql '42.8952000000'
    printf('%1.4g', 1.06800e-10).should.eql '1.068e-10'

  it 'Bases', ->
    printf('%c', 0x7f).should.eql ''
    error = false
    try
      printf '%c', -100
    catch e
      e.message.should.eql 'invalid character code passed to %c in printf'
      error = true
    error.should.be.true
    error = false
    try
      printf '%c', 0x200000
    catch e
      e.message.should.eql 'invalid character code passed to %c in printf'
      error = true
    error.should.be.true

  it 'Mapping', ->
    # %1$s format
    printf('%1$').should.eql '%1$'
    printf('%0$s').should.eql '%0$s'
    printf('%1$s %2$s', 'Hot', 'Pocket').should.eql 'Hot Pocket'
    printf('%1$.1f %2$s %3$ss', 12, 'Hot', 'Pocket').should.eql '12.0 Hot Pockets'
    printf('%1$*.f', '42', 3).should.eql ' 42'
    error = false
    try
      printf '%2$*s', 'Hot Pocket'
    catch e
      e.message.should.eql "got 1 printf arguments, insufficient for '%2$*s'"
      error = true
    error.should.be.true
    # %(map)s format
    printf('%(foo', {}).should.eql '%(foo'
    printf('%(temperature)s %(crevace)s',
      temperature: 'Hot'
      crevace: 'Pocket'
    ).should.eql 'Hot Pocket'
    printf('%(quantity).1f %(temperature)s %(crevace)ss',
      quantity: 12
      temperature: 'Hot'
      crevace: 'Pocket'
    ).should.eql '12.0 Hot Pockets'
    printf('nested values %(nested.foo)s %(nested.bar.baz)d',
      nested:
        foo: 'work'
        bar:
          baz: 2
    ).should.eql 'nested values work 2'
    error = false
    try
      printf '%(foo)s', 42
    catch e
      e.message.should.eql 'format requires a mapping'
      error = true
    error.should.be.true
    error = false
    try
      printf '%(foo)s %(bar)s', 'foo', 42
    catch e
      e.message.should.eql 'format requires a mapping'
      error = true
    error.should.be.true
    error = false
    try
      printf '%(foo)*s',
        foo: 'Hot Pocket'
    catch e
      e.message.should.eql '* width not supported in mapped formats'
      error = true
    error.should.be.true

  it 'Positionals', ->
    printf('%*s', 'foo', 4).should.eql ' foo'
    printf('%*.*f', 3.14159265, 10, 2).should.eql '      3.14'
    printf('%0*.*f', 3.14159265, 10, 2).should.eql '0000003.14'
    printf('%-*.*f', 3.14159265, 10, 2).should.eql '3.14      '
    error = false
    try
      printf '%*s', 'foo', 'bar'
    catch e
      e.message.should.eql 'the argument for * width at position 2 is not a number in %*s'
      error = true
    error.should.be.true
    error = false
    try
      printf '%10.*f', 'foo', 42
    catch e
      e.message.should.eql "format argument 'foo' not a float; parseFloat returned NaN"
      error = true
    error.should.be.true

  it 'vs. Formatter', ->
    i = 0
    while i < 1000
      printf '%d %s Pockets', i, 'Hot'
      i++

  it 'Formatter', ->
    str = new printf.Formatter('%d %s Pockets')
    i = 0
    while i < 1000
      str.format i, 'Hot'
      i++

  it 'Miscellaneous', ->
    printf('+%s+', 'hello').should.eql '+hello+'
    printf('+%d+', 10).should.eql '+10+'
    printf('%c', 'a').should.eql 'a'
    printf('%c', 34).should.eql '\"'
    printf('%c', 36).should.eql '$'
    printf('%d', 10).should.eql '10'
    error = false
    try
      printf '%s%s', 42
    catch e
      e.message.should.eql "got 1 printf arguments, insufficient for '%s%s'"
      error = true
    error.should.be.true
    error = false
    try
      printf '%c'
    catch e
      e.message.should.eql "got 0 printf arguments, insufficient for '%c'"
      error = true
    error.should.be.true
    printf('%10', 42).should.eql '%10'

  it 'Escape', ->
    printf('%d %', 10).should.eql '10 %'

  it 'Object inspection', ->
    test =
      foo:
        is:
          bar: true
          baz: false
        isnot:
          array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
        maybe: undefined
    printf('%.0O', test).replace(/\s+/g, ' ').should.eql '{ foo: [Object] }'
    printf('%#O', test.foo.isnot.array).should.eql '[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ]'
    # Object inspect serialize object in different order when showHidden is true
    printf('%+O', test.foo.is).should.eql '{ bar: \u001b[33mtrue\u001b[39m, baz: \u001b[33mfalse\u001b[39m }'
    return if semver.lt process.version, 'v0.9.0'
    printf('%O', test).replace(/\s+/g, ' ').should.eql '{ foo: { is: { bar: true, baz: false }, isnot: { array: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, [length]: 10 ] }, maybe: undefined } }'
    if semver.lt process.version, 'v8.0.0'
    then printf('%.2O', test).replace(/\s+/g, ' ').should.eql '{ foo: { is: { bar: true, baz: false }, isnot: { array: [Object] }, maybe: undefined } }'
    else printf('%.2O', test).replace(/\s+/g, ' ').should.eql '{ foo: { is: { bar: true, baz: false }, isnot: { array: [Array] }, maybe: undefined } }'
