Skip to content

Commit

Permalink
fix(runner): Ensure test.each print -0 and -NaN properly (#5806)
Browse files Browse the repository at this point in the history
  • Loading branch information
pengooseDev authored Jun 3, 2024
1 parent dd754c1 commit 9ac8ff9
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 3 deletions.
17 changes: 16 additions & 1 deletion packages/runner/src/suite.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { format, isObject, objDisplay, objectAttr } from '@vitest/utils'
import { format, isNegativeNaN, isObject, objDisplay, objectAttr } from '@vitest/utils'
import { parseSingleStack } from '@vitest/utils/source-map'
import type { Custom, CustomAPI, File, Fixtures, RunMode, Suite, SuiteAPI, SuiteCollector, SuiteFactory, SuiteHooks, Task, TaskCustomOptions, Test, TestAPI, TestFunction, TestOptions } from './types'
import type { VitestRunner } from './types/runner'
Expand Down Expand Up @@ -433,6 +433,21 @@ function formatTitle(template: string, items: any[], idx: number) {
.replace(/__vitest_escaped_%__/g, '%%')
}
const count = template.split('%').length - 1

if (template.includes('%f')) {
const placeholders = template.match(/%f/g) || []
placeholders.forEach((_, i) => {
if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
// Replace the i-th occurrence of '%f' with '-%f'
let occurrence = 0
template = template.replace(/%f/g, (match) => {
occurrence++
return occurrence === i + 1 ? '-%f' : match
})
}
})
}

let formatted = format(template, ...items.slice(0, count))
if (isObject(items[0])) {
formatted = formatted.replace(
Expand Down
11 changes: 11 additions & 0 deletions packages/utils/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,14 @@ export function getCallLastIndex(code: string) {
}
return null
}

export function isNegativeNaN(val: number) {
if (!Number.isNaN(val))
return false
const f64 = new Float64Array(1)
f64[0] = val
const u32 = new Uint32Array(f64.buffer)
const isNegative = u32[1] >>> 31 === 1

return isNegative
}
2 changes: 1 addition & 1 deletion test/core/test/utils-display.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('format', () => {
expect(format(formatString, ...args), `failed ${formatString}`).toBe(util.format(formatString, ...args))
})

test('cannont serialize some values', () => {
test('cannot serialize some values', () => {
expect(() => format('%j', 100n)).toThrowErrorMatchingInlineSnapshot(`[TypeError: Do not know how to serialize a BigInt]`)
})

Expand Down
18 changes: 17 additions & 1 deletion test/core/test/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { beforeAll, describe, expect, test } from 'vitest'
import { assertTypes, createColors, deepClone, objDisplay, objectAttr, toArray } from '@vitest/utils'
import { assertTypes, createColors, deepClone, isNegativeNaN, objDisplay, objectAttr, toArray } from '@vitest/utils'
import { deepMerge, resetModules } from '../../../packages/vitest/src/utils'
import { deepMergeSnapshot } from '../../../packages/snapshot/src/port/utils'
import type { EncodedSourceMap } from '../../../packages/vite-node/src/types'
Expand Down Expand Up @@ -295,3 +295,19 @@ describe(createColors, () => {
expect(c.blue(c.blue('x').repeat(10000))).toBeTruthy()
})
})

describe('isNegativeNaN', () => {
test.each`
value | expected
${Number.NaN} | ${false}
${-Number.NaN} | ${true}
${0} | ${false}
${-0} | ${false}
${1} | ${false}
${-1} | ${false}
${Number.POSITIVE_INFINITY} | ${false}
${Number.NEGATIVE_INFINITY} | ${false}
`('isNegativeNaN($value) -> $expected', ({ value, expected }) => {
expect(isNegativeNaN(value)).toBe(expected)
})
})

0 comments on commit 9ac8ff9

Please sign in to comment.