mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
Resolves #3353. * test: enhance nullish coalescing tests for arrays, matrices, and conditional expressions * docs: add nullish coalescing operator precedence details and update syntax documentation --------- Co-authored-by: Jos de Jong <wjosdejong@gmail.com> Co-authored-by: Glen Whitney <glen@studioinfinity.org>
214 lines
7.3 KiB
JavaScript
214 lines
7.3 KiB
JavaScript
import assert from 'assert'
|
|
import math from '../../../../src/defaultInstance.js'
|
|
const { sparse, matrix, nullish } = math
|
|
|
|
describe('nullish', function () {
|
|
it('should return right if left nullish', function () {
|
|
assert.strictEqual(nullish(null, 42), 42)
|
|
assert.strictEqual(nullish(undefined, 'foo'), 'foo')
|
|
assert.strictEqual(nullish(0, 42), 0)
|
|
})
|
|
|
|
it('should short-circuit scalar ?? sparse', function () {
|
|
const s = sparse([[1, 0]])
|
|
assert.strictEqual(nullish(5, s), 5)
|
|
assert.strictEqual(nullish(undefined, s), s)
|
|
})
|
|
|
|
it('should short-circuit scalar ?? dense', function () {
|
|
const d = matrix([
|
|
[1, null],
|
|
[undefined, 4]
|
|
])
|
|
assert.strictEqual(nullish(5, d), 5)
|
|
assert.strictEqual(nullish(undefined, d), d)
|
|
})
|
|
|
|
it('should handle sparse ?? dense efficiently', function () {
|
|
const s = sparse([[1, 0]])
|
|
const d = matrix([[10, 20]])
|
|
const res = nullish(s, d)
|
|
assert(res.isSparseMatrix) // but since 0 not nullish, res should have 1 and 0 (but sparse might skip 0)
|
|
assert.deepStrictEqual(res.toArray(), [[1, 0]])
|
|
})
|
|
|
|
it('should handle dense ?? scalar element-wise', function () {
|
|
const d = matrix([
|
|
[null, 0],
|
|
[undefined, 1]
|
|
])
|
|
const res = nullish(d, 42)
|
|
assert.deepStrictEqual(res.toArray(), [
|
|
[42, 0],
|
|
[42, 1]
|
|
])
|
|
})
|
|
|
|
it('should allow scalar broadcasting', function () {
|
|
assert.strictEqual(nullish(5, [7, 8]), 5)
|
|
assert.deepStrictEqual(nullish(null, [7, 8]), [7, 8])
|
|
assert.deepStrictEqual(nullish([null, undefined], 42), [42, 42])
|
|
})
|
|
|
|
describe('nullish with advanced types', function () {
|
|
it('should handle Complex numbers', function () {
|
|
const zeroComplex = math.complex(0, 0)
|
|
const nonZeroComplex = math.complex(1, 1)
|
|
assert.strictEqual(nullish(null, nonZeroComplex), nonZeroComplex)
|
|
assert.strictEqual(nullish(zeroComplex, nonZeroComplex), zeroComplex) // zero complex is not nullish
|
|
assert.strictEqual(nullish(nonZeroComplex, zeroComplex), nonZeroComplex)
|
|
})
|
|
|
|
it('should handle BigNumbers', function () {
|
|
const zeroBig = math.bignumber(0)
|
|
const nonZeroBig = math.bignumber(42)
|
|
assert.strictEqual(nullish(null, nonZeroBig), nonZeroBig)
|
|
assert.strictEqual(nullish(zeroBig, nonZeroBig), zeroBig) // zero BigNumber is not nullish
|
|
assert.strictEqual(nullish(nonZeroBig, zeroBig), nonZeroBig)
|
|
})
|
|
|
|
it('should handle Fractions', function () {
|
|
const zeroFrac = math.fraction(0)
|
|
const nonZeroFrac = math.fraction(3, 4)
|
|
assert.strictEqual(nullish(null, nonZeroFrac), nonZeroFrac)
|
|
assert.strictEqual(nullish(zeroFrac, nonZeroFrac), zeroFrac) // zero Fraction is not nullish
|
|
assert.strictEqual(nullish(nonZeroFrac, zeroFrac), nonZeroFrac)
|
|
})
|
|
|
|
it('should handle Units', function () {
|
|
const zeroUnit = math.unit(0, 'cm')
|
|
const nonZeroUnit = math.unit(5, 'cm')
|
|
assert.strictEqual(nullish(null, nonZeroUnit), nonZeroUnit)
|
|
assert.strictEqual(nullish(zeroUnit, nonZeroUnit), zeroUnit) // zero Unit is not nullish
|
|
assert.strictEqual(nullish(nonZeroUnit, zeroUnit), nonZeroUnit)
|
|
})
|
|
})
|
|
|
|
describe('nullish with n-dimensional matrices', function () {
|
|
it('should handle 3D matrices element-wise', function () {
|
|
const left = math.matrix([
|
|
[
|
|
[null, 1],
|
|
[undefined, 2]
|
|
],
|
|
[
|
|
[3, null],
|
|
[4, 5]
|
|
]
|
|
])
|
|
const right = math.matrix([
|
|
[
|
|
[10, 20],
|
|
[30, 40]
|
|
],
|
|
[
|
|
[50, 60],
|
|
[70, 80]
|
|
]
|
|
])
|
|
const res = nullish(left, right)
|
|
assert.deepStrictEqual(res.toArray(), [
|
|
[
|
|
[10, 1],
|
|
[30, 2]
|
|
],
|
|
[
|
|
[3, 60],
|
|
[4, 5]
|
|
]
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('shape handling and sparse matrices', function () {
|
|
it('should throw on mismatched shapes', function () {
|
|
assert.throws(() => nullish([1], [7, 8]), /Dimension mismatch/)
|
|
assert.throws(() => nullish(matrix([1]), matrix([7, 8])), /RangeError/)
|
|
assert.throws(() => nullish(sparse([[1]]), matrix([7, 8])), /DimensionError/)
|
|
})
|
|
|
|
it('should throw on mismatched shapes for sparse ?? dense', function () {
|
|
const left = sparse([[1, 0]])
|
|
const right = matrix([7, 8])
|
|
assert.throws(() => nullish(left, right), /Dimension mismatch/)
|
|
})
|
|
|
|
it('should throw on mismatched shapes for sparse ?? dense with zeros', function () {
|
|
const left = sparse([[0, 1]])
|
|
const right = matrix([7, 8])
|
|
assert.throws(() => nullish(left, right), /Dimension mismatch/)
|
|
})
|
|
|
|
it('should handle sparse with explicit null', function () {
|
|
const d = math.matrix([[null, 1]])
|
|
const s = math.sparse([[10, 20]])
|
|
const res = nullish(d, s)
|
|
assert.deepStrictEqual(res.toArray(), [[10, 1]])
|
|
})
|
|
|
|
it('should handle explicit null in dense ?? sparse', function () {
|
|
const d = math.matrix([[null, 1]])
|
|
const s = math.sparse([[10, 20]])
|
|
const res = nullish(d, s)
|
|
assert.deepStrictEqual(res.toArray(), [[10, 1]])
|
|
})
|
|
|
|
it('should throw on broadcastable but mismatched sizes', function () {
|
|
assert.throws(() => nullish([1], [7, 8]), /Dimension mismatch/)
|
|
assert.throws(() => nullish(math.matrix([1]), math.matrix([7, 8])), /Dimension mismatch/)
|
|
})
|
|
|
|
it('should throw on mismatched shapes for sparse ?? array (no temp conversion)', function () {
|
|
const left = sparse([[1, 0]])
|
|
const right = [7, 8, 9]
|
|
assert.throws(() => nullish(left, right), /Dimension mismatch/)
|
|
})
|
|
|
|
it('should throw on mismatched shapes for sparse ?? sparse', function () {
|
|
const left = sparse([[1, 0]]) // 1x2
|
|
const right = sparse([[7], [8]]) // 2x1
|
|
assert.throws(() => nullish(left, right), /Dimension mismatch/)
|
|
})
|
|
|
|
it('should return left on matching shapes for sparse ?? sparse', function () {
|
|
const left = sparse([[1, 0]]) // 1x2
|
|
const right = sparse([[7, 8]]) // 1x2
|
|
const res = nullish(left, right)
|
|
assert(res && res.isSparseMatrix)
|
|
assert.deepStrictEqual(res.toArray(), [[1, 0]])
|
|
})
|
|
})
|
|
|
|
describe('result type conventions (function form)', function () {
|
|
it('Array, Array -> Array', function () {
|
|
const r = nullish([null, 2], [7, 8])
|
|
assert(Array.isArray(r))
|
|
assert.deepStrictEqual(r, [7, 2])
|
|
})
|
|
|
|
it('Array, DenseMatrix -> Matrix', function () {
|
|
const r = nullish([null, 2], math.matrix([7, 8]))
|
|
assert.strictEqual(!!(r && (r.isMatrix || r.isDenseMatrix || r.isSparseMatrix)), true)
|
|
assert.deepStrictEqual(r.toArray(), [7, 2])
|
|
})
|
|
|
|
it('DenseMatrix, Array -> Matrix', function () {
|
|
const r = nullish(math.matrix([null, 2]), [7, 8])
|
|
assert.strictEqual(!!(r && (r.isMatrix || r.isDenseMatrix || r.isSparseMatrix)), true)
|
|
assert.deepStrictEqual(r.toArray(), [7, 2])
|
|
})
|
|
|
|
it('SparseMatrix, Array -> Matrix (left returned on match)', function () {
|
|
const r = nullish(math.sparse([[1, 0]]), [[7, 8]])
|
|
assert.strictEqual(!!(r && (r.isMatrix || r.isDenseMatrix || r.isSparseMatrix)), true)
|
|
assert.deepStrictEqual(r.toArray(), [[1, 0]])
|
|
})
|
|
|
|
it('Array, any (scalar) -> Array', function () {
|
|
const r = nullish([null, 5], 42)
|
|
assert(Array.isArray(r))
|
|
assert.deepStrictEqual(r, [42, 5])
|
|
})
|
|
})
|
|
})
|