text: import assert from 'assert'
  import { maxArgumentCount, memoize, memoizeCompare } from '../../../src/utils/function.js'
  import { deepStrictEqual } from '../../../src/utils/object.js'
  
  describe('util.function', function () {
    describe('memoize', function () {
      it('should memoize a function with one argument', function () {
        const f = function (x) { return x * x }
  
        const m = memoize(f)
  
        assert.strictEqual(m(2), 4)
        assert.strictEqual(m(3), 9)
      })
  
      it('should memoize a function with two arguments', function () {
        const f = function (x, y) { return x * y }
  
        const m = memoize(f)
  
        assert.strictEqual(m(2, 3), 6)
  
        // hash should differ
        assert.strictEqual(m(1, 23), 23)
        assert.strictEqual(m(12, 3), 36)
      })
  
      it('should memoize a function with objects as arguments', function () {
        const f = function (obj) { return obj.x * obj.y }
  
        const m = memoize(f)
  
        assert.strictEqual(m({ x: 2, y: 3 }), 6)
        assert.deepStrictEqual([...m.cache.values.keys()], ['[{"x":2,"y":3}]'])
        assert.strictEqual(m.cache.values.get('[{"x":2,"y":3}]'), 6)
      })
  
      it('should memoize a function with a custom hashIt function', function () {
        const f = function (obj) { return obj.id }
        const hashIt = function (args) {
          return 'id:' + args[0].id
        }
  
        const m = memoize(f, { hasher: hashIt })
  
        assert.strictEqual(m({ id: 2 }), 2)
        assert.deepStrictEqual([...m.cache.values.keys()], ['id:2'])
        assert.strictEqual(m.cache.values.get('id:2'), 2)
      })
  
      it('should really return the cached result', function () {
        let a = 2
        const f = function (x) { return a } // trick: no pure function
  
        const m = memoize(f)
  
        assert.strictEqual(m(4), 2)
        a = 3
        assert.strictEqual(m(4), 2)
      })
    })
  
    it('should limit the number of values stored', function () {
      let a = 1
      const f = function (x) { a++; return a } // trick: no pure function
  
      const m = memoize(f, { limit: 2 })
  
      assert.strictEqual(m(1), 2)
      assert.strictEqual(m(2), 3)
      // this should evict m(1)
      assert.strictEqual(m(3), 4)
  
      assert.strictEqual(m(1), 5)
    })
  
    describe('memoizeCompare', function () {
      it('should memoize using comparison', () => {
        let execCount = 0
  
        function multiply (obj) {
          execCount++
          return obj.x * obj.y
        }
  
        const m = memoizeCompare(multiply, deepStrictEqual)
  
        assert.strictEqual(m({ x: 2, y: 3 }), 6)
        assert.strictEqual(execCount, 1)
        assert.strictEqual(m({ x: 2, y: 3 }), 6)
        assert.strictEqual(execCount, 1)
  
        assert.strictEqual(m({ x: 2, y: 3, z: 4 }), 6)
        assert.strictEqual(execCount, 2)
  
        const fn1 = (a, b) => a + b
        const fn2 = (a, b) => a + b
        assert.strictEqual(m({ x: 2, y: 3, add: fn1 }), 6)
        assert.strictEqual(execCount, 3)
        assert.strictEqual(m({ x: 2, y: 3, add: fn1 }), 6)
        assert.strictEqual(execCount, 3)
        assert.strictEqual(m({ x: 2, y: 3, add: fn2 }), 6)
        assert.strictEqual(execCount, 4)
  
        assert.strictEqual(m({ x: 2, y: 3, z: undefined }), 6)
        assert.strictEqual(execCount, 5)
        assert.strictEqual(m({ x: 2, y: 3, z: undefined }), 6)
        assert.strictEqual(execCount, 5)
      })
    })
  
    describe('maxArgumentCount', function () {
      it('should calculate the max argument count of a typed function', function () {
        const a = function () {}
        a.signatures = {
          'number, number': function () {},
          number: function () {}
        }
        assert.strictEqual(maxArgumentCount(a), 2)
  
        const b = function () {}
        b.signatures = {
          number: function () {},
          'number, number': function () {}
        }
        assert.strictEqual(maxArgumentCount(b), 2)
  
        const c = function () {}
        c.signatures = {
          number: function () {},
          BigNumber: function () {}
        }
        assert.strictEqual(maxArgumentCount(c), 1)
  
        const d = function () {}
        d.signatures = {
          'number,number': function () {},
          number: function () {},
          'number,any,number': function () {}
        }
        assert.strictEqual(maxArgumentCount(d), 3)
      })
  
      it('should return -1 for regular functions', function () {
        assert.strictEqual(maxArgumentCount(function () {}), -1)
      })
    })
  })
  