mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-25 15:07:57 +00:00
Added some more unit tests
This commit is contained in:
parent
99f5de862d
commit
f1ea498927
@ -44,7 +44,7 @@ var mathjs = require('../index'),
|
||||
parser = math.parser(),
|
||||
fs = require('fs');
|
||||
|
||||
var PRECISION = 14; // digits
|
||||
var PRECISION = 14; // decimals
|
||||
|
||||
/**
|
||||
* auto complete a text
|
||||
|
||||
@ -137,6 +137,7 @@ math.add('hello ', 'world!'); // String 'hello world!'
|
||||
- math.clone(x)
|
||||
- math.forEach(x, callback)
|
||||
- math.format(value [, precision])
|
||||
- math.ifElse(conditionalExpr, trueExpr, falseExpr)
|
||||
- math.import(filename | object, override)
|
||||
- math.map(x, callback)
|
||||
- math.print(template, values [, precision])
|
||||
|
||||
@ -1,9 +1,29 @@
|
||||
# Extend
|
||||
# Import
|
||||
|
||||
The library can easily be extended with functions and variables using the
|
||||
`import` function. The function `import` accepts a filename or an object with
|
||||
functions and variables.
|
||||
|
||||
Function `import` has the following syntax:
|
||||
|
||||
```js
|
||||
math.import(object: Object [, options: Object])
|
||||
math.import(moduleName: String [, options: Object])
|
||||
```
|
||||
|
||||
The first argument can be a module name or an object. The optional second
|
||||
argument can be an object with options. The following options are available:
|
||||
|
||||
- `{Boolean} override`
|
||||
If true, existing functions will be overwritten. False by default.
|
||||
- `{Boolean} wrap`
|
||||
If true (default), the functions will be wrapped in a wrapper function which
|
||||
converts data types like Matrix to primitive data types like Array.
|
||||
The wrapper is needed when extending math.js with libraries which do not
|
||||
support the math.js data types.
|
||||
|
||||
Math.js can be extended with functions and variables:
|
||||
|
||||
```js
|
||||
// create an instance of math.js
|
||||
var math = require('mathjs')();
|
||||
@ -11,6 +11,6 @@
|
||||
- [Complex Numbers](datatypes/complex_numbers.md)
|
||||
- [Matrices](datatypes/matrices.md)
|
||||
- [Units](datatypes/units.md)
|
||||
- [Extension](extend.md)
|
||||
- [Import](import.md)
|
||||
- [Configuration](configuration.md)
|
||||
- [Command Line Interface](command_line_interface.md)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Math.js can easily be extended with functions and variables using the
|
||||
* `import` function. The function `import` accepts a filename or an object
|
||||
* with functions and variables.
|
||||
* `import` function. The function `import` accepts a module name or an object
|
||||
* containing functions and variables.
|
||||
*/
|
||||
|
||||
// load math.js and create an instance
|
||||
@ -78,3 +78,15 @@ if (math.eig) {
|
||||
var b = [9, 8, 3];
|
||||
print(math.solve(A, b)); // [2, -1, 3]
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, the function import does not allow overriding existing functions.
|
||||
* Existing functions can be overridden by specifying option `override=true`
|
||||
*/
|
||||
math.import({
|
||||
pi: 3.14
|
||||
}, {
|
||||
override: true
|
||||
});
|
||||
|
||||
print(math.pi); // returns 3.14 instead of 3.141592653589793
|
||||
|
||||
@ -21,8 +21,7 @@ module.exports = function (math) {
|
||||
*/
|
||||
function Selector (value) {
|
||||
if (!(this instanceof Selector)) {
|
||||
throw new SyntaxError(
|
||||
'Selector constructor must be called with the new operator');
|
||||
throw new SyntaxError('Constructor must be called with the new operator');
|
||||
}
|
||||
|
||||
if (value instanceof Selector) {
|
||||
|
||||
@ -10,8 +10,8 @@ module.exports = function (math) {
|
||||
isUnit = Unit.isUnit;
|
||||
|
||||
/**
|
||||
* Import functions from an object or a file
|
||||
* @param {function | String | Object} object
|
||||
* Import functions from an object or a module
|
||||
* @param {String | Object} object
|
||||
* @param {Object} [options] Available options:
|
||||
* {Boolean} override
|
||||
* If true, existing functions will be
|
||||
@ -27,6 +27,11 @@ module.exports = function (math) {
|
||||
*/
|
||||
// TODO: return status information
|
||||
math['import'] = function math_import(object, options) {
|
||||
var num = arguments.length;
|
||||
if (num != 1 && num != 2) {
|
||||
throw new math.error.ArgumentsError('import', num, 1, 2);
|
||||
}
|
||||
|
||||
var name;
|
||||
var opts = {
|
||||
override: false,
|
||||
@ -47,19 +52,7 @@ module.exports = function (math) {
|
||||
throw new Error('Cannot load file: require not available.');
|
||||
}
|
||||
}
|
||||
else if (isSupportedType(object)) {
|
||||
// a single function
|
||||
name = object.name;
|
||||
if (name) {
|
||||
if (opts.override || math[name] === undefined) {
|
||||
_import(name, object, opts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error('Cannot import an unnamed function or object');
|
||||
}
|
||||
}
|
||||
else if (object instanceof Object) {
|
||||
else if (typeof object === 'object') {
|
||||
// a map with functions
|
||||
for (name in object) {
|
||||
if (object.hasOwnProperty(name)) {
|
||||
@ -73,6 +66,9 @@ module.exports = function (math) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new TypeError('Object or module name expected');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -35,7 +35,7 @@ module.exports = function (math) {
|
||||
if (x instanceof Unit) return 'unit';
|
||||
if (x instanceof Index) return 'index';
|
||||
if (x instanceof Range) return 'range';
|
||||
if (x instanceof Help) return 'matrix';
|
||||
if (x instanceof Help) return 'help';
|
||||
|
||||
if (x instanceof math.chaining.Selector) return 'selector';
|
||||
}
|
||||
|
||||
@ -25,8 +25,7 @@ var util = require('../util/index'),
|
||||
*/
|
||||
function Complex(re, im) {
|
||||
if (!(this instanceof Complex)) {
|
||||
throw new SyntaxError(
|
||||
'Complex constructor must be called with the new operator');
|
||||
throw new SyntaxError('Constructor must be called with the new operator');
|
||||
}
|
||||
|
||||
switch (arguments.length) {
|
||||
|
||||
@ -14,6 +14,12 @@ var util = require('../util/index'),
|
||||
* @constructor
|
||||
*/
|
||||
function Help (math, doc) {
|
||||
if (!(this instanceof Help)) {
|
||||
throw new SyntaxError('Constructor must be called with the new operator');
|
||||
}
|
||||
|
||||
// TODO: throw an error when math or doc is not provided
|
||||
|
||||
this.math = math;
|
||||
this.doc = doc;
|
||||
}
|
||||
@ -80,7 +86,7 @@ Help.prototype.toString = function () {
|
||||
* Export the help object to JSON
|
||||
*/
|
||||
Help.prototype.toJSON = function () {
|
||||
return object.extend({}, this.doc);
|
||||
return object.clone(this.doc);
|
||||
};
|
||||
|
||||
// exports
|
||||
|
||||
@ -30,8 +30,7 @@ var util = require('../util/index'),
|
||||
*/
|
||||
function Index(ranges) {
|
||||
if (!(this instanceof Index)) {
|
||||
throw new SyntaxError(
|
||||
'Index constructor must be called with the new operator');
|
||||
throw new SyntaxError('Constructor must be called with the new operator');
|
||||
}
|
||||
|
||||
this._ranges = [];
|
||||
|
||||
@ -33,7 +33,7 @@ var util = require('../util/index'),
|
||||
function Matrix(data) {
|
||||
if (!(this instanceof Matrix)) {
|
||||
throw new SyntaxError(
|
||||
'Matrix constructor must be called with the new operator');
|
||||
'Constructor must be called with the new operator');
|
||||
}
|
||||
|
||||
if (data instanceof Matrix) {
|
||||
|
||||
@ -34,8 +34,7 @@ var util = require('../util/index'),
|
||||
*/
|
||||
function Range(start, end, step) {
|
||||
if (!(this instanceof Range)) {
|
||||
throw new SyntaxError(
|
||||
'Range constructor must be called with the new operator');
|
||||
throw new SyntaxError('Constructor must be called with the new operator');
|
||||
}
|
||||
|
||||
if (start != null && !number.isNumber(start)) {
|
||||
|
||||
@ -23,7 +23,7 @@ var util = require('../util/index'),
|
||||
*/
|
||||
function Unit(value, unit) {
|
||||
if (!(this instanceof Unit)) {
|
||||
throw new Error('Unit constructor must be called with the new operator');
|
||||
throw new Error('Constructor must be called with the new operator');
|
||||
}
|
||||
|
||||
if (value != null && !isNumber(value)) {
|
||||
|
||||
@ -32,13 +32,19 @@ exports.clone = function clone(x) {
|
||||
|
||||
// object
|
||||
if (x instanceof Object) {
|
||||
if (x instanceof Number) return new Number(x.valueOf());
|
||||
if (x instanceof String) return new String(x.valueOf());
|
||||
if (x instanceof Boolean) return new Boolean(x.valueOf());
|
||||
if (x instanceof Date) return new Date(x.valueOf());
|
||||
if (x instanceof RegExp) throw new TypeError('Cannot clone ' + x); // TODO: clone a RegExp
|
||||
|
||||
var m = {};
|
||||
for (var key in x) {
|
||||
if (x.hasOwnProperty(key)) {
|
||||
m[key] = clone(x[key]);
|
||||
}
|
||||
}
|
||||
return x;
|
||||
return m;
|
||||
}
|
||||
|
||||
// this should never happen
|
||||
|
||||
@ -59,7 +59,7 @@ describe('distribution', function () {
|
||||
describe('random', function() {
|
||||
var originalRandom;
|
||||
|
||||
it('should pick uniformely distributed numbers in [0, 1]', function() {
|
||||
it('should pick uniformly distributed numbers in [0, 1]', function() {
|
||||
var picked = [];
|
||||
|
||||
_.times(1000, function() {
|
||||
@ -69,7 +69,7 @@ describe('distribution', function () {
|
||||
});
|
||||
|
||||
|
||||
it('should pick uniformely distributed numbers in [min, max]', function() {
|
||||
it('should pick uniformly distributed numbers in [min, max]', function() {
|
||||
var picked = [];
|
||||
|
||||
_.times(1000, function() {
|
||||
@ -78,7 +78,7 @@ describe('distribution', function () {
|
||||
assertUniformDistribution(picked, -10, 10);
|
||||
});
|
||||
|
||||
it('should pick uniformely distributed random matrix, with elements in [0, 1]', function() {
|
||||
it('should pick uniformly distributed random matrix, with elements in [0, 1]', function() {
|
||||
var picked = [],
|
||||
matrices = [],
|
||||
size = [2, 3, 4];
|
||||
@ -99,7 +99,7 @@ describe('distribution', function () {
|
||||
assertUniformDistribution(picked, 0, 1);
|
||||
});
|
||||
|
||||
it('should pick uniformely distributed random matrix, with elements in [min, max]', function() {
|
||||
it('should pick uniformly distributed random matrix, with elements in [min, max]', function() {
|
||||
var picked = [],
|
||||
matrices = [],
|
||||
size = [2, 3, 4];
|
||||
@ -131,7 +131,7 @@ describe('distribution', function () {
|
||||
|
||||
describe('randomInt', function() {
|
||||
|
||||
it('should pick uniformely distributed integers in [min, max)', function() {
|
||||
it('should pick uniformly distributed integers in [min, max)', function() {
|
||||
var picked = [];
|
||||
|
||||
_.times(10000, function() {
|
||||
@ -141,7 +141,7 @@ describe('distribution', function () {
|
||||
assertUniformDistributionInt(picked, -15, -5);
|
||||
});
|
||||
|
||||
it('should pick uniformely distributed random matrix, with elements in [min, max)', function() {
|
||||
it('should pick uniformly distributed random matrix, with elements in [min, max)', function() {
|
||||
var picked = [],
|
||||
matrices = [],
|
||||
size = [2, 3, 4];
|
||||
|
||||
@ -10,6 +10,11 @@ describe('clone', function() {
|
||||
assert.strictEqual(b, 1);
|
||||
});
|
||||
|
||||
it('should throw an error on wrong number of arguments', function() {
|
||||
assert.throws (function () {math.clone()}, math.error.ArgumentsError);
|
||||
assert.throws (function () {math.clone(2, 4)}, math.error.ArgumentsError);
|
||||
});
|
||||
|
||||
it('should clone a bignumber', function() {
|
||||
var a = math.bignumber('2.3e500');
|
||||
var b = math.clone(a);
|
||||
@ -21,6 +26,7 @@ describe('clone', function() {
|
||||
var a = 'hello world';
|
||||
var b = math.clone(a);
|
||||
a = 'bye!';
|
||||
assert.strictEqual(a, 'bye!');
|
||||
assert.strictEqual(b, 'hello world');
|
||||
});
|
||||
|
||||
|
||||
@ -80,4 +80,10 @@ describe('format', function() {
|
||||
assert.equal(math.format(oneThird, 18), '0.333333333333333333');
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error on wrong number of arguments', function() {
|
||||
assert.throws (function () {math.format()}, math.error.ArgumentsError);
|
||||
assert.throws (function () {math.format(1, 2, 3)}, math.error.ArgumentsError);
|
||||
});
|
||||
|
||||
});
|
||||
@ -99,4 +99,36 @@ describe('import', function() {
|
||||
approx.equal(estFollowers, 1422.431464053916);
|
||||
});
|
||||
|
||||
it.skip('should throw an error when trying to load a module when no module loader is available', function () {
|
||||
// TODO: how to temporarily override the global function require?
|
||||
var orig = require;
|
||||
require = undefined;
|
||||
|
||||
assert.throws(function () {math.import('numbers');}, /Cannot load file: require not available/);
|
||||
|
||||
require = orig;
|
||||
});
|
||||
|
||||
it('should throw an error in case of wrong number of arguments', function () {
|
||||
assert.throws (function () {math.import()}, math.error.ArgumentsError);
|
||||
assert.throws (function () {math.import('', {}, 3)}, math.error.ArgumentsError);
|
||||
|
||||
});
|
||||
|
||||
it('should throw an error in case of wrong type of arguments', function () {
|
||||
assert.throws(function () {math.import(2)}, /Object or module name expected/);
|
||||
assert.throws(function () {math.import(function () {})}, /Object or module name expected/);
|
||||
});
|
||||
|
||||
it('should ignore properties on Object', function () {
|
||||
Object.prototype.foo = 123;
|
||||
|
||||
math.import({bar: 456});
|
||||
|
||||
assert(!math.hasOwnProperty('foo'));
|
||||
assert(math.hasOwnProperty('bar'));
|
||||
|
||||
delete Object.prototype.foo;
|
||||
});
|
||||
|
||||
});
|
||||
@ -17,8 +17,30 @@ describe('print', function() {
|
||||
}), 'hello, first last!');
|
||||
});
|
||||
|
||||
it('should round interpolate values to provided precision', function() {
|
||||
it('should round interpolate values with provided precision', function() {
|
||||
assert.equal(math.print('pi=$pi', {pi: math.pi}, 3), 'pi=3.14');
|
||||
});
|
||||
|
||||
it('should leave unresolved variables untouched', function() {
|
||||
assert.equal(math.print('$a,$b', {b: 2}), '$a,2');
|
||||
assert.equal(math.print('$a.value,$b.value', {a: {}, b: {value: 2}}), '$a.value,2');
|
||||
});
|
||||
|
||||
it('should leave trailing point intact', function() {
|
||||
assert.equal(math.print('Hello $name.', {name: 'user'}), 'Hello user.');
|
||||
assert.equal(math.print('Hello $name...', {name: 'user'}), 'Hello user...');
|
||||
assert.equal(math.print('Hello $user.name.', {user: {name: 'user'}}), 'Hello user.');
|
||||
});
|
||||
|
||||
it('should throw an error on wrong number of arguments', function() {
|
||||
assert.throws (function () {math.print()}, math.error.ArgumentsError);
|
||||
assert.throws (function () {math.print('')}, math.error.ArgumentsError);
|
||||
assert.throws (function () {math.print('', {}, 6, 2)}, math.error.ArgumentsError);
|
||||
});
|
||||
|
||||
it('should throw an error on wrong type of arguments', function() {
|
||||
assert.throws (function () {math.print(2, {})}, TypeError);
|
||||
assert.throws (function () {math.print('', 2)}, TypeError);
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,5 +1,11 @@
|
||||
// test typeof
|
||||
var assert = require('assert'),
|
||||
Index = require('../../../lib/type/Index'),
|
||||
Range = require('../../../lib/type/Range'),
|
||||
Matrix = require('../../../lib/type/Matrix'),
|
||||
Help = require('../../../lib/type/Help'),
|
||||
Unit = require('../../../lib/type/Unit'),
|
||||
Complex = require('../../../lib/type/Complex'),
|
||||
math = require('../../../index')();
|
||||
|
||||
describe('typeof', function() {
|
||||
@ -20,6 +26,7 @@ describe('typeof', function() {
|
||||
});
|
||||
|
||||
it('should return complex type for a complex number', function() {
|
||||
assert.equal(math.typeof(new Complex(2,3)), 'complex');
|
||||
assert.equal(math.typeof(math.complex(2,3)), 'complex');
|
||||
});
|
||||
|
||||
@ -28,11 +35,18 @@ describe('typeof', function() {
|
||||
assert.equal(math.typeof(new Array()), 'array');
|
||||
});
|
||||
|
||||
it('should return matrix type for a matrix', function() {
|
||||
assert.equal(math.typeof(math.matrix()), 'matrix');
|
||||
it('should return array type for an array', function() {
|
||||
assert.equal(math.typeof([1,2,3]), 'array');
|
||||
assert.equal(math.typeof(new Array()), 'array');
|
||||
});
|
||||
|
||||
it('should return unit type for a unit', function() {
|
||||
it('should return matrix type for a matrix', function() {
|
||||
assert.equal(math.typeof(math.matrix()), 'matrix');
|
||||
assert.equal(math.typeof(new Matrix()), 'matrix');
|
||||
});
|
||||
|
||||
it('should return unit type for a unit', function() {
|
||||
assert.equal(math.typeof(new Unit(5, 'cm')), 'unit');
|
||||
assert.equal(math.typeof(math.unit('5cm')), 'unit');
|
||||
});
|
||||
|
||||
@ -63,6 +77,18 @@ describe('typeof', function() {
|
||||
assert.equal(math.typeof(math.select(3)), 'selector');
|
||||
});
|
||||
|
||||
it('should return function type for an index', function() {
|
||||
assert.equal(math.typeof(new Index([0, 10])), 'index');
|
||||
});
|
||||
|
||||
it('should return function type for a range', function() {
|
||||
assert.equal(math.typeof(new Range(0, 10)), 'range');
|
||||
});
|
||||
|
||||
it('should return function type for a help object', function() {
|
||||
assert.equal(math.typeof(new Help()), 'help');
|
||||
});
|
||||
|
||||
it('should return object type for an object', function() {
|
||||
assert.equal(math.typeof({}), 'object');
|
||||
assert.equal(math.typeof(new Object()), 'object');
|
||||
|
||||
@ -1,14 +1,125 @@
|
||||
// test Help
|
||||
var assert = require('assert'),
|
||||
Help = require('../../lib/type/Help'),
|
||||
math = require('../../index')();
|
||||
|
||||
var help = new math.type.Help(math, math.expression.docs.sin);
|
||||
|
||||
describe('help', function() {
|
||||
|
||||
var doc = {
|
||||
'name': 'add',
|
||||
'category': 'Operators',
|
||||
'syntax': [
|
||||
'x + y',
|
||||
'add(x, y)'
|
||||
],
|
||||
'description': 'Add two values.',
|
||||
'examples': [
|
||||
'2.1 + 3.6',
|
||||
'ans - 3.6'
|
||||
],
|
||||
'seealso': [
|
||||
'subtract'
|
||||
]
|
||||
};
|
||||
|
||||
it('should generate the help for a function', function() {
|
||||
assert.deepEqual(help.doc.name, 'sin');
|
||||
assert.deepEqual(help.doc, math.expression.docs.sin);
|
||||
var help = new Help(math, doc);
|
||||
|
||||
assert(help instanceof Help);
|
||||
assert.deepEqual(help.doc.name, 'add');
|
||||
assert.deepEqual(help.doc, doc);
|
||||
});
|
||||
|
||||
it('should throw an error when constructed without new operator', function() {
|
||||
assert.throws(function () {
|
||||
Help(math, math.expression.docs.sin);
|
||||
}, /Constructor must be called with the new operator/)
|
||||
});
|
||||
|
||||
it('should test whether an object is a Help object', function() {
|
||||
var help = new Help(math, doc);
|
||||
|
||||
assert.equal(Help.isHelp(help), true);
|
||||
assert.equal(Help.isHelp(new Date()), false);
|
||||
assert.equal(Help.isHelp({}), false);
|
||||
});
|
||||
|
||||
it('should stringify a help', function() {
|
||||
var help = new Help(math, doc);
|
||||
assert.equal(help.toString(),
|
||||
'\nName: add\n' +
|
||||
'\n'+
|
||||
'Category: Operators\n' +
|
||||
'\n' +
|
||||
'Description:\n' +
|
||||
' Add two values.\n' +
|
||||
'\n' +
|
||||
'Syntax:\n' +
|
||||
' x + y\n' +
|
||||
' add(x, y)\n' +
|
||||
'\n' +
|
||||
'Examples:\n' +
|
||||
' 2.1 + 3.6\n' +
|
||||
' 5.7\n' +
|
||||
' ans - 3.6\n' +
|
||||
' 2.1\n' +
|
||||
'\n' +
|
||||
'See also: subtract\n');
|
||||
});
|
||||
|
||||
it('should stringify a help with empty doc', function() {
|
||||
var help = new Help(math);
|
||||
assert.equal(help.toString(), '\n');
|
||||
});
|
||||
|
||||
it('should stringify a help without doc', function() {
|
||||
var help = new Help(math);
|
||||
assert.equal(help.toString(), '\n');
|
||||
});
|
||||
|
||||
it('should stringify a doc with empty example', function() {
|
||||
var help = new Help(math, {
|
||||
'name': 'add',
|
||||
'examples': [
|
||||
'2 + 3',
|
||||
''
|
||||
]
|
||||
});
|
||||
|
||||
assert.equal(help.toString(),
|
||||
'\nName: add\n' +
|
||||
'\n'+
|
||||
'Examples:\n' +
|
||||
' 2 + 3\n' +
|
||||
' 5\n' +
|
||||
' \n' +
|
||||
'\n');
|
||||
});
|
||||
|
||||
it('should stringify a doc with example throwing an error', function() {
|
||||
var help = new Help(math, {
|
||||
'name': 'add',
|
||||
'examples': [
|
||||
'2 ++ 3'
|
||||
]
|
||||
});
|
||||
|
||||
assert.equal(help.toString(),
|
||||
'\nName: add\n' +
|
||||
'\n'+
|
||||
'Examples:\n' +
|
||||
' 2 ++ 3\n' +
|
||||
' SyntaxError: Value expected (char 4)\n' +
|
||||
'\n');
|
||||
});
|
||||
|
||||
it('should export doc to JSON', function() {
|
||||
var help = new Help(math, doc);
|
||||
var json = help.toJSON();
|
||||
assert.deepEqual(json, doc);
|
||||
json.name = 'foo'; // this should not alter the original doc
|
||||
json.examples.push('2 + 3'); // this should not alter the original doc
|
||||
assert.equal(doc.name, 'add');
|
||||
assert.notEqual(json.examples.length, doc.examples.length);
|
||||
});
|
||||
|
||||
});
|
||||
@ -314,7 +314,7 @@ describe('number', function() {
|
||||
|
||||
describe('bignumber', function () {
|
||||
before (function () {
|
||||
math.type.BigNumber.config(20); // ensure the precision is 20 digits, the default
|
||||
BigNumber.config(20); // ensure the precision is 20 digits, the default
|
||||
});
|
||||
|
||||
it('should format big numbers', function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user