{"id":20782858,"url":"https://github.com/janiczek/elm-minithesis","last_synced_at":"2025-04-30T23:59:05.733Z","repository":{"id":42743477,"uuid":"281509251","full_name":"Janiczek/elm-minithesis","owner":"Janiczek","description":"An Elm port of Minithesis","archived":false,"fork":false,"pushed_at":"2024-08-26T15:18:35.000Z","size":717,"stargazers_count":16,"open_issues_count":22,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-30T23:59:00.529Z","etag":null,"topics":["elm","hypothesis","minithesis","property-based-testing"],"latest_commit_sha":null,"homepage":"","language":"Elm","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Janiczek.png","metadata":{"files":{"readme":"README.md","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":"2020-07-21T21:35:34.000Z","updated_at":"2024-07-01T08:54:07.000Z","dependencies_parsed_at":"2023-01-27T01:16:40.319Z","dependency_job_id":null,"html_url":"https://github.com/Janiczek/elm-minithesis","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Janiczek%2Felm-minithesis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Janiczek%2Felm-minithesis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Janiczek%2Felm-minithesis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Janiczek%2Felm-minithesis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Janiczek","download_url":"https://codeload.github.com/Janiczek/elm-minithesis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251801180,"owners_count":21645968,"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":["elm","hypothesis","minithesis","property-based-testing"],"created_at":"2024-11-17T14:15:10.856Z","updated_at":"2025-04-30T23:59:05.713Z","avatar_url":"https://github.com/Janiczek.png","language":"Elm","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IMPORTANT:\n\nSee also :sparkles:\n[`elm-microthesis`](https://github.com/Janiczek/elm-microthesis) :sparkles: (and\nits various branches/tags) which is more Elm-idiomatic implementation of the\nsame ideas. The repo you are currently viewing is a more direct port of the\nPython Minithesis idea. Read below.\n\n# `elm-minithesis`\n\n`elm-minithesis` is a property-based testing library based on [Minithesis](https://github.com/drmaciver/minithesis), which is the minimal implementation of the core idea of [Hypothesis](https://github.com/HypothesisWorks/hypothesis).\n\n\u003e Read more in the [About](#About) section.\n\n```elm\nimport Minithesis.Fuzz as Fuzz exposing (Fuzzer)\nimport Minithesis exposing (Test, TestResult)\n\nints : Fuzzer (List Int)\nints =\n    Fuzz.list (Fuzz.int 0 10000)\n\n\nfindsSmallList : Test (List Int)\nfindsSmallList =\n    Minithesis.test \"list always sums under 1000 lol\" ints \u003c|\n        \\fuzzedList -\u003e\n            List.sum fuzzedList \u003c= 1000\n\n\n{-| Will fail and shrink to the minimal example:\n\n`( \"list always sums under 1000 lol\", FailsWith [ 1001 ] )`\n\n-}\nresult : Int -\u003e TestResult (List Int)\nresult seed =\n    Minithesis.run seed findsSmallList\n\n\n{-| Running these tests inside elm-test can be done via functions inside\nthe Test.Minithesis module\n-}\ntest : Test.Test\ntest =\n    Test.Minithesis.mFuzz findsSmallList\n```\n\n# Tips and tricks\n\n## Examples\n\nTry `Fuzz.example` and `Fuzz.exampleWithSeed` in the REPL for quick\nsanity checks of your fuzzers! \n\n```elm\nimport Minithesis.Fuzz as F\n\nF.string |\u003e F.exampleWithSeed 0\n--\u003e gives 10 examples\n[\"x\",\"I\",\"\",\"6a=U\",\";W?\",\"uDc\",\":ei_^~\",\"=Y\",\"-NAT\\\\QJ\",\"{92H2DI}-(KOc\"]\n\nF.string |\u003e F.exampleWithSeed 1\n--\u003e different seed -\u003e different examples\n[\"KI\",\"\u003cj XT\",\"\",\"'xpvdQ1ONkM/\",\"tdVd_v\",\"I3=:e0i3\",\"\",\"P)y8$e@^y}1s\",\",]uz\\\\\",\"8\"]\n```\n\n## Inspect shrink history\n\nUse the `showShrinkHistory` field of `Minithesis.runWith` to get additional\ninformation about how shrinking of your data went. All `FailsWith` results\nbecome `FailsWithShrinks` containing additional info. This gives a bit of\nvisibility into what happens in the black box that Minithesis shrinking is. \n\n\n```elm\nimport Minithesis as M\nimport Minithesis.Fuzz as F\n\nM.runWith \n  { maxExamples = 100\n  , showShrinkHistory = True \n  } \n  1\n  (M.test \"list always sums under 1000 lol\"\n    (F.list (F.int 0 10000))\n    (\\list -\u003e List.sum list \u003c= 1000)\n  )\n--\u003e \n( \"list always sums under 1000 lol\"\n, FailsWithShrinks \n    { finalRun = [1,1001,0]\n    , finalValue = [1001]\n    , history = \n        [ value = [166,5536,4725,8499,7844,1727], { run = [1,166,1,5536,1,4725,1,8499,1,7844,1,1727,0], shrinkerUsed = \"Initial\"                                                           }\n        , value = [166,5536],                     { run = [1,166,1,5536,0],                             shrinkerUsed = \"DeleteChunkAndMaybeDecrementPrevious { size = 8, startIndex = 5 }\" }\n        , value = [5536],                         { run = [1,5536,0],                                   shrinkerUsed = \"DeleteChunkAndMaybeDecrementPrevious { size = 2, startIndex = 1 }\" }\n        , value = [1001],                         { run = [1,1001,0],                                   shrinkerUsed = \"MinimizeChoiceWithBinarySearch { index = 1 }\"                      }\n        ] \n    }\n)\n```\n\nPaired with some knowledge about which shrinking strategies there are and what\nthey do, you can sometimes tweak your fuzzers to optimize how they interact with\nthe shrinking process, allowing them to be shrunk better.\n\n(Related: [Hypothesis docs: \"Strategies that shrink\"](https://github.com/HypothesisWorks/hypothesis/blob/master/guides/strategies-that-shrink.rst))\n\n# About\n\n`elm-minithesis` is a property-based testing library based on [Minithesis](https://github.com/drmaciver/minithesis), which is the minimal implementation of the core idea of [Hypothesis](https://github.com/HypothesisWorks/hypothesis).\n\nHypothesis itself is a Python testing library for property-based testing. What\nsets it apart is its underlying implementation: instead of working on the\ngenerated values themselves (defining shrinkers on these values, eg. saying that\na Bool will shrink from `True` to `[False]` and from `False` to `[]`), it\nremembers the underlying random \"dice rolls\" that were used to generate the\nvalues, and it shrinks *those*. \n\n```elm\n-- \"type-based shrinking\"\n-- (QuickCheck and most other property-based testing libraries, including elm-test)\nshrink : a -\u003e LazyList a -- has to be defined for each fuzzed type,\n                         -- doesn't shrink by default\n\n-- \"integrated shrinking\"\n-- (Hypothesis, jqwik, elm-minithesis :) )\nshrink : List Int -\u003e LazyList (List Int) -- shrinks all fuzzers automatically,\n                                         -- can't be configured\n```\n\nA very cool consequence of the above is is that it mostly sidesteps the issue\nmost other property-based testing libraries have: `andThen` (monadic bind). More\nspecifically, QuickCheck-like libraries either don't expose `andThen` at all (as\nis the case with Elm), or struggle with making the shrunk values satisfy the\nsame invariants the `andThen`-generated values do. Hypothesis instead shrinks\nthe underlying \"dice roll\" history and generates a new value from that, so\nits values satisfy the invariants out of the box even if using `andThen`!\n\n(Source: [Hypothesis blog: \"Integrated vs type based shrinking\"](https://hypothesis.works/articles/integrated-shrinking/))\n\n# Community\n\nThere is a small piece of internet dedicated to `elm-minithesis`: [the\n`#elm-minithesis` channel on Incremental Elm\nDiscord](https://discord.gg/PC7Ckpg). Come join and hear about updates first!\n\nThe original discussion around `elm-minithesis` happened on the [Elm\nDiscourse](https://discourse.elm-lang.org/t/elm-minithesis-shrinking-without-compromises/6071/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaniczek%2Felm-minithesis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaniczek%2Felm-minithesis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaniczek%2Felm-minithesis/lists"}