/* global artifacts, contract, before, it, assert */
/* eslint-disable prefer-reflect */

let big = require('bignumber');
let testdata = require('./helpers/FormulaTestData.js');
let testArrays = require('./helpers/FormulaTestArrays.js');
let BancorFormula = artifacts.require('./BancorFormula.sol');

function isThrow(error) {
    return error.toString().indexOf('invalid JUMP') != -1 || error.toString().indexOf('VM Exception while executing eth_call: invalid opcode') != -1;
}

function expectedThrow(error) {
    if (isThrow(error))
        console.log('\tExpected throw. Test succeeded.');
    else
        assert(false, error.toString());
}

function _hex(hexstr) {
    if (hexstr.startsWith('0x'))
        hexstr = hexstr.substr(2);

    return new big.BigInteger(hexstr, 16);
}

function num(numericStr) {
    return new big.BigInteger(numericStr, 10);
}

contract('BancorFormula', () => {
    for (var precision = 0; precision < 128; precision++) {
        it('handles legal input ranges (fixedExp)', () => {
            return BancorFormula.deployed().then((instance) => {
                let ok = testArrays.maxExpArray[precision];
                return instance.fixedExp.call(ok, precision);
            }).then((retval) => {
                let expected = testArrays.maxValArray[precision];
                assert.equal(expected.toString(16), retval.toString(16), 'Wrong result for fixedExp at limit');
            });
        });
        it('throws outside input range (fixedExp)', () => {
            return BancorFormula.deployed().then((instance) => {
                let err = testArrays.maxExpArray[precision] + 1;
                return instance.fixedExp.call(err, precision);
            }).then(() => {
                assert(false, "was supposed to throw but didn't.");
            }).catch(expectedThrow);
        });
    }

    let purchaseTest = (k) => {
        let [S, R, F, E, expect, exact] = k;
        S = num(S), R = num(R), F = num(F), E = num(E), expect = num(expect);

        it('Should get correct amount of tokens when purchasing', () => {
            return BancorFormula.deployed()
                .then((f) => {
                    return f.calculatePurchaseReturn.call(S, R, F, E);
                })
                .then((retval) => {
                    // assert(retval.valueOf() <= expect,"Purchase return "+retval+" should be <="+expect+" ( "+exact+"). [S,R,F,E] "+[S,R,F,E]);
                    assert(retval.eq(expect), 'Purchase return ' + retval + ' should be ==' + expect + ' ( ' + exact + '). [S,R,F,E] ' + [S, R, F, E]);
                })
                .catch((error) => {
                    if (isThrow(error)) {
                        if (expect.valueOf() == 0)
                            assert(true, 'Expected throw');
                        else
                            assert(false, 'Sale return generated throw');
                    }
                    else {
                        assert(false, error.toString());
                    }
                });
        });
    };

    let saleTest = (k) => {
        let [S, R, F, T, expect, exact] = k;
        S = num(S), R = num(R), F = num(F), T = num(T), expect = num(expect);

        it('Should get correct amount of Ether when selling', () => {
            return BancorFormula.deployed().then(
                (f) => {
                    return f.calculateSaleReturn.call(S, R, F, T);
                })
                .then((retval) => {
                    assert(retval.eq(expect), 'Sale return ' + retval + ' should be ==' + expect + ' ( ' + exact + '). [S,R,F,T] ' + [S, R, F, T]);
                })
                .catch((error) => {
                    if (isThrow(error)) {
                        if (expect.valueOf() == 0)
                            assert(true, 'Expected throw');
                        else
                            assert(false, 'Sale return generated throw');
                    }
                    else {
                        assert(false, error.toString());
                    }
                });
        });
    };

    let purchaseThrowTest = (k) => {
        let [S, R, F, E, expect, exact] = k;

        it('Should throw on out of bounds', () => {
            return BancorFormula.deployed()
                .then((f) => {
                    return f.calculatePurchaseReturn.call(S, R, F, E);
                })
                .then((retval) => {
                    assert(false, "was supposed to throw but didn't: [S,R,F,E] " + [S, R, F, E] + ' => ' + retval.toString(16));
                })
                .catch(expectedThrow);
        });
    };

    let saleThrowTest = (k) => {
        let [S, R, F, T, expect, exact] = k;

        it('Should throw on out of bounds', () => {
            return BancorFormula.deployed()
                .then((f) => {
                    return f.calculateSaleReturn.call(S, R, F, T);
                })
                .then((retval) => {
                    assert(false, "was supposed to throw but didn't: [S,R,F,T] " + [S, R, F, T] + '=> ' + retval.toString(16));
                })
                .catch(expectedThrow);
        });
    };

    testdata.purchaseReturns.forEach(purchaseTest);
    testdata.saleReturns.forEach(saleTest);

    testdata.purchaseReturnsLarge.forEach(purchaseTest);
    testdata.saleReturnsLarge.forEach(saleTest);
    testdata.randomPurchaseReturns.forEach(purchaseTest);
    testdata.randomSaleReturns.forEach(saleTest);

    testdata.purchaseReturnExpectedThrows.forEach(purchaseThrowTest);
    testdata.saleReturnExpectedThrows.forEach(saleThrowTest);
});

@@ -1453,34 +1453,28 @@
 it('
-throws outside
+verifies
  input 
-range
+limit
  (fi
@@ -1471,32 +1471,38 @@
  limit (fixedExp
+Unsafe
 )', () =%3E %7B%0A    
@@ -1586,14 +1586,47 @@
 let 
-err = 
+retval0 = instance.fixedExpUnsafe.call(
 test
@@ -1657,17 +1657,29 @@
 sion%5D + 
-1
+0, precision)
 ;%0A      
@@ -1680,38 +1680,45 @@
                 
-return
+let retval1 =
  instance.fixedE
@@ -1723,29 +1723,112 @@
 dExp
-.call(err, precision)
+Unsafe.call(testArrays.maxExpArray%5Bprecision%5D + 1, precision);%0A                return %5Bretval0, retval1%5D
 ;%0A  
@@ -1846,16 +1846,23 @@
 ).then((
+retvals
 ) =%3E %7B%0A 
@@ -1887,87 +1887,98 @@
 ert(
-false, %22was supposed to throw but didn't.%22);%0A            %7D).catch(expectedThrow
+retvals%5B0%5D %3E retvals%5B1%5D, 'Result indicates wrong limit for fixedExpUnsafe');%0A            %7D
 );%0A 

Verify the limit of fixedExpUnsafe