/* global describe, it */

'use strict'

var assert = require('assert'),
    sprintfjs = require('../src/sprintf.js'),
    sprintf = sprintfjs.sprintf,
    vsprintf = sprintfjs.vsprintf

function should_throw(format,args,err) {
    assert.throws(function() { vsprintf(format,args) }, err)
}

function should_not_throw(format,args) {
    assert.doesNotThrow(function() { vsprintf(format,args) })
}

describe('sprintfjs cache', function() {

    it('should not throw Error (cache consistency)', function() {
        // redefine object properties to ensure that is not affect to the cache
        sprintf('hasOwnProperty')
        sprintf('constructor')
        should_not_throw('%s', ['caching...'])
        should_not_throw('%s', ['crash?'])
    })
})

describe('sprintfjs', function() {

    it('should throw SyntaxError for placeholders', function() {
        should_throw('%', [], SyntaxError)
        should_throw('%A', [], SyntaxError)
        should_throw('%s%', [], SyntaxError)
        should_throw('%(s', [], SyntaxError)
        should_throw('%)s', [], SyntaxError)
        should_throw('%$s', [], SyntaxError)
        should_throw('%()s', [], SyntaxError)
        should_throw('%(12)s', [], SyntaxError)
    })

    var numeric = 'bcdiefguxX'.split('')
    numeric.forEach(function(specifier) {
        var fmt = sprintf('%%%s',specifier)
        it(fmt + ' should throw TypeError for invalid numbers', function() {
            should_throw(fmt, [], TypeError)
            should_throw(fmt, ['str'], TypeError)
            should_throw(fmt, [{}], TypeError)
            should_throw(fmt, ['s'], TypeError)
        })

        it(fmt + ' should not throw TypeError for something implicitly castable to number', function() {
            should_not_throw(fmt, [1/0])
            should_not_throw(fmt, [true])
            should_not_throw(fmt, [[1]])
            should_not_throw(fmt, ['200'])
            should_not_throw(fmt, [null])
        })
    })

    it('should not throw Error for expression which evaluates to undefined', function() {
        should_not_throw("%(x.y)s", {x : {}})
    })

    it('should throw own Error when expression evaluation would raise TypeError', function() {
        var fmt = "%(x.y)s"
        try {
            sprintf(fmt, {})
        } catch (e) {
            assert(e.message.indexOf('[sprintf]') !== -1)
        }
    })

    it('should not throw when accessing properties on the prototype', function() {
        function C() { }
        C.prototype = {
            get x() { return 2 },
            set y(v) { /*Noop */}
        }
        var c = new C()
        should_not_throw("%(x)s", c)
        should_not_throw("%(y)s", c)
    })
})
