@@ -132,22 +132,164 @@ class SystemError extends makeNodeError(Error) {
132132 }
133133}
134134
135+ function createErrDiff ( actual , expected , operator ) {
136+ var other = '' ;
137+ var res = '' ;
138+ var lastPos = 0 ;
139+ var end = '' ;
140+ var skipped = false ;
141+ const actualLines = util
142+ . inspect ( actual , { compact : false } ) . split ( '\n' ) ;
143+ const expectedLines = util
144+ . inspect ( expected , { compact : false } ) . split ( '\n' ) ;
145+ const msg = `Input A expected to ${ operator } input B:\n` +
146+ '\u001b[32m+ expected\u001b[39m \u001b[31m- actual\u001b[39m' ;
147+ const skippedMsg = ' ... Lines skipped' ;
148+
149+ // Remove all ending lines that match (this optimizes the output for
150+ // readability by reducing the number of total changed lines).
151+ var a = actualLines [ actualLines . length - 1 ] ;
152+ var b = expectedLines [ expectedLines . length - 1 ] ;
153+ var i = 0 ;
154+ while ( a === b ) {
155+ if ( i ++ < 2 ) {
156+ end = `\n ${ a } ${ end } ` ;
157+ } else {
158+ other = a ;
159+ }
160+ actualLines . pop ( ) ;
161+ expectedLines . pop ( ) ;
162+ a = actualLines [ actualLines . length - 1 ] ;
163+ b = expectedLines [ expectedLines . length - 1 ] ;
164+ }
165+ if ( i > 3 ) {
166+ end = `\n...${ end } ` ;
167+ skipped = true ;
168+ }
169+ if ( other !== '' ) {
170+ end = `\n ${ other } ${ end } ` ;
171+ other = '' ;
172+ }
173+
174+ const maxLines = Math . max ( actualLines . length , expectedLines . length ) ;
175+ var printedLines = 0 ;
176+ for ( i = 0 ; i < maxLines ; i ++ ) {
177+ // Only extra expected lines exist
178+ const cur = i - lastPos ;
179+ if ( actualLines . length < i + 1 ) {
180+ if ( cur > 1 && i > 2 ) {
181+ if ( cur > 4 ) {
182+ res += '\n...' ;
183+ skipped = true ;
184+ } else if ( cur > 3 ) {
185+ res += `\n ${ expectedLines [ i - 2 ] } ` ;
186+ printedLines ++ ;
187+ }
188+ res += `\n ${ expectedLines [ i - 1 ] } ` ;
189+ printedLines ++ ;
190+ }
191+ lastPos = i ;
192+ other += `\n\u001b[32m+\u001b[39m ${ expectedLines [ i ] } ` ;
193+ printedLines ++ ;
194+ // Only extra actual lines exist
195+ } else if ( expectedLines . length < i + 1 ) {
196+ if ( cur > 1 && i > 2 ) {
197+ if ( cur > 4 ) {
198+ res += '\n...' ;
199+ skipped = true ;
200+ } else if ( cur > 3 ) {
201+ res += `\n ${ actualLines [ i - 2 ] } ` ;
202+ printedLines ++ ;
203+ }
204+ res += `\n ${ actualLines [ i - 1 ] } ` ;
205+ printedLines ++ ;
206+ }
207+ lastPos = i ;
208+ res += `\n\u001b[31m-\u001b[39m ${ actualLines [ i ] } ` ;
209+ printedLines ++ ;
210+ // Lines diverge
211+ } else if ( actualLines [ i ] !== expectedLines [ i ] ) {
212+ if ( cur > 1 && i > 2 ) {
213+ if ( cur > 4 ) {
214+ res += '\n...' ;
215+ skipped = true ;
216+ } else if ( cur > 3 ) {
217+ res += `\n ${ actualLines [ i - 2 ] } ` ;
218+ printedLines ++ ;
219+ }
220+ res += `\n ${ actualLines [ i - 1 ] } ` ;
221+ printedLines ++ ;
222+ }
223+ lastPos = i ;
224+ res += `\n\u001b[31m-\u001b[39m ${ actualLines [ i ] } ` ;
225+ other += `\n\u001b[32m+\u001b[39m ${ expectedLines [ i ] } ` ;
226+ printedLines += 2 ;
227+ // Lines are identical
228+ } else {
229+ res += other ;
230+ other = '' ;
231+ if ( cur === 1 || i === 0 ) {
232+ res += `\n ${ actualLines [ i ] } ` ;
233+ printedLines ++ ;
234+ }
235+ }
236+ // Inspected object to big (Show ~20 rows max)
237+ if ( printedLines > 20 && i < maxLines - 2 ) {
238+ return `${ msg } ${ skippedMsg } \n${ res } \n...${ other } \n...` ;
239+ }
240+ }
241+ return `${ msg } ${ skipped ? skippedMsg : '' } \n${ res } ${ other } ${ end } ` ;
242+ }
243+
135244class AssertionError extends Error {
136245 constructor ( options ) {
137246 if ( typeof options !== 'object' || options === null ) {
138247 throw new exports . TypeError ( 'ERR_INVALID_ARG_TYPE' , 'options' , 'Object' ) ;
139248 }
140- var { actual, expected, message, operator, stackStartFn } = options ;
249+ var {
250+ actual,
251+ expected,
252+ message,
253+ operator,
254+ stackStartFn,
255+ errorDiff = 0
256+ } = options ;
257+
141258 if ( message != null ) {
142259 super ( message ) ;
143260 } else {
261+ if ( util === null ) util = require ( 'util' ) ;
262+
144263 if ( actual && actual . stack && actual instanceof Error )
145264 actual = `${ actual . name } : ${ actual . message } ` ;
146265 if ( expected && expected . stack && expected instanceof Error )
147266 expected = `${ expected . name } : ${ expected . message } ` ;
148- if ( util === null ) util = require ( 'util' ) ;
149- super ( `${ util . inspect ( actual ) . slice ( 0 , 128 ) } ` +
150- `${ operator } ${ util . inspect ( expected ) . slice ( 0 , 128 ) } ` ) ;
267+
268+ if ( errorDiff === 0 ) {
269+ let res = util . inspect ( actual ) ;
270+ let other = util . inspect ( expected ) ;
271+ if ( res . length > 128 )
272+ res = `${ res . slice ( 0 , 125 ) } ...` ;
273+ if ( other . length > 128 )
274+ other = `${ other . slice ( 0 , 125 ) } ...` ;
275+ super ( `${ res } ${ operator } ${ other } ` ) ;
276+ } else if ( errorDiff === 1 ) {
277+ // In case the objects are equal but the operator requires unequal, show
278+ // the first object and say A equals B
279+ const res = util
280+ . inspect ( actual , { compact : false } ) . split ( '\n' ) ;
281+
282+ if ( res . length > 20 ) {
283+ res [ 19 ] = '...' ;
284+ while ( res . length > 20 ) {
285+ res . pop ( ) ;
286+ }
287+ }
288+ // Only print a single object.
289+ super ( `Identical input passed to ${ operator } :\n${ res . join ( '\n' ) } ` ) ;
290+ } else {
291+ super ( createErrDiff ( actual , expected , operator ) ) ;
292+ }
151293 }
152294
153295 this . generatedMessage = ! message ;
0 commit comments