Browse Source

More tutorials

default_compile_flags
vector-of-bool 5 years ago
parent
commit
acb1496595
5 changed files with 200 additions and 1 deletions
  1. +2
    -0
      docs/guide/packages.rst
  2. +39
    -0
      docs/tut/hello-lib.rst
  3. +127
    -0
      docs/tut/hello-test.rst
  4. +30
    -0
      docs/tut/hello-world.rst
  5. +2
    -1
      docs/tut/index.rst

+ 2
- 0
docs/guide/packages.rst View File

@@ -182,6 +182,8 @@ and it will only ever add source roots to the *include-search-path*.
``dds`` supports either one or two source roots in a library.


.. _pkgs.lib-roots:

Library Roots
*************


+ 39
- 0
docs/tut/hello-lib.rst View File

@@ -0,0 +1,39 @@
A *Hello, World* Library
########################

Creating a single application is fun, but what if we want to create code that
we can distribute and reuse across other packages and projects? That's what
*libraries* are for.

You may notice something strange: This page is much shorter than the previous.
What gives?

It turns out that we've already covered all the material to make a library in
the page on creating a :doc:`Hello, world! executable <hello-world>`. As soon
as we created the ``strings.hpp`` file, our project had become a library. When
we added a ``strings.cpp`` file to accompany it, our library became a *compiled*
library.

The ``hello-world.main.cpp`` file is expressly *not* considered to be part of a
library, as it is specifically designated to be an application entry point,
and source files of such kind are not part of a library.

Before continuing on, note the following about creating a library that wasn't
specifically addressed in the prior example:

#. The *source roots* of a library are added to the compiler's ``#include``
search-path. In our example, this is only the ``src/`` directory of the
project.
#. ``dds`` also supports a top-level directory named ``include/``. Both
``include/`` and ``src/`` may be present in a single library, but there are
some important differences. Refer to :ref:`pkgs.lib-roots` in the layout
guide.
#. A single *library root* may contain any number of applications defined in
``.main`` files, but a *library root* will correspond to exactly *one*
library. Defining additional libraries requires additional packages or
adding multiple library roots to a single package.

.. seealso::
Like flossing, we all know we *should* be writing tests, but it can be such
a hassle. Fortunately, ``dds`` makes it simple. Read on to:
:doc:`hello-test`.

+ 127
- 0
docs/tut/hello-test.rst View File

@@ -0,0 +1,127 @@
A *Hello, World* Test
#####################

So far, we have a simple library with a single function: ``get_greeting()``
and an application that makes use of it. How can we test it?

With ``dds``, similar to generating applications, creating a test requires
adding a suffix to a source filename stem. Instead of ``.main``, simply
add ``.test`` before the file extension.


A New Test Executable
*********************

We'll create a test for our ``strings`` component, in a file named
``strings.test.cpp``. We'll use an ``assert`` to check our ``get_greeting()``
function:

.. code-block:: c++
:caption: ``<root>/src/hello/strings.test.cpp``
:linenos:

#include <hello/strings.hpp>

int main() {
if (hello::get_greeting() != "Hello world!") {
return 1;
}
}

If you run ``dds build`` once again, ``dds`` will generate a test executable
and run it immediately. If the test executable exits with a non-zero exit code,
then it will consider the test to have failed, and ``dds`` itself will exit
with a non-zero exit code.

.. important::
``dds`` executes tests *in parallel* by default! If the tests need access
to a shared resource, locking must be implemented manually, or the shared
resource should be split.

.. note::
``dds`` builds and executes tests for *every build* **by default**. The
``*.test.cpp`` tests are meant to be very fast *unit* tests, so consider
their execution time carefully.

If your code matches the examples so far, the above test will *fail*. Keen eyes
will already know the problem, but wouldn't it be better if we had better test
diagnostics?


A ``Test-Driver``: Using *Catch2*
*********************************

``dds`` ships with built-in support for the `Catch2`_ C and C++ testing
framework, a popular

.. _catch2: https://github.com/catchorg/Catch2

To make use of Catch as our test driver, we simply declare this intent in the
``package.dds`` file at the package root:

.. code-block:: yaml
:caption: ``<root>/package.dds``
:emphasize-lines: 5

Name: hello-dds
Version: 0.1.0
Namespace: tutorial

Test-Driver: Catch-Main

If you now run ``dds build``, we will get a linker error for a multiply-defined
``main`` function. When setting the ``Test-Driver`` to ``Catch-Main``, ``dds``
will compile an entrypoint separately from any particular test, and the tests
will link against that entrypoint. This means we cannot provide our own
``main`` function, and should instead use Catch's ``TEST_CASE`` macro to
declare our test cases.

In addition to an entrypoint, ``dds`` provides a ``catch.hpp`` header that we
may use in our tests, simply by ``#include``-ing the appropriate path. We'll
modify our test to use the Catch test macros instead of our own logic. We'll
leave the condition the same, though:

.. code-block:: c++
:caption: ``<root>/src/hello/strings.test.cpp``
:linenos:
:emphasize-lines: 3, 5-7

#include <hello/strings.hpp>

#include <catch2/catch.hpp>

TEST_CASE("Check the greeting") {
CHECK(hello::get_greeting() == "Hello world!");
}

Now running ``dds build`` will print more output that Catch has generated as
part of test execution, and we can see the reason for the failing test::

[16:41:45] [error] Test <root>/_build/test/hello/strings failed! Output:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
strings is a Catch v2.10.2 host application.
Run with -? for options

-------------------------------------------------------------------------------
Check the greeting
-------------------------------------------------------------------------------
<root>/src/hello/strings.test.cpp:5
...............................................................................

<root>/src/hello/strings.test.cpp:5: FAILED:
CHECK( hello::get_greeting() == "Hello world!" )
with expansion:
"Hello, world!" == "Hello world!"

===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed

[dds - test output end]

Now that we have the direct results of the offending expression, we can
much more easily diagnose the nature of the test failure. In this case, the
function returns a string containing a comma ``,`` while our expectation lacks
one. If we fix either the ``get_greeting`` or the expected string, we will then
see our tests pass successfully and ``dds`` will exit cleanly.

+ 30
- 0
docs/tut/hello-world.rst View File

@@ -219,3 +219,33 @@ It turns out, we *did* tell ``dds`` all of this information by simply placing
the files on the filesystem with the appropriate file paths. The name of the
executable, ``hello-world``, was inferred by stripping the trailing ``.main``
from the stem of the filename which defined the entry point.


Cleaning Up
***********

There's one final formality that should be taken care of before proceeding:
Creating a package manifest file.

``dds`` will work happily with packages that do not declare themselves, as long
as the filesystem structure is sufficient. However: To use features covered in
later tutorials, we'll need a simple ``package.dds`` file to declare
information about are package. This file should be placed directly in the
package root:

.. code-block:: yaml
:caption: ``<root>/package.dds``

Name: hello-dds
Version: 0.1.0
Namespace: tutorial


.. note::
The ``Namespace`` option will be discussed later.

Rebuilding the project will show no difference at the moment.

.. seealso::
Creating a single application executable is fine and all, but what if we
want to create libraries? See the next page: :doc:`hello-lib`

+ 2
- 1
docs/tut/index.rst View File

@@ -15,4 +15,5 @@ place to begin!
:maxdepth: 2

hello-world

hello-lib
hello-test

Loading…
Cancel
Save