import * as fc from 'fast-check'
import * as fcArb from '../../../../utilities/fast-check/arbitraries'
import stringify from './stringify'

it('should exist', () => {
  expect(stringify).toBeDefined()
})

it('should be a function', () => {
  expect(stringify).toBeFunction()
})

it('should accept 1 argument', () => {
  expect(stringify).toHaveLength(1)
})

it('should return a string value', () => {
  fc.assert(
    fc.property(fc.anything(), (v) => {
      expect(stringify(v)).toBeString()
    }),
  )
})

describe('on arguments', () => {
  it('should consider `undefined` as empty string', () => {
    expect(stringify(undefined)).toBe('')
  })

  it('should consider `null` as empty string', () => {
    expect(stringify(null)).toBe('')
  })

  it('should stringify non-objects', () => {
    fc.assert(
      fc.property(fcArb.nonObject(), fc.string(), (v) => {
        expect(stringify(v)).toBe(String(v))
      }),
    )
  })

  it('should stringify objects', () => {
    fc.assert(
      fc.property(fc.object(), (v) => {
        expect(stringify(v)).toBe(JSON.stringify(v))
      }),
    )
  })

  describe('on arrays', () => {
    it('should stringify empty arrays', () => {
      fc.assert(
        fc.property(fc.array(fcArb.nonObject(), 0), (v) => {
          expect(stringify(v)).toBe('')
        }),
      )
    })

    it('should stringify arrays with single values', () => {
      fc.assert(
        fc.property(fc.array(fcArb.nonObject(), 1, 1), (v) => {
          expect(stringify(v)).toBe(String(v[0]))
        }),
      )
    })

    it('should stringify arrays with 2 or more values', () => {
      fc.assert(
        fc.property(fc.array(fcArb.nonObject(), 2, 20), (v) => {
          expect(stringify(v)).toContain(',')
        }),
      )
    })
  })
})
