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

``dds`` supports either one or two source roots in a library. ``dds`` supports either one or two source roots in a library.




.. _pkgs.lib-roots:

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



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

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

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

the files on the filesystem with the appropriate file paths. The name of the the files on the filesystem with the appropriate file paths. The name of the
executable, ``hello-world``, was inferred by stripping the trailing ``.main`` executable, ``hello-world``, was inferred by stripping the trailing ``.main``
from the stem of the filename which defined the entry point. 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

:maxdepth: 2 :maxdepth: 2


hello-world hello-world

hello-lib
hello-test

Loading…
Cancel
Save