{"id":21909857,"url":"https://github.com/andrenth/ospec","last_synced_at":"2025-10-19T15:41:28.475Z","repository":{"id":530442,"uuid":"159390","full_name":"andrenth/ospec","owner":"andrenth","description":"BDD for OCaml","archived":false,"fork":false,"pushed_at":"2013-07-23T11:48:31.000Z","size":220,"stargazers_count":26,"open_issues_count":0,"forks_count":4,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-16T02:12:20.907Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrenth.png","metadata":{"files":{"readme":"README","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2009-03-25T19:54:59.000Z","updated_at":"2023-06-04T11:43:41.000Z","dependencies_parsed_at":"2022-07-07T14:05:05.467Z","dependency_job_id":null,"html_url":"https://github.com/andrenth/ospec","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrenth%2Fospec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrenth%2Fospec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrenth%2Fospec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrenth%2Fospec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrenth","download_url":"https://codeload.github.com/andrenth/ospec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249183106,"owners_count":21226142,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-28T17:26:31.020Z","updated_at":"2025-10-19T15:41:23.443Z","avatar_url":"https://github.com/andrenth.png","language":"OCaml","readme":"                               ospec\n                               ~~~~~\n\n1. INTRODUCTION\n---------------\n\nOSpec is a Behavior-Driven Development tool for OCaml, inspired by RSpec, a\nRuby BDD library. It is implemented as a Camlp4 syntax extension.\n\nThis is a work in progress and should be considered beta quality.\n\nNote: OSpec requires OCaml \u003e= 3.10.0 to run. On versions below 3.11.0, though,\nthere are two limitations due to OCaml toplevel bugs:\n\n* If you want to use helpers in your specifications (see below), you must\n  explicitely \"open Helpers\" at the top of every specification file.\n\n* Running the \"ospec\" command with multiple files as arguments doesn't work.\n\n\n2. USAGE\n--------\n\nTo build and install OSpec, simply type\n\n  $ ocaml setup.ml -configure\n  $ ocaml setup.ml -build\n  # ocaml setup.ml -install\n\nThese commands (and OSpec itself) rely on findlib, so you need to have it\ninstalled for them to work. An executable called \"ospec\" which takes\nspecification files as command line arguments will be build. For example, the\ncommand below will run the specifications in the file specs.ml:\n\n  $ ospec specs.ml\n\nThe default report format is \"nested\". You can choose the format from the\ncommand line using the \"-format\" option. Currently the available formats are\n\"nested\" and \"progress\".\n\n\n3. SYNTAX\n---------\n\nSpecifications are defined with the \"describe\" keyword. Inside a specification,\nexamples are defined, with the \"it\" keyword, including one or more expectations.\nExpectations are tests comparing some result to an expected value using the\n\"should\" keyword.\n\nHere's useless specification which shows how OSpec's syntax works:\n\n  describe \"The number one\" do\n    it \"should equal 2 when added to itself\" do\n      (1 + 1) should = 2  (* anything 'a -\u003e 'a -\u003e bool should work *)\n    done;\n\n    it \"should be positive\" do\n      let positive x = x \u003e 0 in\n      1 should be positive  (* 'a -\u003e bool should work too *)\n    done;\n\n    it \"should be negative when multiplied by -1\" do\n      let x = 1 * (-1) in\n      x should be \u003c 0;      (* \"be\" is optional *)\n      x should not be \u003e= 0\n    done;\n\n    it \"should fail when divided by 0\" do\n      (* For exception tests, wrap it in a fun *)\n      let f = fun () -\u003e 1 / 0 in\n      f should raise_an_exception;\n      f should raise_exception Division_by_zero;\n      f should not raise Exit\n    done;\n\n    it \"should match ^[0-9]+$ when converted to a string\" do\n      (string_of_int 1) should match_regexp \"^[0-9]+$\"\n    done;\n\n    (* Specify behaviors still not implemented like this *)\n    it \"should be cool\"\n  done\n\nIt is also possible to group related examples in nested specifications. See\nexamples/nested.ml for a sample.\n\n\n4. BEFORE AND AFTER BLOCKS\n--------------------------\n\nOSpec supports \"before\" and \"after\" blocks, which can be used to run code\nbefore or after running the examples. This is only useful for operations\nwhich cause side-effects on some global variable (see examples/hooks.ml).\nDefining a variable in a \"before\" block doesn't make it available for the\nexamples, since the scope of such a variable would be the \"before\" block\nitself.\n\n  describe \"An example\" do\n    before all do\n      (* Code here runs once, before all examples. *)\n    done;\n\n    before each do\n      (* Code here runs before each example. *)\n    done;\n\n    after each do\n      (* Code here runs after each example. *)\n    done;\n\n    after all do\n      (* Code here runs once, after all examples. *)\n    done;\n\n    it \"should behave in a certain way\" do\n      (* ... *)\n    done\n  done\n\n\n5. MATCH SYNTAX EXTENSION\n-------------------------\n\nOSpec also extends the \"match\" syntax so that you can write expectations like\n\n  [1] should match h::t\n  [1] should not match []\n\n\n6. PROPERTY TESTING\n-------------------\n\nOSpec provides support for property testing with the \"forall\" function.\nCombining forall with a sample generator (either one of the provided generators\nor a custom one), it is possible to write specifications such as\n\n  describe \"A list\" do\n    it \"should equal itself when reversed twice\" do\n      forall (list_of int) l . (List.rev (List.rev l)) should = l\n    done\n  done\n\nIn the example above, two generators are used: \"list_of\" and \"int\". The former\nis a higher-order generator, since it takes another sample generator as a\nparameter. This generator is used to sample values which the random list will\ncontain (in this case, int values). Each sample list will be bound to \"l\",\nwhich can then be used in the property specified after the dot.\n\nIt is also possible to specify constraints to the generated samples, such as\nin the (contrived) example below.\n\n  describe \"A bool\" do\n    it \"should be true if all samples are true\" do\n      forall bool b . b = true -\u003e b should = true\n    done\n  done\n\nIf the value of the boolean expression before the arrow is false for a given\nsample, it is discarded and a new one is generated.\n\nBy default, 100 samples are generated for each property test. A different\nnumber of samples may be specified explicitly as in the example below.\n\n  forall 42 bool b . b = true -\u003e b should = true\n\nThis will generate 42 bool instances instead of the default 100.\n\n\n7. PREDEFINED GENERATORS\n------------------------\n\nBelow is a list of sample generators defined by OSpec. They can be used as\nbuilding blocks for custom generators for more complex data types. A generator\nis simply a function of type (unit -\u003e 'a). By convention, higher-order\ngenerators are named with an \"_of\" suffix.\n\nval bool : unit -\u003e bool\n  Generates true or false with 50% probabilty each.\n\nval float : unit -\u003e float\n  Generates a random float in the interval [0, 1).\n\nval int : unit -\u003e int\n  Generates a random int between 0 (inclusive) and max_int (exclusive).\n\nval int_in_range : int -\u003e int -\u003e unit -\u003e int\n  Generates a random int in the inclusive range given by the two int arguments.\n\nval int32 : unit -\u003e Int32.t\n  Generates a random int32 between 0 (inclusive) and Int32.max_int (exclusive).\n\nval int32_in_range : int32 -\u003e int32 -\u003e unit -\u003e int32\n  Generates a random int32 in the inclusive range given by the two int32\n  arguments.\n\nval int64 : unit -\u003e Int64.t\n  Generates a random int64 between 0 (inclusive) and Int64.max_int (exclusive).\n\nval int64_in_range : int64 -\u003e int64 -\u003e unit -\u003e int64\n  Generates a random int64 in the inclusive range given by the two int64\n  arguments.\n\nval nativeint : unit -\u003e Nativeint.t\n  Generates a random nativeint between 0 (inclusive) and Nativeint.max_int\n  (exclusive).\n\nval nativeint_in_range : nativeint -\u003e nativeint -\u003e unit -\u003e nativeint\n  Generates a random nativeint in the inclusive range given by the two nativeint\n  arguments.\n\nval char : unit -\u003e char\n  Generates a random character.\n\nval char_in_range : char -\u003e char -\u003e unit -\u003e char\n  Generates a random character in the inclusive range given by the two char\n  arguments.\n\nval ascii : unit -\u003e char\n  Generates a random ASCII character.\n\nval digit : unit -\u003e char\n  Generates a random digit character.\n\nval lowercase : unit -\u003e char\n  Generates a random lowercase character [a-z].\n\nval uppercase : unit -\u003e char\n  Generates a random uppercase character [A-Z].\n\nval alphanumeric : unit -\u003e char\n  Generates a random alphanumeric character.\n\nval string_of : ?length:(unit -\u003e int) -\u003e (unit -\u003e char) -\u003e unit -\u003e string\n  Given one of the character generators, returns a random string of length\n  given by the \"length\" int generator.\n\nval string : ?length:(unit -\u003e int) -\u003e unit -\u003e string\n  Generates a random string of ASCII characters. It is equivalent to\n  \"string_of ascii\".\n\nval list_of : ?length:(unit -\u003e int) -\u003e (unit -\u003e 'a) -\u003e unit -\u003e 'a list\n  Given a generator for the list elements, returns a random list of length\n  given by the \"length\" int generator.\n\nval list : ?length:(unit -\u003e int) -\u003e unit -\u003e unit list\n  Generates a random-sized list of unit elements.\n\nval array_of : ?length:(unit -\u003e int) -\u003e (unit -\u003e 'a) -\u003e unit -\u003e 'a array\n  Given a generator for the array elements, returns a random array of length\n  given by the \"length\" int generator.\n\nval array : ?length:(unit -\u003e int) -\u003e unit -\u003e unit array\n  Generates a random-sized array of unit elements.\n\nval queue_of : ?length:(unit -\u003e int) -\u003e (unit -\u003e 'a) -\u003e unit -\u003e 'a Queue.t\n  Given a generator for the queue elements, returns a random queue of length\n  given by the \"length\" int generator.\n\nval queue : ?length:(unit -\u003e int) -\u003e unit -\u003e unit queue\n  Generates a random-sized queue of unit elements.\n\nval stack_of : ?length:(unit -\u003e int) -\u003e (unit -\u003e 'a) -\u003e unit -\u003e 'a Stack.t\n  Given a generator for the stack elements, returns a random stack of length\n  given by the \"length\" int generator.\n\nval stack : ?length:(unit -\u003e int) -\u003e unit -\u003e unit stack\n  Generates a random-sized stack of unit elements.\n\nval hashtbl_of : ?length:(unit -\u003e int) -\u003e (unit -\u003e 'a) * (unit -\u003e 'b) -\u003e unit -\u003e\n                 ('a, 'b) Hashtbl.t\n  Given a tuple of generators for the hash table keys and values, returns a\n  random hash table of length given by the \"length\" int generator.\n\n\n8. HELPERS\n----------\n\nSome helper functions are provided, as shown above. They are described below.\n\nval raise_an_exception : (unit -\u003e 'a) -\u003e bool\n  Returns true if any exception is raised\n\nval raise_exception : (unit -\u003e 'a) -\u003e exn -\u003e bool\n  Returns true if the given exception is raised\n\nval match_regexp : string -\u003e string -\u003e bool\n  Returns true if the given string (first argument) matches the given regex\n  (second argument).\n\n\n9. TODO\n-------\n\n* Provide more report formats.\n* Provide more helpers.\n* Cleanup the code, which is horrible and hacky.\n* ...\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrenth%2Fospec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrenth%2Fospec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrenth%2Fospec/lists"}