Thread overview
Re: Needed enhancement for documentable unittest
Mar 25, 2013
Jens Mueller
Mar 30, 2013
Andrej Mitrovic
Mar 30, 2013
Timothee Cour
March 25, 2013
Andrej Mitrovic wrote:
> On 2/7/13, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> > I'm very happy that this will be part of the upcoming release: https://github.com/D-Programming-Language/dmd/pull/1342 (see also http://d.puremagic.com/issues/show_bug.cgi?id=2630) allows defining unittests that simultaneously work as documentation. This is a great way to simultaneously write meaningful tests and good documentation examples.
> >
> > If you want to help, feel free to hop on the Phobos documentation and convert some of it to use the new feature.
> 
> Kenji and I have been working on getting this feature working properly, and it should be pretty solid by now in DMD-head.
> 
> But one case where it might not be a good idea to move the embedded code into unittests is when you have a big comment section, for example the one for std.algorithm.map. I think this should be a new enhancement request. Here's part of the documentation for map:

I thought the example (embedded code) is not being moved into unittests
rather it's copied. The example will still be shown in the
documentation.
Why is it a problem with e.g. std.algorithm.map (one big comment)?

Thanks for pushing this feature. It's a very useful one.

Jens
March 30, 2013
On 3/25/13, Jens Mueller <jens.k.mueller@gmx.de> wrote:
> I thought the example (embedded code) is not being moved into unittests
> rather it's copied.

No, that's not how it works. Code in in documented unittests is moved into Example sections in ddoc output. So the new definition of map would look like:

<quote>
/**
$(D auto map2(Range)(Range r) if (isInputRange!(Unqual!Range));)

Implements the homonym function (also known as $(D transform)) present
in many languages of functional flavor. The call $(D map!(fun)(range))
returns a range of which elements are obtained by applying $(D fun(x))
left to right for all $(D x) in $(D range). The original ranges are
not changed. Evaluation is done lazily.
*/
template map2(fun...) if (fun.length >= 1)
{
    auto map2(Range)(Range r)
    {

    }
}

///
unittest
{
    int[] arr1 = [ 1, 2, 3, 4 ];
    int[] arr2 = [ 5, 6 ];
    auto squares = map!(a => a * a)(chain(arr1, arr2));
    assert(equal(squares, [ 1, 4, 9, 16, 25, 36 ]));
}

/**
Multiple functions can be passed to $(D map). In that case, the
element type of $(D map) is a tuple containing one element for each
function.
*/
unittest
{
    auto arr1 = [ 1, 2, 3, 4 ];
    foreach (e; map!("a + a", "a * a")(arr1))
    {
        writeln(e[0], " ", e[1]);
    }
}

/**
You may alias $(D map) with some function(s) to a symbol and use
it separately:
*/
unittest
{
    alias map!(to!string) stringize;
    assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
}
</quote>

This will look similar to how it looks now in the documentation.

My problem is that the actual documentation text in the source file is now spread out into unittest comments rather than being at a single place (right next to the function header).

It may or may not be a problem, I'm on the fence about it.
March 30, 2013
Examples moved out to unittests:
Cons: doc gets spread out in unittests
Pros: much easier to write those examples, no quoting necessary, code
is syntax highlighted, compilable and ran by unittest suite.
Much better than the hack of embedding examples inside doc
For proof, see how many embedded examples are out of date. Or even compilable.


On Fri, Mar 29, 2013 at 11:46 PM, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:
> On 3/25/13, Jens Mueller <jens.k.mueller@gmx.de> wrote:
>> I thought the example (embedded code) is not being moved into unittests
>> rather it's copied.
>
> No, that's not how it works. Code in in documented unittests is moved into Example sections in ddoc output. So the new definition of map would look like:
>
> <quote>
> /**
> $(D auto map2(Range)(Range r) if (isInputRange!(Unqual!Range));)
>
> Implements the homonym function (also known as $(D transform)) present
> in many languages of functional flavor. The call $(D map!(fun)(range))
> returns a range of which elements are obtained by applying $(D fun(x))
> left to right for all $(D x) in $(D range). The original ranges are
> not changed. Evaluation is done lazily.
> */
> template map2(fun...) if (fun.length >= 1)
> {
>     auto map2(Range)(Range r)
>     {
>
>     }
> }
>
> ///
> unittest
> {
>     int[] arr1 = [ 1, 2, 3, 4 ];
>     int[] arr2 = [ 5, 6 ];
>     auto squares = map!(a => a * a)(chain(arr1, arr2));
>     assert(equal(squares, [ 1, 4, 9, 16, 25, 36 ]));
> }
>
> /**
> Multiple functions can be passed to $(D map). In that case, the
> element type of $(D map) is a tuple containing one element for each
> function.
> */
> unittest
> {
>     auto arr1 = [ 1, 2, 3, 4 ];
>     foreach (e; map!("a + a", "a * a")(arr1))
>     {
>         writeln(e[0], " ", e[1]);
>     }
> }
>
> /**
> You may alias $(D map) with some function(s) to a symbol and use
> it separately:
> */
> unittest
> {
>     alias map!(to!string) stringize;
>     assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
> }
> </quote>
>
> This will look similar to how it looks now in the documentation.
>
> My problem is that the actual documentation text in the source file is now spread out into unittest comments rather than being at a single place (right next to the function header).
>
> It may or may not be a problem, I'm on the fence about it.