{"size": 4181, "ext": "js", "max_stars_repo_path": "test.js", "max_stars_repo_name": "watson/error-callsites", "max_stars_repo_stars_event_min_datetime": "2015-11-08T09:52:16.000Z", "max_stars_repo_stars_event_max_datetime": "2020-01-24T12:05:38.000Z", "max_issues_repo_path": "test.js", "max_issues_repo_name": "watson/error-callsites", "max_issues_repo_issues_event_min_datetime": "2015-11-06T09:40:28.000Z", "max_issues_repo_issues_event_max_datetime": "2021-09-27T09:07:44.000Z", "max_forks_repo_path": "test.js", "max_forks_repo_name": "watson/error-callsites", "max_forks_repo_forks_event_min_datetime": "2021-02-12T10:34:07.000Z", "max_forks_repo_forks_event_max_datetime": "2021-02-12T10:34:07.000Z"}
{"max_stars_count": 5, "max_issues_count": 7, "max_forks_count": 1, "avg_line_length": 29.8642857143, "max_line_length": 126, "alphanum_fraction": 0.6883520689}
'use strict'

const { EOL } = require('os')
const util = require('util')
const test = require('tape')
const callsites = require('./')
const { callsitesSym } = require('./lib/internal/symbols')

test('return non-empty array', function (t) {
  const err = new Error('foo')
  const arr = callsites(err)
  t.ok(Array.isArray(arr))
  t.ok(arr.length > 0)
  t.end()
})

test('return array of callsites', function (t) {
  const err = new Error('foo')
  const arr = callsites(err)
  t.equal(typeof arr[0], 'object')
  t.equal(typeof arr[0].getFileName, 'function')
  t.equal(arr[0].getFileName(), __filename)
  t.end()
})

test('error should have stack string', function (t) {
  const err = new Error('foo')
  callsites(err)
  t.equal(typeof err.stack, 'string')
  t.equal(err.stack.split('\n')[0], 'Error: foo')
  t.end()
})

test('process same error twice', function (t) {
  const err = new Error('foo')
  callsites(err)
  callsites(err)
  t.equal(typeof err.stack, 'string')
  t.ok(Array.isArray(err[callsitesSym]))
  t.end()
})

// In Node.js v7 this used to throw when using this module because it emits a
// deprecation warning when trying to re-define the callsites symbol property.
// By defining that property as configurable this error goes away.
test('run deprecated function', function (t) {
  util.deprecate(function () {}, 'foo')()
  t.end()
})

test('overwrite Error.prepareStackTrace', function (t) {
  Error.prepareStackTrace = () => 'boom!'
  const err = new Error('foo')
  t.equal(err.stack, 'boom!')
  t.ok(Array.isArray(err[callsitesSym]))
  t.end()
})

test('re-set Error.prepareStackTrace', function (t) {
  const orig = Error.prepareStackTrace
  Error.prepareStackTrace = () => 'boom!'

  const e1 = {}
  Error.captureStackTrace(e1)
  t.equal(e1.stack, 'boom!')
  t.ok(Array.isArray(e1[callsitesSym]))

  Error.prepareStackTrace = orig

  const e2 = {}
  Error.captureStackTrace(e2)
  t.notEqual(e2.stack, 'boom!')
  t.equal(typeof e2.stack, 'string')
  t.ok(Array.isArray(e2[callsitesSym]))

  t.end()
})

// Test that we don't get into an infinite loop in case someone else overwrites
// `Error.prepareStackTrace` while at the same time calling the original value
// of `Error.prepareStackTrace`. This is a problem with, amongst others, the
// stackback module.
test('break infinite loop', function (t) {
  let calls = 0
  const orig = Error.prepareStackTrace

  Error.prepareStackTrace = function (err, callsites) {
    t.equal(++calls, 1, 'should only call the overwritten Error.prepareStackTrace once')
    t.ok(Array.isArray(err[callsitesSym]), 'should have set callsite symbol when calling overwritten Error.prepareStackTrace')

    err.foo = 42

    return orig(err, callsites)
  }

  const err = new Error('foo')
  const stack = err.stack.split(EOL)
  const message = stack.shift()

  Error.prepareStackTrace = orig

  t.equal(err.foo, 42, 'should retain modifications made by overwritten Error.prepareStackTrace')
  t.ok(stack.length >= 3, 'should have a normal stack trace sting with at least two frames')
  t.equal(message, 'Error: foo')
  for (let i = 0; i < stack.length; i++) {
    t.equal(stack[i].indexOf('    at '), 0)
  }
  t.end()
})

// Setting `Error.prepareStackTrace = undefined` is a way to signal that you
// want to JS engine's default stack trace string generation. In earlier
// versions of this package, this blew up.
test('support Error.prepareStackTrace=undefined', function (t) {
  var previousPrepareStackTrace = Error.prepareStackTrace
  Error.prepareStackTrace = undefined

  let cs
  let message
  let stack
  try {
    throw new Error('boom with undefined Error.prepareStackTrace')
  } catch (err) {
    stack = err.stack.split(EOL)
    message = stack.shift()
    cs = callsites(err)
  } finally {
    Error.prepareStackTrace = previousPrepareStackTrace
  }

  t.ok(Array.isArray(cs), 'got callsites array')
  t.equal(typeof cs[0].getFileName, 'function')
  t.ok(stack.length >= 3, 'should have a normal stack trace sting with at least two frames')
  t.equal(message, 'Error: boom with undefined Error.prepareStackTrace')
  for (let i = 0; i < stack.length; i++) {
    t.equal(stack[i].indexOf('    at '), 0)
  }
  t.end()
})
