The problem: Given a big, hairy, often-changing Route
custom type, and a pair of functions Route -> String
and String -> Maybe Route
, how can we be sure that (almost) every Route turned into a string and back into Route produces the same value that we started with?
Route
looks like:
module Route exposing (..)
import UserRoutes exposing UserRoutes
import TaskRoutes exposing TaskRoutes
type Route
= Home
| Settings
| About
| User String UserRoutes
| Task Int TaskRoutes
-- ...dozens more...
Is there some tool I can point at Route.elm, say “give me the structure of the Route
type”, and have it follow the module imports, so that it returns an enumerable list of properties? Something like:
{
type: "CustomType",
name: "Route",
members: [
{
name: "Home",
},
{
name: "Settings",
},
{
name: "About",
},
{
name: "User",
args: [
{
type: "String",
},
{
type: "CustomType",
name: "UserRoutes",
members: [
{
name: "Summary",
},
{
name: "Activity",
},
// ... etc ...
],
}
],
},
{
name: "Task",
args: [
{
type: "Int",
},
{
type: "CustomType",
name: "TaskRoutes",
members: [
{
name: "Active",
},
{
name: "Overdue",
},
// ... etc ...
],
}
],
},
// ... etc ...
]
}
I’m thinking that I’d use that to generate a RouteTest.elm file that uses default (or fuzzed) values for the Ints and Strings, which might look like:
suite : Test
suite =
describe "routes"
[ test "should parse generated cases" <|
\_ ->
let
data =
[ Home
, Settings
, About
, User "a" UserRoutes.Summary
, User "a" UserRoutes.Activity
, Task 1 TaskRoutes.Active
, Task 1 TaskRoutes.Overdue
-- ... plus the rest ...
]
actual =
data |> List.map (routeToString >> routeFromString)
expected =
data |> List.map Just
in
actual |> Expect.equalLists expected
]