Verified Commit 6c3fe26e authored by Camil Staps's avatar Camil Staps 🚀

Support @property and friends on instances

parent f2ead2e9
Pipeline #28980 passed with stage
in 5 minutes and 18 seconds
...@@ -18,7 +18,7 @@ Minimal test suites use only \nameref{sec:property}, though \nameref{sec:propert ...@@ -18,7 +18,7 @@ Minimal test suites use only \nameref{sec:property}, though \nameref{sec:propert
\subsubsection{\clean{@property}} \subsubsection{\clean{@property}}
\label{sec:property} \label{sec:property}
\availableon{functions} \availableon{functions; instances}
In properties, the full Clean syntax can be used to specify Gast properties. In properties, the full Clean syntax can be used to specify Gast properties.
Since Gast is automatically imported (see \cref{sec:property-bootstrap}), you can use its combinators. Since Gast is automatically imported (see \cref{sec:property-bootstrap}), you can use its combinators.
The first line of a property indicates its name and arguments. The first line of a property indicates its name and arguments.
...@@ -86,7 +86,7 @@ Then we can use this invariant in the definition of the correctness property of ...@@ -86,7 +86,7 @@ Then we can use this invariant in the definition of the correctness property of
\subsubsection{\clean{@precondition}} \subsubsection{\clean{@precondition}}
\label{sec:precondition} \label{sec:precondition}
\availableon{functions} \availableon{functions; instances}
This is a convenience field for functions that already have a(t least one) \nameref{sec:property} field. This is a convenience field for functions that already have a(t least one) \nameref{sec:property} field.
Its content should be an arbitrary Clean expression with type \clean{Bool} or \clean{Property}. Its content should be an arbitrary Clean expression with type \clean{Bool} or \clean{Property}.
...@@ -157,7 +157,7 @@ For example: ...@@ -157,7 +157,7 @@ For example:
\subsubsection{\clean{@property-test-with}} \subsubsection{\clean{@property-test-with}}
\label{sec:property-test-with} \label{sec:property-test-with}
\availableon{modules; functions} \availableon{modules; functions; instances}
With this field it is possible to abstract from concrete types in property signatures and still allow Gast to generate test values. With this field it is possible to abstract from concrete types in property signatures and still allow Gast to generate test values.
We can specify the correctness property of \module{Data.Set}'s \clean{member} function (\cref{sec:property}) more abstractly using \clean{a} instead of \clean{Int}: We can specify the correctness property of \module{Data.Set}'s \clean{member} function (\cref{sec:property}) more abstractly using \clean{a} instead of \clean{Int}:
......
...@@ -44,8 +44,10 @@ from syntax import ...@@ -44,8 +44,10 @@ from syntax import
:: Ident{id_name}, :: Ident{id_name},
:: Module{mod_defs,mod_ident}, :: Module{mod_defs,mod_ident},
:: Optional, :: Optional,
:: ParsedDefinition(PD_Function,PD_Type,PD_TypeSpec), :: ParsedDefinition(PD_Function,PD_Instance,PD_Instances,PD_Type,PD_TypeSpec),
:: ParsedExpr, :: ParsedExpr,
:: ParsedInstance{pi_ident},
:: ParsedInstanceAndMembers{pim_pi},
:: ParsedTypeDef, :: ParsedTypeDef,
:: Position, :: Position,
:: Priority, :: Priority,
...@@ -241,12 +243,21 @@ handleModule opts fp w ...@@ -241,12 +243,21 @@ handleModule opts fp w
opts.print_options opts.print_options
opts.test_options opts.test_options
moddoc moddoc
// Functions:
[(id.id_name,doc) \\ [(id.id_name,doc) \\
(pd,id) <- (pd,id) <-
[(pd,id) \\ pd=:(PD_Function pos id _ _ _ _) <- dcldefs] ++ [(pd,id) \\ pd=:(PD_Function pos id _ _ _ _) <- dcldefs] ++
[(pd,id) \\ pd=:(PD_TypeSpec pos id _ _ _) <- dcldefs], [(pd,id) \\ pd=:(PD_TypeSpec pos id _ _ _) <- dcldefs],
Just docstring <- [getComment pd documentation], Just docstring <- [getComment pd documentation],
doc <- parseDocWithWarnings docstring] doc <- parseDocWithWarnings docstring]
// Instances:
[(id.id_name,doc) \\
(pd,id) <-
[(pd,id) \\ pd=:(PD_Instance {pim_pi=pim_pi=:{pi_ident=id}}) <- dcldefs] ++
[(pd,id) \\ pd=:(PD_Instances piams) <- dcldefs, {pim_pi=pim_pi=:{pi_ident=id}} <- piams],
Just docstring <- [getComment pd documentation],
doc <- parseDocWithWarnings docstring]
// Type definitions:
[(id.id_name,doc) \\ [(id.id_name,doc) \\
pd=:(PD_Type {td_ident=id}) <- dcldefs, pd=:(PD_Type {td_ident=id}) <- dcldefs,
Just docstring <- [getComment pd documentation], Just docstring <- [getComment pd documentation],
...@@ -300,13 +311,15 @@ where ...@@ -300,13 +311,15 @@ where
Right (r,ws) -> traceParseWarnings ws [r] Right (r,ws) -> traceParseWarnings ws [r]
generatePropertyModule :: !String !String ![String] ![String] !(Maybe ModuleDoc) generatePropertyModule :: !String !String ![String] ![String] !(Maybe ModuleDoc)
![(!String, !FunctionDoc)] ![(!String, !TypeDoc)] ![(String, FunctionDoc)]
![(String, InstanceDoc)]
![(String, TypeDoc)]
-> (!Int, !Real, !String) -> (!Int, !Real, !String)
generatePropertyModule testmodname modname print_options test_options mod_doc fes tes generatePropertyModule testmodname modname print_options test_options mod_doc fes ies tes
= (n_props, coverage, tests) = (n_props, coverage, tests)
where where
n_props = length props n_props = length props
coverage = toReal (length (filter (not o isEmpty) propsets)) / toReal (length fes) coverage = toReal (length (filter (not o isEmpty) propsets)) / toReal (length fes + length ies)
tests = join "\n\n" tests = join "\n\n"
[ "module " +++ testmodname [ "module " +++ testmodname
, join "\n" , join "\n"
...@@ -323,8 +336,11 @@ where ...@@ -323,8 +336,11 @@ where
: [gp.gp_implementation \\ gp <- props] : [gp.gp_implementation \\ gp <- props]
] ]
propsets = map (uncurry $ generateProperties modname pvis generators) fes propsets = handle fes ++ handle ies
where pvis = fromMaybe [] $ docPropertyTestWith <$> mod_doc where
handle :: ([(String,doc)] -> [[GeneratedProperty]]) | docPreconditions, docProperties, docPropertyTestWith doc
handle = map (uncurry $ generateProperties modname pvis generators)
pvis = fromMaybe [] $ docPropertyTestWith <$> mod_doc
props = flatten propsets props = flatten propsets
bootstrap = fromMaybe "" (docPropertyBootstrap =<< mod_doc) bootstrap = fromMaybe "" (docPropertyBootstrap =<< mod_doc)
...@@ -378,10 +394,11 @@ where ...@@ -378,10 +394,11 @@ where
, ga_ptg :: !Maybe NamedTestGenerator // the generator used , ga_ptg :: !Maybe NamedTestGenerator // the generator used
} }
generateProperties :: !String ![PropertyVarInstantiation] ![NamedTestGenerator] !String !FunctionDoc -> [GeneratedProperty] generateProperties :: !String ![PropertyVarInstantiation] ![NamedTestGenerator] !String
!doc -> [GeneratedProperty] | docPreconditions, docProperties, docPropertyTestWith doc
generateProperties modname pvis generators fname doc = generateProperties modname pvis generators fname doc =
[gen i fname doc.preconditions p config [gen i fname (docPreconditions doc) p config
\\ p <- doc.properties \\ p <- docProperties doc
, config <- configurationsForProperty p (pvis ++ docPropertyTestWith doc) , config <- configurationsForProperty p (pvis ++ docPropertyTestWith doc)
& i <- [1..]] & i <- [1..]]
where where
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment