Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

QuickCheck implementation for Dart

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 README.md
Octocat-spinner-32 arbitrary.dart
Octocat-spinner-32 builders.dart
Octocat-spinner-32 helpers.dart
Octocat-spinner-32 main.dart
Octocat-spinner-32 qc.dart
Octocat-spinner-32 reports.dart
Octocat-spinner-32 runner.dart
Octocat-spinner-32 tests.dart
README.md

Dart QuickCheck

Abstract

'Dart QuickCheck' (or simply qc) is a set of hacks developed in a try to port Haskell Quickcheck to Dart language. Abandon all hope you, who want to actually use it for a real project. There are no plans to maintain or support it.

For more info on QuickCheck and property based tetsing read Wikipedia Article

Example usage

The most canonical example is to test Lists reverse function. Of course, for this we have to create one ourselves :) , like this:

reverse(L) {
  var L2 = [];
  for (int i = L.length -1; i>=0; --i) {
    L2.add(L[i]);         
  }
  return L2;
}

And make a small helper to test for list equality:

listsEqual(L1, L2) {
  try {
    Expect.listEquals(L1, L2);
  } catch (var _) {
    return false;
  }
  return true;  
}

And then, after very annoying couple of minutes we can actulay test our function:

#import("qc.dart");

main() {
  property("reverse of reverse of list should equal to initial list",
    ForAll.lists.with.integers,
    (xs) => listsEqual(xs, reverse(reverse(xs))));
  checkAll();
}

You can also ask qc to output all inputs it passes to function by calling beVerbose() function. For example:

#import("qc.dart");

main() {
  property("reverse of reverse of list should equal initial list",
    ForAll.lists.with.integers,
    (xs) => listsEqual(xs, reverse(reverse(xs))));

  beVerbose();
  checkAll();
}

will result in (output is truncated):

Testing property: 'reverse of reverse of list should equal initial list'
  SUCCESS for '[]'
  SUCCESS for '[36, 42, 21, 29, 33, 16, 8, 4, 2, 1, 0, 0, 0, 0, 24, 12, 6, 21, 10, 5, 2, 1, 0]'
    SUCCESS for '[29, 33, 16, 8, 23, 11, 5, 2, 1, 24, 36, 42, 40, 38, 38, 37, 37, 37, 37, 18]'
    SUCCESS for '[4, 2, 25, 36, 42, 40, 38, 19, 9]'
    SUCCESS for '[26, 13, 6, 3]'
    SUCCESS for '[12, 30, 34, 41, 20, 10, 5, 2, 1, 0, 0, 24, 36, 42, 21, 29, 33, 40, 20, 10, 23, 36, 42, 39, 19]'
    SUCCESS for '[23, 36, 18, 27, 13, 31, 34, 41, 39]'
    SUCCESS for '[9, 4, 2, 25, 36, 42, 40, 20, 10, 23, 36, 42, 21, 29, 33, 16, 27, 32, 16]'
    SUCCESS for '[13, 6, 22, 35, 17, 27, 13, 31, 34, 41, 20, 29, 33, 40, 20, 29, 33, 16, 27, 32, 40, 20, 10, 5, 2, 1]'
  ...

SUCCESS: tested 1 properties.

For more examples take a look at our extensive set of tests for qc itself :)

#import("qc.dart");

main () {
  property("any int over 5", ForAll.positiveIntegers.greaterThan(5), (x) => x > 5);
  property("any int under 5", ForAll.positiveIntegers.lessThan(5), (x) => x < 5); 

  property("positive ints", ForAll.positiveIntegers, (x) => x > 0);
  property("negative ints", ForAll.negativeIntegers, (x) => x < 0);
  property("non-negative ints", ForAll.nonNegativeIntegers, (x) => x >= 0);
  property("non-positive ints", ForAll.nonPositiveIntegers, (x) => x <= 0);
  property("integers", ForAll.integers, (x) => x is int);

  property("chars", ForAll.chars, (x) => x is String);
  property("chars in range", ForAll.chars.ofRange('A','F'), (x) => "ABCDEF".indexOf(x) != -1);

  property("lists of positive integers", ForAll.lists.with.positiveIntegers, 
    (x) => x is List && x.every((e) => e >= 0)
  );

  property("lists of list of integers", ForAll.lists.with.lists.with.positiveIntegers, 
    (x) => x is List && x.every((e) => e is List)
  );

  property("lists of length", ForAll.lists.ofLength(3).with.integers.between(1, 3), 
    (xs) => xs.length == 3);

  property("choice", ForAll.objectsIn([1, "a"]), (x) => x == 1 || x == "a");
  property("list of choice", ForAll.lists.with.objectsIn([1, "a"]), 
    (xs) => xs.every((x) => x == 1 || x == "a")
  );
  checkAll();
}

The result of execution will be:

Testing property: 'any int over 5'
Testing property: 'any int under 5'
Testing property: 'positive ints'
Testing property: 'negative ints'
Testing property: 'non-negative ints'
Testing property: 'non-positive ints'
Testing property: 'integers'
Testing property: 'chars'
Testing property: 'chars in range'
Testing property: 'lists of positive integers'
Testing property: 'lists of list of integers'
Testing property: 'lists of length'
Testing property: 'choice'
Testing property: 'list of choice'

SUCCESS: tested 14 properties.

Something went wrong with that request. Please try again.