|
1 |
Code style guide
|
|
2 |
================
|
|
3 |
|
|
4 |
Python
|
|
5 |
------
|
|
6 |
|
|
7 |
.. highlight:: python
|
|
8 |
|
|
9 |
These are a few guidelines for Ganeti code and documentation.
|
|
10 |
|
|
11 |
In simple terms: try to stay consistent with the existing code. `PEP 8`_ says:
|
|
12 |
|
|
13 |
.. _PEP 8: http://www.python.org/dev/peps/pep-0008/
|
|
14 |
|
|
15 |
A style guide is about consistency. Consistency with this style guide is
|
|
16 |
important. Consistency within a project is more important. Consistency
|
|
17 |
within one module or function is most important.
|
|
18 |
|
|
19 |
.. note::
|
|
20 |
|
|
21 |
You might also want to take a look at the `Google style guide`_, since we
|
|
22 |
have some things in common with it.
|
|
23 |
|
|
24 |
.. _Google style guide: http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
|
|
25 |
|
|
26 |
Indentation
|
|
27 |
~~~~~~~~~~~
|
|
28 |
In general, always indent using two (2) spaces and don't use tabs.
|
|
29 |
|
|
30 |
The two spaces should always be relative to the previous level of indentation,
|
|
31 |
even if this means that the final number of spaces is not a multiple of 2.
|
|
32 |
|
|
33 |
When going on a new line inside an open parenthesis, align with the content of
|
|
34 |
the parenthesis on the previous line.
|
|
35 |
|
|
36 |
Valid example::
|
|
37 |
|
|
38 |
v = (somevalue,
|
|
39 |
a_function([
|
|
40 |
list_elem, # 7 spaces, but 2 from the previous indentation level
|
|
41 |
another_elem,
|
|
42 |
]))
|
|
43 |
|
|
44 |
Formatting strings
|
|
45 |
~~~~~~~~~~~~~~~~~~
|
|
46 |
Always use double quotes (``""``), never single quotes (``''``), except for
|
|
47 |
existing code. Examples for formatting strings::
|
|
48 |
|
|
49 |
var = "value"
|
|
50 |
|
|
51 |
# Note: The space character is always on the second line
|
|
52 |
var = ("The quick brown fox jumps over the lazy dog. The quick brown fox"
|
|
53 |
" jumps over the lazy dog. The quick brown fox jumps over the lazy"
|
|
54 |
" dog.")
|
|
55 |
|
|
56 |
fn("The quick brown fox jumps over the lazy dog. The quick brown fox jumps"
|
|
57 |
" over the lazy dog.")
|
|
58 |
|
|
59 |
fn(constants.CONFIG_VERSION,
|
|
60 |
("The quick brown fox jumps over the lazy dog. The quick brown fox"
|
|
61 |
" jumps over the lazy dog. The quick brown fox jumps over the lazy"
|
|
62 |
" dog."))
|
|
63 |
|
|
64 |
Don't format strings like this::
|
|
65 |
|
|
66 |
# Don't use single quotes
|
|
67 |
var = 'value'
|
|
68 |
|
|
69 |
# Don't use backslash for line continuation
|
|
70 |
var = "The quick brown fox jumps over the lazy dog. The quick brown fox"\
|
|
71 |
" jumps over the lazy dog."
|
|
72 |
|
|
73 |
# Space character goes to the beginning of a new line
|
|
74 |
var = ("The quick brown fox jumps over the lazy dog. The quick brown fox "
|
|
75 |
"jumps over the lazy dog. The quick brown fox jumps over the lazy "
|
|
76 |
"dog.")
|
|
77 |
|
|
78 |
Formatting sequences
|
|
79 |
~~~~~~~~~~~~~~~~~~~~
|
|
80 |
Built-in sequence types are list (``[]``), tuple (``()``) and dict (``{}``).
|
|
81 |
When splitting to multiple lines, each item should be on its own line and a
|
|
82 |
comma must be added on the last line. Don't write multiline dictionaries in
|
|
83 |
function calls, except when it's the only parameter. Always indent items by
|
|
84 |
two spaces.
|
|
85 |
|
|
86 |
::
|
|
87 |
|
|
88 |
# Short lists
|
|
89 |
var = ["foo", "bar"]
|
|
90 |
var = ("foo", "bar")
|
|
91 |
|
|
92 |
# Longer sequences and dictionary
|
|
93 |
var = [
|
|
94 |
constants.XYZ_FILENAME_EXTENSION,
|
|
95 |
constants.FOO_BAR_BAZ,
|
|
96 |
]
|
|
97 |
var = {
|
|
98 |
"key": func(),
|
|
99 |
"otherkey": None,
|
|
100 |
}
|
|
101 |
|
|
102 |
# Multiline tuples as dictionary values
|
|
103 |
var = {
|
|
104 |
"key":
|
|
105 |
("long value taking the whole line, requiring you to go to a new one",
|
|
106 |
other_value),
|
|
107 |
}
|
|
108 |
|
|
109 |
# Function calls
|
|
110 |
var = frozenset([1, 2, 3])
|
|
111 |
var = F({
|
|
112 |
"xyz": constants.XYZ,
|
|
113 |
"abc": constants.ABC,
|
|
114 |
})
|
|
115 |
|
|
116 |
# Wrong
|
|
117 |
F(123, "Hello World",
|
|
118 |
{ "xyz": constants.XYZ })
|
|
119 |
|
|
120 |
We consider tuples as data structures, not containers. So in general please
|
|
121 |
use lists when dealing with a sequence of homogeneous items, and tuples when
|
|
122 |
dealing with heterogeneous items.
|
|
123 |
|
|
124 |
Passing arguments
|
|
125 |
~~~~~~~~~~~~~~~~~
|
|
126 |
Positional arguments must be passed as positional arguments, keyword arguments
|
|
127 |
must be passed as keyword arguments. Everything else will be difficult to
|
|
128 |
maintain.
|
|
129 |
|
|
130 |
::
|
|
131 |
|
|
132 |
# Function signature
|
|
133 |
def F(data, key, salt=None, key_selector=None):
|
|
134 |
pass
|
|
135 |
|
|
136 |
# Yes
|
|
137 |
F("The quick brown fox", "123456")
|
|
138 |
F("The quick brown fox", "123456", salt="abc")
|
|
139 |
F("The quick brown fox", "123456", key_selector="xyz")
|
|
140 |
F("The quick brown fox", "123456", salt="foo", key_selector="xyz")
|
|
141 |
|
|
142 |
# No: Passing keyword arguments as positional argument
|
|
143 |
F("The quick brown fox", "123456", "xyz", "bar")
|
|
144 |
|
|
145 |
# No: Passing positional arguments as keyword argument
|
|
146 |
F(salt="xyz", data="The quick brown fox", key="123456", key_selector="xyz")
|
|
147 |
|
|
148 |
Docstrings
|
|
149 |
~~~~~~~~~~
|
|
150 |
|
|
151 |
.. note::
|
|
152 |
|
|
153 |
`PEP 257`_ is the canonical document, unless epydoc overrules it (e.g. in how
|
|
154 |
to document the type of an argument).
|
|
155 |
|
|
156 |
For docstrings, the recommended format is epytext_, to be processed via
|
|
157 |
epydoc_. There is an ``apidoc`` target that builds the documentation and puts it
|
|
158 |
into the doc/api subdir. Note that we currently use epydoc version 3.0.
|
|
159 |
|
|
160 |
.. _PEP 257: http://www.python.org/dev/peps/pep-0257/
|
|
161 |
.. _epytext: http://epydoc.sourceforge.net/manual-epytext.html
|
|
162 |
.. _epydoc: http://epydoc.sourceforge.net/
|
|
163 |
|
|
164 |
Note that one-line docstrings are only accepted in the unittests.
|
|
165 |
|
|
166 |
Rules for writing the docstrings (mostly standard Python rules):
|
|
167 |
|
|
168 |
* the docstring should start with a sentence, with punctuation at the end,
|
|
169 |
summarizing the the aim of what is being described. This sentence cannot be
|
|
170 |
longer than one line
|
|
171 |
* the second line should be blank
|
|
172 |
* afterwards the rest of the docstring
|
|
173 |
* special epytext tags should come at the end
|
|
174 |
* multi-line docstrings must finish with an empty line
|
|
175 |
* do not try to make a table using lots of whitespace
|
|
176 |
* use ``L{}`` and ``C{}`` where appropriate
|
|
177 |
|
|
178 |
Here's an example::
|
|
179 |
|
|
180 |
def fn(foo, bar):
|
|
181 |
"""Compute the sum of foo and bar.
|
|
182 |
|
|
183 |
This functions builds the sum of foo and bar. It's a simple function.
|
|
184 |
|
|
185 |
@type foo: int
|
|
186 |
@param foo: First parameter.
|
|
187 |
@type bar: float
|
|
188 |
@param bar: The second parameter. This line is longer
|
|
189 |
to show wrapping.
|
|
190 |
@rtype: float
|
|
191 |
@return: the sum of the two numbers
|
|
192 |
|
|
193 |
"""
|
|
194 |
return foo + bar
|
|
195 |
|
|
196 |
Some rules of thumb which should be applied with good judgement on a case-to-
|
|
197 |
case basis:
|
|
198 |
|
|
199 |
* If the meaning of parameters is already obvious given its name and the
|
|
200 |
methods description, don't document it again. Just add a ``@type`` tag.
|
|
201 |
* Refer to the base methods documentation when overwriting methods. Only
|
|
202 |
document more if it applies to the current subclass only, or if you want to
|
|
203 |
clarify on the meaning of parameters for the special subclass.
|
|
204 |
|
|
205 |
Rules for classes and modules
|
|
206 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
207 |
As `PEP 257`_ says, the docstrings of classes should document their attributes
|
|
208 |
and the docstrings of modules should shortly document the exported
|
|
209 |
functions/variables/etc.
|
|
210 |
|
|
211 |
See for example the pydoc output for the ``os`` or ``ConfigParser`` standard
|
|
212 |
modules.
|
|
213 |
|
|
214 |
Haskell
|
|
215 |
-------
|
|
216 |
|
|
217 |
.. highlight:: haskell
|
|
218 |
|
|
219 |
The most important consideration is, as usual, to stay consistent with the
|
|
220 |
existing code.
|
|
221 |
|
|
222 |
As there's no "canonical" style guide for Haskell, this code style has been
|
|
223 |
inspired from a few online resources, including the style guide for the
|
|
224 |
`Snap framework`_, `this style guide`_ and `this other style guide`_.
|
|
225 |
|
|
226 |
.. _Snap framework: http://snapframework.com/docs/style-guide
|
|
227 |
.. _this style guide: https://github.com/tibbe/haskell-style-guide/blob/master/haskell-style.md
|
|
228 |
.. _this other style guide: http://www.cs.caltech.edu/courses/cs11/material/haskell/misc/haskell_style_guide.html
|
|
229 |
|
|
230 |
Files
|
|
231 |
~~~~~
|
|
232 |
Use ordinary, non-`literate`_ Haskell ``.hs`` files.
|
|
233 |
|
|
234 |
.. _literate: http://www.haskell.org/haskellwiki/Literate_programming
|
|
235 |
|
|
236 |
Use proper copyright headers, and proper Haddock style documentation headers::
|
|
237 |
|
|
238 |
{-| Short module summary.
|
|
239 |
|
|
240 |
Longer module description.
|
|
241 |
|
|
242 |
-}
|
|
243 |
|
|
244 |
{-
|
|
245 |
|
|
246 |
Copyright (C) ...
|
|
247 |
|
|
248 |
This program is free software ...
|
|
249 |
|
|
250 |
-}
|
|
251 |
|
|
252 |
If there are module-level pragmas add them right at the top, before the short
|
|
253 |
summary.
|
|
254 |
|
|
255 |
Imports
|
|
256 |
~~~~~~~
|
|
257 |
Imports should be grouped into the following groups and inside each group they
|
|
258 |
should be sorted alphabetically:
|
|
259 |
|
|
260 |
1. standard library imports
|
|
261 |
2. third-party imports
|
|
262 |
3. local imports
|
|
263 |
|
|
264 |
It is allowed to use qualified imports with short names for:
|
|
265 |
|
|
266 |
* standard library (e.g. ``import qualified Data.Map as M``)
|
|
267 |
* local imports (e.g. ``import qualified Ganeti.Constants as C``), although
|
|
268 |
this form should be kept to a minimum
|
|
269 |
|
|
270 |
Indentation
|
|
271 |
~~~~~~~~~~~
|
|
272 |
Use only spaces, never tabs. Indentation level is 2 characters. For Emacs,
|
|
273 |
this means setting the variable ``haskell-indent-offset`` to 2.
|
|
274 |
|
|
275 |
Line length should be at most 78 chars, and 72 chars inside comments.
|
|
276 |
|
|
277 |
Use indentation-based structure, and not braces/semicolons.
|
|
278 |
|
|
279 |
.. note::
|
|
280 |
|
|
281 |
Special indendation of if/then/else construct
|
|
282 |
|
|
283 |
For the ``do`` notation, the ``if-then-else`` construct has a non-intuitive
|
|
284 |
behaviour. As such, the indentation of ``if-then-else`` (both in ``do``
|
|
285 |
blocks and in normal blocks) should be as follows::
|
|
286 |
|
|
287 |
if condition
|
|
288 |
then expr1
|
|
289 |
else expr2
|
|
290 |
|
|
291 |
i.e. indent the then/else lines with another level. This can be accomplished
|
|
292 |
in Emacs by setting the variable ``haskell-indent-thenelse`` to 2 (from the
|
|
293 |
default of zero).
|
|
294 |
|
|
295 |
If you have more than one line of code please newline/indent after the "=". Do
|
|
296 |
`not` do::
|
|
297 |
|
|
298 |
f x = let y = x + 1
|
|
299 |
in y
|
|
300 |
|
|
301 |
Instead do::
|
|
302 |
|
|
303 |
f x =
|
|
304 |
let y = x + 1
|
|
305 |
in y
|
|
306 |
|
|
307 |
or if it is just one line::
|
|
308 |
|
|
309 |
f x = x + 1
|
|
310 |
|
|
311 |
Multiline strings
|
|
312 |
~~~~~~~~~~~~~~~~~
|
|
313 |
Multiline strings are created by closing a line with a backslash and starting
|
|
314 |
the following line with a backslash, keeping the indentation level constant.
|
|
315 |
Whitespaces go on the new line, right after the backslash.
|
|
316 |
|
|
317 |
::
|
|
318 |
|
|
319 |
longString :: String
|
|
320 |
longString = "This is a very very very long string that\
|
|
321 |
\ needs to be split in two lines"
|
|
322 |
|
|
323 |
Data declarations
|
|
324 |
~~~~~~~~~~~~~~~~~
|
|
325 |
.. warning::
|
|
326 |
Note that this is different from the Python style!
|
|
327 |
|
|
328 |
When declaring either data types, or using list literals, etc., the columns
|
|
329 |
should be aligned, and for lists use a comma at the start of the line, not at
|
|
330 |
the end. Examples::
|
|
331 |
|
|
332 |
data OpCode = OpStartupInstance ...
|
|
333 |
| OpShutdownInstance ...
|
|
334 |
| ...
|
|
335 |
|
|
336 |
data Node = Node { name :: String
|
|
337 |
, ip :: String
|
|
338 |
, ...
|
|
339 |
}
|
|
340 |
|
|
341 |
myList = [ value1
|
|
342 |
, value2
|
|
343 |
, value3
|
|
344 |
]
|
|
345 |
|
|
346 |
The choice of whether to wrap the first element or not is up to you; the
|
|
347 |
following is also allowed::
|
|
348 |
|
|
349 |
myList =
|
|
350 |
[ value1
|
|
351 |
, value2
|
|
352 |
]
|
|
353 |
|
|
354 |
White space
|
|
355 |
~~~~~~~~~~~
|
|
356 |
Like in Python, surround binary operators with one space on either side. Do no
|
|
357 |
insert a space after a lamda::
|
|
358 |
|
|
359 |
-- bad
|
|
360 |
map (\ n -> ...) lst
|
|
361 |
-- good
|
|
362 |
foldl (\x y -> ...) ...
|
|
363 |
|
|
364 |
Use a blank line between top-level definitions, but no blank lines between
|
|
365 |
either the comment and the type signature or between the type signature and
|
|
366 |
the actual function definition.
|
|
367 |
|
|
368 |
.. note::
|
|
369 |
Ideally it would be two blank lines between top-level definitions, but the
|
|
370 |
code only has one now.
|
|
371 |
|
|
372 |
As always, no trailing spaces. Ever.
|
|
373 |
|
|
374 |
Spaces after comma
|
|
375 |
******************
|
|
376 |
|
|
377 |
Instead of::
|
|
378 |
|
|
379 |
("a","b")
|
|
380 |
|
|
381 |
write::
|
|
382 |
|
|
383 |
("a", "b")
|
|
384 |
|
|
385 |
Naming
|
|
386 |
~~~~~~
|
|
387 |
Functions should be named in mixedCase style, and types in CamelCase. Function
|
|
388 |
arguments and local variables should be mixedCase.
|
|
389 |
|
|
390 |
When using acronyms, ones longer than 2 characters should be typed capitalised,
|
|
391 |
not fully upper-cased (e.g. ``Http``, not ``HTTP``).
|
|
392 |
|
|
393 |
For variable names, use descriptive names; it is only allowed to use very
|
|
394 |
short names (e.g. ``a``, ``b``, ``i``, ``j``, etc.) when:
|
|
395 |
|
|
396 |
* the function is trivial, e.g.::
|
|
397 |
|
|
398 |
sum x y = x + y
|
|
399 |
|
|
400 |
* we talk about some very specific cases, e.g.
|
|
401 |
iterators or accumulators in folds::
|
|
402 |
|
|
403 |
map (\v -> v + 1) lst
|
|
404 |
|
|
405 |
* using ``x:xs`` for list elements and lists, etc.
|
|
406 |
|
|
407 |
In general, short/one-letter names are allowed when we deal with polymorphic
|
|
408 |
values; for example the standard map definition from Prelude::
|
|
409 |
|
|
410 |
map :: (a -> b) -> [a] -> [b]
|
|
411 |
map _ [] = []
|
|
412 |
map f (x:xs) = f x : map f xs
|
|
413 |
|
|
414 |
In this example, neither the ``a`` nor ``b`` types are known to the map
|
|
415 |
function, so we cannot give them more explicit names. Since the body of the
|
|
416 |
function is trivial, the variables used are longer.
|
|
417 |
|
|
418 |
However, if we deal with explicit types or values, their names should be
|
|
419 |
descriptive.
|
|
420 |
|
|
421 |
.. todo: add a nice example here.
|
|
422 |
|
|
423 |
Finally, the naming should look familiar to people who just read the
|
|
424 |
Prelude/standard libraries.
|
|
425 |
|
|
426 |
Naming for updated values
|
|
427 |
*************************
|
|
428 |
|
|
429 |
.. highlight:: python
|
|
430 |
|
|
431 |
Since one cannot update a value in Haskell, this presents a particular problem
|
|
432 |
on the naming of new versions of the same value. For example, the following
|
|
433 |
code in Python::
|
|
434 |
|
|
435 |
def failover(pri, sec, inst):
|
|
436 |
pri.removePrimary(inst)
|
|
437 |
pri.addSecondary(inst)
|
|
438 |
sec.removeSecondary(inst)
|
|
439 |
sec.addPrimary(inst)
|
|
440 |
|
|
441 |
.. highlight:: haskell
|
|
442 |
|
|
443 |
becomes in Haskell something like the following::
|
|
444 |
|
|
445 |
failover pri sec inst =
|
|
446 |
let pri' = removePrimary pri inst
|
|
447 |
pri'' = addSecondary pri' inst
|
|
448 |
sec' = removeSecondary sec inst
|
|
449 |
sec'' = addPrimary sec' inst
|
|
450 |
in (pri'', sec'')
|
|
451 |
|
|
452 |
When updating values, one should add single quotes to the name for up to three
|
|
453 |
new names (e.g. ``inst``, ``inst'``, ``inst''``, ``inst'''``) and otherwise
|
|
454 |
use numeric suffixes (``inst1``, ``inst2``, ``inst3``, ..., ``inst8``), but
|
|
455 |
that many updates is already bad style and thus should be avoided.
|
|
456 |
|
|
457 |
Type signatures
|
|
458 |
~~~~~~~~~~~~~~~
|
|
459 |
|
|
460 |
Always declare types for functions (and any other top-level bindings).
|
|
461 |
|
|
462 |
If in doubt, feel free to declare the type of the variables/bindings in a
|
|
463 |
complex expression; this usually means the expression is too complex, however.
|
|
464 |
|
|
465 |
Similarly, provide Haddock-style comments for top-level definitions.
|
|
466 |
|
|
467 |
Parentheses, point free style
|
|
468 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
469 |
|
|
470 |
Prefer the so-called point-free style to extra parentheses::
|
|
471 |
|
|
472 |
-- bad
|
|
473 |
let a = f ( g ( h x) )
|
|
474 |
-- better
|
|
475 |
let b = f $ g $ h x
|
|
476 |
-- best
|
|
477 |
let c = f . g . h $ x
|
|
478 |
|
|
479 |
Language features
|
|
480 |
~~~~~~~~~~~~~~~~~
|
|
481 |
|
|
482 |
Extensions
|
|
483 |
**********
|
|
484 |
|
|
485 |
It is recommended to keep the use of extensions to a minimum, so that the code
|
|
486 |
can be understood even if one is familiar with just Haskel98/Haskell2010. That
|
|
487 |
said, some extensions are very common and useful, so they are recommended:
|
|
488 |
|
|
489 |
* `Bang patterns`_: useful when you want to enforce strict evaluation (and better
|
|
490 |
than repeated use of ``seq``)
|
|
491 |
* CPP: a few modules need this in order to account for configure-time options;
|
|
492 |
don't overuse it, since it breaks multi-line strings
|
|
493 |
* `Template Haskell`_: we use this for automatically deriving JSON instances and
|
|
494 |
other similar boiler-plate
|
|
495 |
|
|
496 |
.. _Bang patterns: http://www.haskell.org/ghc/docs/latest/html/users_guide/bang-patterns.html
|
|
497 |
.. _Template Haskell: http://www.haskell.org/ghc/docs/latest/html/users_guide/template-haskell.html
|
|
498 |
|
|
499 |
Such extensions should be declared using the ``Language`` pragma::
|
|
500 |
|
|
501 |
{-# Language BangPatterns #-}
|
|
502 |
|
|
503 |
{-| This is a small module... -}
|
|
504 |
|
|
505 |
Comments
|
|
506 |
********
|
|
507 |
|
|
508 |
Always use proper sentences; start with a capital letter and use punctuation
|
|
509 |
in top level comments::
|
|
510 |
|
|
511 |
-- | A function that does something.
|
|
512 |
f :: ...
|
|
513 |
|
|
514 |
For inline comments, start with a capital letter but no ending punctuation.
|
|
515 |
Furthermore, align the comments together with a 2-space width from the end of
|
|
516 |
the item being commented::
|
|
517 |
|
|
518 |
data Maybe a = Nothing -- ^ Represents empty container
|
|
519 |
| Just a -- ^ Represents a single value
|
|
520 |
|
|
521 |
The comments should be clear enough so that one doesn't need to look at the
|
|
522 |
code to understand what the item does/is.
|
|
523 |
|
|
524 |
Use ``-- |`` to write doc strings rather than bare comment with ``--``.
|
|
525 |
|
|
526 |
Tools
|
|
527 |
*****
|
|
528 |
|
|
529 |
We generate the API documentation via Haddock, and as such the comments should
|
|
530 |
be correct (syntax-wise) for it. Use markup, but sparingly.
|
|
531 |
|
|
532 |
We use hlint_ as a lint checker; the code is currently lint-clean, so you must
|
|
533 |
not add any warnings/errors.
|
|
534 |
|
|
535 |
.. _hlint: http://community.haskell.org/~ndm/darcs/hlint/hlint.htm
|
|
536 |
|
|
537 |
Use these two commands during development::
|
|
538 |
|
|
539 |
make hs-apidoc
|
|
540 |
make hlint
|
|
541 |
|
|
542 |
QuickCheck best practices
|
|
543 |
*************************
|
|
544 |
|
|
545 |
If you have big type that takes time to generate and several properties to
|
|
546 |
test on that, by default 500 of those big instances are generated for each
|
|
547 |
property. In many cases, it would be sufficient to only generate those 500
|
|
548 |
instances once and test all properties on those. To do this, create a property
|
|
549 |
that uses ``conjoin`` to combine several properties into one. Use
|
|
550 |
``printTestCase`` to add expressive error messages. For example::
|
|
551 |
|
|
552 |
prop_myMegaProp :: myBigType -> Property
|
|
553 |
prop_myMegaProp b =
|
|
554 |
conjoin
|
|
555 |
[ printTestCase
|
|
556 |
("Something failed horribly here: " ++ show b) (subProperty1 b)
|
|
557 |
, printTestCase
|
|
558 |
("Something else failed horribly here: " ++ show b)
|
|
559 |
(subProperty2 b)
|
|
560 |
, -- more properties here ...
|
|
561 |
]
|
|
562 |
|
|
563 |
subProperty1 :: myBigType -> Bool
|
|
564 |
subProperty1 b = ...
|
|
565 |
|
|
566 |
subProperty2 :: myBigType -> Property
|
|
567 |
subProperty2 b = ...
|
|
568 |
|
|
569 |
...
|
|
570 |
|
|
571 |
Maybe Generation
|
|
572 |
''''''''''''''''
|
|
573 |
|
|
574 |
Use ``genMaybe genSomething`` to create ``Maybe`` instances of something
|
|
575 |
including some ``Nothing`` instances.
|
|
576 |
|
|
577 |
Use ``Just <$> genSomething`` to generate only ``Just`` instances of
|
|
578 |
something.
|
|
579 |
|
|
580 |
String Generation
|
|
581 |
'''''''''''''''''
|
|
582 |
|
|
583 |
To generate strings, consider using ``genName`` instead of ``arbitrary``.
|
|
584 |
``arbitrary`` has the tendency to generate strings that are too long.
|