main
1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import assert from 'node:assert'
16import { test, describe } from 'node:test'
17import { Fail } from '../src/error.ts'
18
19const {
20 getErrnoMessage,
21 getExitCodeInfo,
22 getCallerLocation,
23 getCallerLocationFromString,
24 formatExitMessage,
25 formatErrorMessage,
26 formatErrorDetails,
27} = Fail
28
29describe('error', () => {
30 test('getExitCodeInfo()', () => {
31 assert.equal(getExitCodeInfo(2), 'Misuse of shell builtins')
32 })
33
34 test('getErrnoMessage()', () => {
35 assert.equal(getErrnoMessage(-2), 'No such file or directory')
36 assert.equal(getErrnoMessage(1e9), 'Unknown error')
37 assert.equal(getErrnoMessage(undefined), 'Unknown error')
38 })
39
40 test('getCallerLocation()', () => {
41 assert.match(
42 getCallerLocation(new Error('Foo')),
43 /TestContext\.<anonymous>/
44 )
45 })
46
47 describe('getCallerLocationFromString()', () => {
48 test('empty', () => {
49 assert.equal(getCallerLocationFromString(), 'unknown')
50 })
51
52 test('no-match', () => {
53 assert.equal(
54 getCallerLocationFromString('stack\nstring'),
55 'stack\nstring'
56 )
57 })
58
59 test(`getCallerLocationFromString-v8`, () => {
60 const stack = `
61 Error
62 at getCallerLocation (/Users/user/test.js:22:17)
63 at Proxy.set (/Users/user/test.js:40:10)
64 at e (/Users/user/test.js:34:13)
65 at d (/Users/user/test.js:11:5)
66 at c (/Users/user/test.js:8:5)
67 at b (/Users/user/test.js:5:5)
68 at a (/Users/user/test.js:2:5)
69 at Object.<anonymous> (/Users/user/test.js:37:1)
70 at Module._compile (node:internal/modules/cjs/loader:1254:14)
71 at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
72 at Module.load (node:internal/modules/cjs/loader:1117:32)
73 at Module._load (node:internal/modules/cjs/loader:958:12)
74 `
75 assert.match(getCallerLocationFromString(stack), /^.*:11:5.*$/)
76 })
77
78 test(`getCallerLocationFromString-JSC`, () => {
79 const stack = `
80 getCallerLocation@/Users/user/test.js:22:17
81 Proxy.set@/Users/user/test.js:40:10)
82 e@/Users/user/test.js:34:13
83 d@/Users/user/test.js:11:5
84 c@/Users/user/test.js:8:5
85 b@/Users/user/test.js:5:5
86 a@/Users/user/test.js:2:5
87 module code@/Users/user/test.js:37:1
88 evaluate@[native code]
89 moduleEvaluation@[native code]
90 moduleEvaluation@[native code]
91 @[native code]
92 asyncFunctionResume@[native code]
93 promiseReactionJobWithoutPromise@[native code]
94 promiseReactionJob@[native code]
95 d@/Users/user/test.js:11:5
96 `
97 assert.match(getCallerLocationFromString(stack), /^.*:11:5.*$/)
98 })
99 })
100
101 // prettier-ignore
102 test('getExitMessage()', () => {
103 assert.match(formatExitMessage(2, null, '', ''), /Misuse of shell builtins/)
104 assert.equal(formatExitMessage(1, 'SIGKILL', '', '', 'data'), `\n at \n exit code: 1\n signal: SIGKILL\n details: \ndata`)
105 assert.equal(formatExitMessage(0, null, '', ''), 'exit code: 0')
106 })
107
108 test('getErrorMessage()', () => {
109 assert.match(
110 formatErrorMessage({ errno: -2 } as NodeJS.ErrnoException, ''),
111 /No such file or directory/
112 )
113 assert.match(
114 formatErrorMessage({ errno: -1e9 } as NodeJS.ErrnoException, ''),
115 /Unknown error/
116 )
117 assert.match(
118 formatErrorMessage({} as NodeJS.ErrnoException, ''),
119 /Unknown error/
120 )
121 })
122
123 test('findErrors()', () => {
124 const lines = [...Array(40).keys()].map((v) => v + '')
125
126 assert.equal(formatErrorDetails([]), '', 'empty returns empty')
127 assert.equal(
128 formatErrorDetails(['foo', 'bar']),
129 'foo\nbar',
130 'squashes a few'
131 )
132 assert.equal(
133 formatErrorDetails(['failure: foo', 'NOT OK smth', ...lines]),
134 'failure: foo\nNOT OK smth',
135 'extracts errors'
136 )
137 assert.equal(
138 formatErrorDetails(lines),
139 '0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n...',
140 'shows a sample'
141 )
142 })
143})