Test Coverage

This assumes you have a single user development environment where you can already build and install Cyrus, and run the CUnit and Cassandane tests. It also assumes your Cyrus install and Cassandane setup do not use "destdir", and that your compiler is GCC.

We'll be tinkering with group membership and file permissions, so proceed with caution on multi-user systems.

When a coverage-enabled binary runs, it writes coverage data into foo.gcda files alongside the source files. CUnit runs as you, but Cassandane runs as cyrus, so we need to arrange for both these users to be able to write to the source directory. We'll do that using group memberships and the group-writeable file mode bit.

One-time setup

Group membership

  1. Add the "cyrus" user account to your own user group

  2. Perhaps: also add your user account to the "cyrus" user's group. This might be "cyrus" or "mail" depending on how you set your system up. I can't remember if this is actually necessary for coverage, or if I have it for something else, so skip it unless it becomes necessary (and update this doc!)

File permissions

  1. Change into your cyrus-imapd directory: cd ~/path/to/cyrus-imapd

  2. Start from a clean state: git clean -xfd

  3. Set the group-writeable bit on everything: chmod -R g+w .

  4. Allow the group-writeable bit on new files you create: umask 0002

  5. Add that umask 0002 line to your .bashrc or equivalent too, otherwise you'll have to remember to fix up file permissions every time you want to make a coverage report


You'll need the lcov and genhtml tools for producing human-readable reports. On Debian, these are both found in the lcov package.

Preparing a coverage report

Compile Cyrus and run CUnit tests

The collection of coverage data slows things down, and it might also log a lot of complaints about overwriting old coverage data, or being unable to. So I do not recommend routinely compiling with coverage enabled -- only do this when you're preparing a coverage report.

  1. Change into your cyrus-imapd directory: cd ~/path/to/cyrus-imapd

  2. Start from a clean state: git clean -xfd

  3. Configure Cyrus, using your usual configure options, plus --enable-coverage

  4. Compile Cyrus: make -j4

  5. Run the CUnit tests: make -j4 check

  6. Install Cyrus (might need sudo): make install

Run Cassandane

  1. Run Cassandane on the installed Cyrus as you usually would

Generate report

I'd suggest making a script to automate this part. I use one like this

  1. Change into your cyrus-imapd directory: cd ~/path/to/cyrus-imapd

  2. Some of the foo.gcda files will be owned by your user (from the CUnit run), some will be owned by the cyrus user (from the Cassandane run). You can use something like this to reclaim the ownership (if your user:group is ellie:ellie):

    find . -name \*.gcda -not -user ellie -execdir sudo chown ellie:ellie "{}" +
  3. If you want to keep accumulating results, you'll need to ensure the Cyrus user can still write to those files. I don't know if this is useful, but something like this will do it: find . -name \*.gcda -execdir chmod g+rw "{}" +

  4. Process all those foo.gcda files into an intermediate form: lcov --directory . -c -o coverage.info

  5. Strip out unit test and external library clutter: lcov --remove coverage.info "cunit/*" "/usr/*" -o coverage.info

  6. Generate HTML: genhtml -o coverage coverage.info

  7. You can now open that report in your browser. Something like this will give you a link to copy and paste: echo file://$PWD/coverage/index.html