export interface IAssertionError {
  /**
   * Set with assertions to show the actual value at the time of testing.
   */
  actual?: unknown
  /**
   * Set with assertions to show the expected value at the time of testing.
   */
  expected?: unknown
  /**
   * The operator used to make the assertion.
   */
  operator?: string
  /**
   * The error message, if any.
   * Assertions usually don't set error messages. Instead they set other fields.
   */
  message?: string
}

export class AssertionError extends Error {
  /**
   * Set with assertions to show the actual value at the time of testing.
   */
  actual: unknown
  /**
   * Set with assertions to show the expected value at the time of testing.
   */
  expected: unknown
  /**
   * The operator used to make the assertion.
   */
  operator: string

  code = 'ERR_ASSERTION'

  constructor(options: IAssertionError = {}) {
    super(options.message || 'Unspecified AssertionError')
    this.name = 'AssertionError'
    this.actual = options.actual
    this.expected = options.expected
    this.operator = options.operator || '[unknown]'
  }

  toJSON(): IAssertionError {
    const result: IAssertionError = {}
    if (this.message) {
      result.message = this.message
    }
    result.actual = this.actual
    result.expected = this.expected
    if (this.operator) {
      result.operator = this.operator
    }
    return result
  }
}
