nocrap /

Filename Size Date modified Message
174 B
1.4 KB
694 B
5.6 KB
93 B
167 B
29.7 KB

No Crap

Tools to help eliminate crap code.

At this time, nocrap only operates on C code using "pmccabe" by Paul Bame to measure the complexity.


nocrap init            # initialize database in current directory
./runtests             # run coverage enabled gcc executables
nocrap capture         # consume gcov output and collect into db
nocrap compute         # calculate overall metrics
nocrap summary         # display summary report
nocrap file myfile.c   # show coverage for files matching myfile.c


CRAP is an acronym for Change Risk Anti-Patterns. It is an objective measure of quality of a piece of code based on its complexity and the quality of the automated tests that exercise it. The more complex a piece of code, the higher its CRAP rating. You can reduce the CRAP rating of code by improving unit test coverage.

A CRAP score higher than 30 indicates that a given function is high risk, either due to its high complexity or poor test coverage, or the combination of the two. Such functions are called CRAPpy functions and have associated with them another metric known as the CRAPLOAD.

The CRAPLOAD is an abstract indicator of the amount of work that needs to be done to convert a function from a CRAPpy function and into a non-CRAPpy function. The overall project has a CRAPLOAD score that sums the CRAPLOAD score of all of its constituent functions.

Ideally, a project will have no CRAPpy functions and will thus have a CRAPLOAD score of 0.

CRAP originated here


The complexity value calculated by pmccabe is the apparent code complexity, rather than the true code complexity. In other words, it processes how the code looks rather than how it gets compiled down to branching instructions.

Tracking per-test data

nocrap maintains a database that holds the raw test data. This can be tracked either as one complete dataset (per the synopsis above) or per test file. This latter case allows you to determine which test files exercise a given source file and help reduce the time it takes to verify code changes during build-test-build-test iterative cycles by allowing the developer to run just those test cases that are related to the file(s) being changed.

The usage pattern for the per-test scenario is to initialize the database at the start of the test run to ensure that you are starting with a clean database:

nocrap init

Then for each test file:

nocrap zero                           # clean up any errant gcov data
./runtest mytestname                  # execute your test
nocrap --testname=mytestname capture  # collect data

And at the end of the test run, compute the totals:

nocrap compute

Using with C programs

In order to collect data from C-programs, the C-program and its component parts need to be built using GCC with code-coverage enabled. The following compiler flags should be passed to GCC while compiling:

-fprofile-arcs -ftest-coverage

And the following linker options need to be used for each executable or shared object file:


You need to make sure that your build process uses consistent compiler flags throughout. In particular, each C source file must compile down to a single object file; rather than compiling the same source into multiple objects and executable, it is best to build that object into a library file and then link the library to the executable.

nocrap uses the gcov binary to process the coverage data into a consumable form.

Getting data out of the tool

You can obtain an overall summary:

% nocrap summary
Line Coverage:     81% (9773 / 12040)
Branch Coverage:   65%
CRAP functions:     0% (3)
CRAPload:         1743
  31     14        605   modules/yaml/api.c:YAML_DECLARE
  31     14        686   src/lauxlib.c:luaL_loadfile
  31     14        452   src/ltablib.c:auxsort
  29     45          0   src/llex.c:llex
  29     15          0   modules/lpeg.c:optimizecaptures
  29     15          0   modules/yaml/api.c:YAML_DECLARE
  29     15          0   src/ldblib.c:db_errorfb
  29     15          0   src/lua.c:pmain
  29     13          0   src/lapi.c:index2adr
  28     15          0   modules/curl.c:lcurl_easy_setopt
  28     13          0   src/lgc.c:local_collection
  15     54          0   src/ldebug.c:symbexec
  15     38          0   src/llex.c:read_string
  15     22          0   src/lcode.c:constfolding
  15     22          0   src/lparser.c:getbinopr

And you can query information on a specific file:

% nocrap file --compact xml
file: modules/xml.c
  Line coverage:    94%
  Func coverage:   100%
  Branch coverage:  61%

  Line coverage:    56%   CRAP:         13   CRAPLOAD: 0
  Branch coverage:  50%   Complexity:    5

  68   {
  69     struct xml_buffer_ptr *clv = vstr;
  71 /   if (len + clv->len > clv->allocd) {
  72 /     int newsize = clv->allocd ? clv->allocd * 2 : 8192;
  73       char *newbuff;
  75 /     while (newsize < len + clv->len) {
  76 -       newsize *= 2;
  77       }
  79       newbuff = realloc(clv->buff, newsize);
  80 /     if (!newbuff) {
  81 -       return -1;
  82       }
  85       clv->buff = newbuff;
  86     }
  88 /   memcpy(clv->buff + clv->len, buffer, len);
  89     clv->len += len;
  90     return len;

Covered by the following test case(s):

  - indicates a line with no coverage
  / indicates a line with less than 100% branch coverage