New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

jsverify

Package Overview
Dependencies
Maintainers
1
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jsverify - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2

speclib/jasmineHelpers.js

302

lib/jsverify.js

@@ -41,4 +41,44 @@ /**

## Documentation
### Use with [jasmine](http://pivotal.github.io/jasmine/) 1.3.x
Check [jasmineHelpers.js](speclib/jasmineHelpers.js) file.
## API
> _Testing shows the presence, not the absence of bugs._
>
> Edsger W. Dijkstra
To show that propositions hold, we need to construct proofs.
There are two extremes: proof by example (unit tests) and formal (machine-checked) proof.
Property-based testing is something in between.
We formulate propositions, invariants or other properties we believe to hold, but
only test it to hold for numerous (random generated) values.
Types and function signatures are written in [Coq](http://coq.inria.fr/)/[Haskell](http://www.haskell.org/haskellwiki/Haskell) influented style:
C# -style `List<T> filter(List<T> v, Func<T, bool> predicate)` is represented by
`filter (v : array T) (predicate : T -> bool) : array T` in our style.
`jsverify` can operate with both synchronous and asynchronous-promise properties.
Generally every property can be wrapped inside [functor](http://learnyouahaskell.com/functors-applicative-functors-and-monoids),
for now in either identity or promise functor, for synchronous and promise properties respectively.
Some type definitions to keep developers sane:
- Functor f => property (size : nat) : f result
- result := true | { counterexample: any }
- Functor f => property_rec := f (result | property)
- generator a := { arbitrary : a, shrink : a -> [a] }
*/
/**
### jsc._ - miscellaneous utilities
*/
/**
#### assert (exp : bool) (message : string) : void
Throw an error with `message` if `exp` is falsy.
*/
function assert(exp, message) {

@@ -50,2 +90,8 @@ if (!exp) {

/**
#### isPromise p : bool
Optimistic duck-type check for promises.
Returns `true` if p is an object with `.then` function property.
*/
function isPromise(p) {

@@ -55,2 +101,9 @@ return new Object(p) === p && typeof p.then === "function";

/**
#### withPromise (Functor f) (p : f a) (f : a -> b) : f b
This is functor map, `fmap`, with arguments flipped.
Essentially `f(p)`. If `p` is promise, returns new promise.
Using `withPromise` makes code look very much [CPS-style](http://en.wikipedia.org/wiki/Continuation-passing_style).
*/
function withPromise(p, f) {

@@ -64,2 +117,33 @@ if (isPromise(p)) {

/**
#### getRandomArbitrary (min max : number) : number
Returns random number from `[min, max)` range.
*/
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
/**
#### getRandomInt (min max : int) : int
Returns random int from `[min, max]` range inclusively.
```js
getRandomInt(2, 3) // either 2 or 3
```
*/
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
/**
### Properties
*/
/**
#### forall (gen : generator a) (prop : a -> property_rec) : property
Property constructor
*/
function forall(generator, property) {

@@ -139,2 +223,7 @@ assert(typeof property === "function", "property should be a function");

/**
#### check (prop : property) : promise result + result
Run random checks for given `prop`. If `prop` is promise based, result is also wrapped in promise.
*/
function check(property) {

@@ -165,13 +254,11 @@ var size = 5;

// Random helpers
/*
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
/**
### Primitive generators
*/
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
// Generators
/**
#### integer (maxsize : nat) : generator integer
Integers, ℤ
*/
function integer(maxsize) {

@@ -191,2 +278,3 @@ maxsize = maxsize || 1000;

} else {
// TODO: redo
return [0, -i+1, i-1];

@@ -198,64 +286,86 @@ }

function pair(a, b) {
/**
#### nat (maxsize : nat) : generator nat
Natural numbers, ℕ (0, 1, 2...)
*/
function nat(maxsize) {
maxsize = maxsize || 1000;
return {
arbitrary: function (size) {
return [a.arbitrary(size), b.arbitrary(size)];
size = Math.min(maxsize, size);
return getRandomInt(0, size);
},
shrink: function (i) {
if (i === 0) {
return [];
} else {
// TODO: redo
return [0, Math.floor(i/2)];
}
},
};
}
shrink: function (p) {
var x = p[0];
var y = p[1];
/**
#### number (maxsize : number) : generator number
return [].concat(
a.shrink(x).map(function (xp) { return [xp, y]; }),
b.shrink(y).map(function (yp) { return [x, yp]; })
);
JavaScript numbers, "doubles", ℝ. `NaN` and `Infinity` are not included.
*/
function number(maxsize) {
maxsize = maxsize || 1000;
return {
arbitrary: function (size) {
size = Math.min(maxsize, size);
return getRandomArbitrary(-size, size);
},
shrink: function () { return []; },
};
}
function oneof(args) {
assert(args.length !== 0, "oneof: at least one parameter expected");
/**
#### bool () : generator bool
return {
arbitrary: function (size) {
var i = getRandomInt(0, args.length-1);
return args[i];
},
Booleans, `true` or `false`.
*/
function bool() {
return {
arbitrary: function (size) {
var i = getRandomInt(0, 1);
return i === 0 ? false : true;
},
shrink: function () { return []; },
};
}
shrink: function (b) {
return b === true ? [false] : [];
},
};
}
function suchthat(generator, predicate) {
return {
arbitrary: function (size) {
while (true) {
var x = generator.arbitrary(size);
if (predicate(x)) {
return x;
}
}
},
/**
#### oneof (args : array any) : generator any
shrink: function (x) {
return generator.shrink(x).filter(predicate);
},
};
}
Random element of `args` array.
*/
function oneof(args) {
assert(args.length !== 0, "oneof: at least one parameter expected");
function bool() {
return {
arbitrary: function (size) {
var i = getRandomInt(0, 1);
return i === 0 ? false : true;
},
return {
arbitrary: function (size) {
var i = getRandomInt(0, args.length-1);
return args[i];
},
shrink: function (b) {
return b === true ? [false] : [];
},
};
}
// TODO: make shrink
shrink: function () { return []; },
};
}
function list(generator) {
/**
#### array (gen : generator a) : generator (array a)
*/
function array(generator) {
generator = generator || integer();

@@ -293,3 +403,3 @@

function nonshrinklist(generator) {
function nonshrinkarray(generator) {
generator = generator || integer();

@@ -313,2 +423,54 @@

/**
### Generator combinators
*/
/**
#### pair (a : generator A) (b : generator B) : generator (A * B)
If not specified `a` and `b` are equal to `integer()`.
*/
function pair(a, b) {
a = a || integer();
b = b || integer();
return {
arbitrary: function (size) {
return [a.arbitrary(size), b.arbitrary(size)];
},
shrink: function (p) {
var x = p[0];
var y = p[1];
return [].concat(
a.shrink(x).map(function (xp) { return [xp, y]; }),
b.shrink(y).map(function (yp) { return [x, yp]; })
);
},
};
}
/**
#### suchthat (gen : generator a) (p : a -> bool) : generator {a | p a == true}
Generator of values that satisfy `p` predicate. It's adviced that `p`'s accept rate is high.
*/
function suchthat(generator, predicate) {
return {
arbitrary: function (size) {
while (true) {
var x = generator.arbitrary(size);
if (predicate(x)) {
return x;
}
}
},
shrink: function (x) {
return generator.shrink(x).filter(predicate);
},
};
}
// Export

@@ -320,9 +482,11 @@ var jsc = {

// generators
nat: nat,
integer: integer,
bool: bool,
number : number,
bool: bool,
pair: pair,
list: list,
nonshrinklist: nonshrinklist,
oneof: oneof,
suchthat: suchthat,
array: array,
nonshrinkarray: nonshrinkarray,
oneof: oneof,
suchthat: suchthat,

@@ -334,2 +498,4 @@ // internal utility lib

withPromise: withPromise,
getRandomInt: getRandomInt,
getRandomArbitrary: getRandomArbitrary,
},

@@ -360,3 +526,4 @@ };

- 0.0.0 Initial preview
- 0.0.2 Documented preview
- 0.0.1 Initial preview

@@ -369,2 +536,4 @@ ## License

### JavaScript
- [JSCheck](http://www.jscheck.org/)

@@ -375,2 +544,11 @@ - [claire](https://npmjs.org/package/claire)

- [quickcheck](https://npmjs.org/package/quickcheck)
- [qc.js](https://bitbucket.org/darrint/qc.js/)
### Others
- [Wikipedia - QuickCheck](http://en.wikipedia.org/wiki/QuickCheck)
- [Haskell - QuickCheck](http://hackage.haskell.org/package/QuickCheck) [Introduction](http://www.haskell.org/haskellwiki/Introduction_to_QuickCheck1)
- [Erlang - QuviQ](http://www.quviq.com/index.html)
- [Erlang - triq](https://github.com/krestenkrab/triq)
- [Scala - ScalaCheck](https://github.com/rickynils/scalacheck)
*/
{
"name": "jsverify",
"description": "Property-based testing for JavaScript.",
"version": "0.0.1",
"version": "0.0.2",
"homepage": "https://github.com/phadej/jsverify",

@@ -6,0 +6,0 @@ "author": {

@@ -38,2 +38,106 @@

### Use with [jasmine](http://pivotal.github.io/jasmine/) 1.3.x
Check [jasmineHelpers.js](speclib/jasmineHelpers.js) file.
## API
> _Testing shows the presence, not the absence of bugs._
>
> Edsger W. Dijkstra
To show that propositions hold, we need to construct proofs.
There are two extremes: proof by example (unit tests) and formal (machine-checked) proof.
Property-based testing is something in between.
We formulate propositions, invariants or other properties we believe to hold, but
only test it to hold for numerous (random generated) values.
Types and function signatures are written in [Coq](http://coq.inria.fr/)/[Haskell](http://www.haskell.org/haskellwiki/Haskell) influented style:
C# -style `List<T> filter(List<T> v, Func<T, bool> predicate)` is represented by
`filter (v : array T) (predicate : T -> bool) : array T` in our style.
`jsverify` can operate with both synchronous and asynchronous-promise properties.
Generally every property can be wrapped inside [functor](http://learnyouahaskell.com/functors-applicative-functors-and-monoids),
for now in either identity or promise functor, for synchronous and promise properties respectively.
Some type definitions to keep developers sane:
- Functor f => property (size : nat) : f result
- result := true | { counterexample: any }
- Functor f => property_rec := f (result | property)
- generator a := { arbitrary : a, shrink : a -> [a] }
### jsc._ - miscellaneous utilities
#### assert (exp : bool) (message : string) : void
Throw an error with `message` if `exp` is falsy.
#### isPromise p : bool
Optimistic duck-type check for promises.
Returns `true` if p is an object with `.then` function property.
#### withPromise (Functor f) (p : f a) (f : a -> b) : f b
This is functor map, `fmap`, with arguments flipped.
Essentially `f(p)`. If `p` is promise, returns new promise.
Using `withPromise` makes code look very much [CPS-style](http://en.wikipedia.org/wiki/Continuation-passing_style).
#### getRandomArbitrary (min max : number) : number
Returns random number from `[min, max)` range.
#### getRandomInt (min max : int) : int
Returns random int from `[min, max]` range inclusively.
```js
getRandomInt(2, 3) // either 2 or 3
```
### Properties
#### forall (gen : generator a) (prop : a -> property_rec) : property
Property constructor
#### check (prop : property) : promise result + result
Run random checks for given `prop`. If `prop` is promise based, result is also wrapped in promise.
### Primitive generators
#### integer (maxsize : nat) : generator integer
Integers, ℤ
#### nat (maxsize : nat) : generator nat
Natural numbers, ℕ (0, 1, 2...)
#### number (maxsize : number) : generator number
JavaScript numbers, "doubles", ℝ. `NaN` and `Infinity` are not included.
#### bool () : generator bool
Booleans, `true` or `false`.
#### oneof (args : array any) : generator any
Random element of `args` array.
#### array (gen : generator a) : generator (array a)
### Generator combinators
#### pair (a : generator A) (b : generator B) : generator (A * B)
If not specified `a` and `b` are equal to `integer()`.
#### suchthat (gen : generator a) (p : a -> bool) : generator {a | p a == true}
Generator of values that satisfy `p` predicate. It's adviced that `p`'s accept rate is high.
## Contributing

@@ -44,2 +148,3 @@

- You can use `grunt jasmine-build` to generate `_SpecRunner.html` to run tests in your browser of choice.
- Use tabs for indentation

@@ -52,3 +157,4 @@ ### Preparing for release

- 0.0.0 Initial preview
- 0.0.2 Documented preview
- 0.0.1 Initial preview

@@ -61,2 +167,4 @@ ## License

### JavaScript
- [JSCheck](http://www.jscheck.org/)

@@ -67,1 +175,10 @@ - [claire](https://npmjs.org/package/claire)

- [quickcheck](https://npmjs.org/package/quickcheck)
- [qc.js](https://bitbucket.org/darrint/qc.js/)
### Others
- [Wikipedia - QuickCheck](http://en.wikipedia.org/wiki/QuickCheck)
- [Haskell - QuickCheck](http://hackage.haskell.org/package/QuickCheck) [Introduction](http://www.haskell.org/haskellwiki/Introduction_to_QuickCheck1)
- [Erlang - QuviQ](http://www.quviq.com/index.html)
- [Erlang - triq](https://github.com/krestenkrab/triq)
- [Scala - ScalaCheck](https://github.com/rickynils/scalacheck)

@@ -1,25 +0,5 @@

/* global jsc, _, describe, it, expect, beforeEach */
/* global jsc, _, Q, describe, it, expect, waitsFor, runs */
(function () {
"use strict";
beforeEach(function () {
this.addMatchers({
// Expects that property is synchronous
toHold: function () {
var actual = this.actual;
var notText = this.isNot ? " not" : "";
var r = jsc.check(actual);
var counterExampleText = r === true ? "" : "Counter example found: " + JSON.stringify(r.counterexample);
this.message = function() {
return "Expected property to " + notText + " to not hold." + counterExampleText;
};
return r === true;
},
});
});
describe("examples", function () {

@@ -50,2 +30,27 @@ it("failing inc", function () {

it("fixed inc - promise", function () {
function inc(i) {
return i + 1;
}
var propPromise = Q.delay(100).then(function () {
return jsc.forall(jsc.integer(), function (i) {
return inc(i) === i + 1;
});
});
// TODO: how to make matcher on promise?
var done = false;
propPromise.fin(function () { done = true; });
waitsFor(function () { return done; });
runs(function () {
propPromise.then(function (prop) {
expect(prop).toHold();
}, function (e) {
expect(false).toBe(true); // should be never executed
});
});
});
it("failing add", function () {

@@ -67,3 +72,3 @@ function add(i, j) {

function add(i, j) {
return i + (j && 1);
return i + (j && 1);
}

@@ -121,4 +126,4 @@

var prop = jsc.forall(jsc.nonshrinklist(), function (a) {
return jsc.forall(jsc.nonshrinklist(), function (b) {
var prop = jsc.forall(jsc.nonshrinkarray(), function (a) {
return jsc.forall(jsc.nonshrinkarray(), function (b) {
return intersects(a, b) === (_.intersection(a, b) !== []);

@@ -130,4 +135,4 @@ });

var prop2 = jsc.forall(jsc.list(), function (a) {
return jsc.forall(jsc.list(), function (b) {
var prop2 = jsc.forall(jsc.array(), function (a) {
return jsc.forall(jsc.array(), function (b) {
return intersects(a, b) === (_.intersection(a, b) !== []);

@@ -139,4 +144,4 @@ });

var prop3 = jsc.forall(jsc.list(), function (a) {
return jsc.forall(jsc.list(), function (b) {
var prop3 = jsc.forall(jsc.array(), function (a) {
return jsc.forall(jsc.array(), function (b) {
return intersects(a, b) === (_.intersection(a, b).length !== 0);

@@ -149,4 +154,4 @@ });

/*
var prop4 = jsc.forall(jsc.list(), function (a) {
return jsc.forall(jsc.list(), function (b) {
var prop4 = jsc.forall(jsc.array(), function (a) {
return jsc.forall(jsc.array(), function (b) {
return q.delay(10).then(function () {

@@ -165,6 +170,2 @@ return intersects(a, b) === (_.intersection(a, b).length !== 0);

it("booleans", function () {
var true_and_right_prop = jsc.forall(jsc.bool(), function (x) {
return x && true === x;
});
var true_and_left_prop = jsc.forall(jsc.bool(), function (x) {

@@ -174,5 +175,11 @@ return true && x === x;

expect(true_and_right_prop).not.toHold(); // be careful!
expect(true_and_left_prop).toHold();
var true_and_right_prop = jsc.forall(jsc.bool(), function (x) {
return x && true === x;
});
expect(true_and_right_prop).not.toHold(); // be careful!
var true_and_right_fixed_prop = jsc.forall(jsc.bool(), function (x) {

@@ -222,7 +229,7 @@ return (x && true) === x;

it("array indexOf", function () {
var nonemptylist = jsc.suchthat(jsc.list(), function (l) {
var nonemptyarray = jsc.suchthat(jsc.array(), function (l) {
return l.length !== 0;
});
var prop = jsc.forall(nonemptylist, function (l) {
var prop = jsc.forall(nonemptyarray, function (l) {
return jsc.forall(jsc.oneof(l), function (x) {

@@ -235,3 +242,47 @@ return l.indexOf(x) !== -1;

});
it("numbers", function () {
var nat_nonnegative_prop = jsc.forall(jsc.nat(), function (n) {
return n >= 0;
});
expect(nat_nonnegative_prop).toHold();
var integer_round_noop_property = jsc.forall(jsc.integer(), function (n) {
return Math.round(n) === n;
});
expect(integer_round_noop_property).toHold();
var number_round_noop_property = jsc.forall(jsc.number(), function (n) {
return Math.round(n) === n;
});
expect(number_round_noop_property).not.toHold();
});
it("_.sortBy idempotent", function () {
var prop1 = jsc.forall(jsc.array(), function (l) {
return _.isEqual(_.sortBy(l), l);
});
expect(prop1).toHold();
function sort(l) {
return _.sortBy(l, _.identity);
}
var prop2 = jsc.forall(jsc.array(), function (l) {
return _.isEqual(sort(l), l);
});
expect(prop2).not.toHold();
var prop3 = jsc.forall(jsc.array(), function (l) {
return _.isEqual(sort(sort(l)), sort(l));
});
expect(prop3).toHold();
});
});
}());
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc