package exenum

  1. Overview
  2. Docs
Build efficient enumerations for datatypes. Inspired by Feat for Haskell.

Install

Dune Dependency

Authors

Maintainers

Sources

0.86.tar.gz
md5=a4854a0286dfd8bcb3f34003365195a9

Description

The exenum library offers constructors to build enumerations for datatypes, that is, functions from (arbitrarily large) integers to values. Such enumerations are typically used for unit testing. The library is efficient: the n-th element of an enumeration is returned without having computed the (n-1) previous elements. Complexity is in log(n), except for some pathological datatypes. See the homepage for details: https://github.com/lebotlan/ocaml-exenum Inspired by Feat: Functional Enumeration of Algebraic Types, by Duregard, Jansson, Wang, Chalmers University.

As an example, consider the following datatype: type term = Var of string | App of term * term | Lambda of string * term

Using exenum, one may easily generate zillions of different lambda-terms. In our specific example, term number 2000000000000 happens to be ((((x v) (fun u -> y)) ((fun u -> y) (fun y -> y))) (((x v) (fun u -> v)) (fun u -> y)))

Published: 14 Aug 2018

README

ocaml-exenum

exenum is an OCaml library that helps building exhaustive or semi-exhaustive data sets, typically for intensive unit testing.

Inspired by testing-feat for Haskell.

Install

Install with opam: opam install exenum

API Documentation

The Exenum API. See also the examples/ dir.

The ocamlfind package names are exenum and exenum.lwt (the latter is installed only if lwt is present).

When using exenum.lwt, you need to compile with the following packages (in ocamlbuild's _tag notation): package(lwt,exenum,exenum.lwt,lwt.ppx)

Overview

We consider a simple example.

  • Assume that, for testing purposes, we need many values of type int list.

open Exenum

(* Build a new enumeration of type int list. *)
let enum_intlist = e_list e_int
  • Because pretty-printing matters, we take the time to define string_of_intlist:

let string_of_intlist l = "[" ^ String.concat ", " (List.map string_of_int l) ^ "]"
  • We ask Exenum to show a few values of this enumeration:

let () = show enum_intlist string_of_intlist 0 11
Value #0 is []
Value #1 is [2]
Value #2 is [0]
Value #3 is [3]
Value #4 is [1]
Value #5 is [-2]
Value #6 is [-1]
Value #7 is [-3]
Value #8 is [4, 2]
Value #9 is [1, 2]
Value #10 is [0, -2]
  • We are curious. What are values at a very large index?

let index = Z.pow (Z.of_int 10) 200 (* Indeed, this is 10^200. *)
let () = bigshow enum_intlist string_of_intlist index 2
Value #0 is [-11141639911, 19603183504, -15283679472, 6656783909, 1634524031, -471077998, 112885229, -223859756, -132220646, -7807730, -47780089, 30956540, -11221453, 3859390, 2834978, 2087393, 895525, -306900, -121738, -9063, 29280, 23372, 13852, -6911, -2887, 1103, 846, -253, -68, -13, 43, 10, -4, -2]
Value #1 is [13635890183, -19174930941, -15838074444, -4484269954, -2648391618, -1149614834, 645802777, -18833984, 256671692, 42265941, -44644927, 19249984, 2972215, -5443265, 2028581, 844099, 519800, 375847, -76182, 27590, -64122, 29835, 14849, -7121, 4030, -327, -753, -498, 104, -8, 47, 0, -5, 4, -1]
  • Notice how these two values, which are adjacent in the enumeration, are (purposely) significantly different.

  • Computing values at a large index is quick (the complexity is basically logarithmic with respect to the index).

  • Testing a function

(* This is the function we wish to test. *)
let mysum l = List.fold_left (+) 0 l

(* This is the test we perform on mysum. *)
let test_mysum l =
  let sum1 = mysum l
  
  (* Here, we use an oracle to check if the function is right. *)
  and sum2 = List.fold_right (+) l 0 in

  assert (sum1 = sum2)
  
(* Exenum provides a 'tester', which applies test_mysum continuously. *)  
let () = tester enum_intlist ~tos:string_of_intlist ~len:1000 ~verbose_period:10000 test_mysum
  • The ~len argument is the number of consecutive indices which are tested before doubling the current index.

  • A message is printed every ~verbose_period tests.

Test number 0, index #0 ... with [] ... done
Test number 10000, index #2046000 ... with [51, 8, -9, 3, 2] ... done
Test number 20000, index #2097150000 ... with [8, 0, 17, 3, 2, 2] ... done
Test number 30000, index #2147483646000 ... with [212, 107, -20, -9, 15, 0, -1] ... done
Test number 40000, index #2199023255550000 ... with [-158, 4, 30, -48, 15, 5, -7, -2] ... done
Test number 50000, index #2251799813685246000 ... with [47, 93, -244, -54, 5, 11, -13, 3, -3] ... done
Test number 60000, index #2305843009213693950000 ... with [746, -191, 499, 61, -58, 31, -21, 9, 5, 2] ... done
...
(and so on, you have to interrupt)

Contact

Didier Le Botlan, github.lebotlan@dfgh.met where you replace .met by .net.

Dependencies (3)

  1. zarith
  2. dune
  3. ocaml >= "4.02.3"

Dev Dependencies

None

Used by

None

Conflicts (1)

  1. lwt >= "4.0.0"