CppUnit project page CppUnit home page

Coding Guidelines


Naming convention

Definition: Capitalized First Letter convention (camel case)

This convention is used for most naming, and will be referred to as camel case convention. The name is in mixed case, with the first letter of each word in upper case, and the other in lower case. Acronym (example: DLL = Dynamically Linked Library) are in upper case. Unless stated otherwise, those identifiers should not contain any '_'.

This convention has two main variants: first letter of the name in lower case, and first letter of the name in upper case. If the first letter is part of an acronym, then the acronym is in the same case as the first letter.

Example:

First letter in upper caseFirst letter in lower case
TestCasetestCase
DLLLoaderdllLoader

File name

File name should be in lower case and File name should not contain any ‘_’. File names should be named after the feature they provide.

File extensions: .cpp for C++ source file .h/.inl for C++ headers.

Rational: avoid case issues for case sensitive filesystem, corrupting CVS repository when attempting to change file name case on buggy client.

Example :

testcase.c      // OK
testcase.h      // OK
testcase.inl    // OK
resource.c      // OK

test_case.c     // BAD
TestCase.c      // BAD
TestCase.h      // BAD
TestCase.C      // BAD

C++ identifiers

Rules: no identifier must contain two underscores '__' or starts with a single underscore '_'. Identifiers may only contains the following characters: a..z, A..Z, 0..9. The usage of '$' is forbidden.

Rationale: such usage of underscore is reserved by the C++ standard.

Notes:

Macro names

Rules: Macro name must be completely in upper case, with words separated by an underscore ‘_’. Macro name should also be prefixed with a library or application name. This prefix serves as namespace and help avoiding conflicts.

The following prefix should be used:
LibraryPrefix
CppUnit 2CPPUT_
CppTL (CppUnit Tool Library)CPPTL_
JsonCppJSON_
OpenTestOPENTEST_

Rationale: macro substitution occurs at preprocessing time without regards to namespace. Prefixing macro names help makes them unique and avoid clash between libraries. The naming conventions are such that no C++ identifier should have a name similar to a macro name. This conventions is widely adopted across all C++ naming conventions, meaning that it also help avoid conflicts with third-parties.

Class names

Rules: Class name must be in camel case, starting with an upper case letter.

Rationale: defined by java standard naming convention, and a widely spread C++ convention as well. Identifiers starting with an upper case are used to identify ‘Type’ identifiers (enum, class...)

Example:

Test
TestCase
ExceptionGuard

Class attributes

Rules: attribute names must be in camel case starting with a lower case letter and suffixed with an underscore '_'.

Rationale: defined by java standard naming convention, and a widely spread C++ convention as well. Identifiers starting with a lower case are used to identify ‘value’ identifiers (attribute, variable...)

Example:

int size_;
double timeOut_;
LightTestRunner runner_;

Member function names

Rules: member function names must be in camel case, starting with a lower case. The name should contains a verb and be structured in such a way that it can be read naturally.

Rationale: This is a widely spread convention in the Java and C++ community.

Recommendation: when overriding virtual function, specify in which inherited class the virtual function is defined:

Example:

void addChild( const std::string &parentSuiteName,
                const std::string &childSuiteName );

bool removeChild( const std::string &parentSuiteName,
                    const std::string &childSuiteName );

TestFactoryId add( const std::string &parentSuiteName,
                    const TestFactory &testFactory );

class OPENTEST_API TestRunnerServer : public RemoteMessageServer
                                    , private TestRunnerListener
{
public:
   TestRunnerServer( TestRunnerInterface &impl );

   void attachTransport( const MessageTransportPtr &transport );

public: // overridden from RemoteMessageServer
   void dispatchPendingMessages( const RemoteMessagePtr &message,
                                 MessageTransport &transport );

public: // overridden from TestRunnerListener
   virtual void testRunStarted( TestRunId testRunId );
   virtual void testRunDone( TestRunId testRunId );

   virtual void startTesting( TestPlanId testPlanId );
   virtual void doneTesting( TestPlanId testPlanId,
                             const ResultStatus &status );
private: //
   ...
};

Enumeration type

Rules: enumeration type name must be in camel case, starting with an upper case.

Rationale: avoid potential clash with macro.

Example:

enum ParameterRequirement
{
    noParameter,         
    optionalParameter,   
    requiredParameter,   
    oneOrMoreParameter,  
    zeroOrMoreParameter  
};

Local variables and function parameters

Rules: local variable and function parameters must be in camel case, starting with a lower case. Name should be ‘intention revealing name’, that is indicating what is the use of the variable/parameter rather than indicating what the variable/parameter is.

Rationale: avoid ambiguity in declaration between type and variable name.

Example:

bool 
parse( const std::string &document, 
       Value &root,
       bool collectComments = true );


Style Guide

The following style should be used when writing code:

General code layout:


Guidelines

Headers

Rules: All headers must either include the file config. of their library or include anything of the library (and therefore include the file config. indirectly).

Rules: All classes and typedef must be exported using the XYZ_API macro, where XYZ is the library macro prefix (see [Macro names]).

Rules: All classes must be forward declared in forwards.h header of the library.

Using namespace directive

Rules: Never use the using namespace directive in any headers.

Recommendation: Avoid the using namespace directive in any sources.

Rational: avoid poluting namespaces of sources including that header; enhance code readability by making obvious from which library a type/function originate from.

C++ language feature restrictions

No cast style function template

Rules: All function template template argument must be deduced from parameters. Use CppTL::Type to explicitly pass the type as a parameter if needed.

Rationale: some older compilers only includes function parameters type in the function signature used for link, resulting in very strange bug if cast style function templtes are used.

Example:

// usage: get<int>( value);
template<class ValueType>
CppTL::Any &get( const CppTL::Any &value );  // BAD

// usage: get(value,CppTL::Type<int>());
template<class ValueType>
CppTL::Any &get( const CppTL::Any &value, 
                 CppTL::Type<ValueType> );   // OK

Template member functions

Rules: Do not use template member functions (e.g. template methods).

Template member functions should be avoided as they are not well supported by older compiler (e.g. VC++ 6.0). Usually, a template free functions can be used instead, taking as first parameter an instance of the class type.

Examples:

class Any
{
   // Limited portability
   template<class ValueType>  
   void set( const ValueType &newValue );    // BAD
};

// Most portable, use class any as first parameter
template<class ValueType>
CppTL::Any &set( CppTL::Any &value, const ValueType &newValue );  // OK

Exception safety

We distinguish three levels of exception safety that a (member/free) function may provide:

Rules: All code should provide at least the weak exception safety guaranty. See [Resource Acquisition Is Initialization principle (RAII)] for tips on how to do that easily.

Strongly recommended reading: “Exceptional C++”, by Herb Sutter. This book contains very detailed examples explaining the some of the techniques exposed below (

Todo:
). Many of the articles of this book started their life in “Guru of the Week” columns: http://www.gotw.ca/gotw/.

Exception Specifications

Exception specification is the throw clause that specify the list of exception of function may throw (see example below).

Rules: Do not use throw specification unless required (subclassing std::exception for example).

Rationale: Compilers don’t deal as the one would expect in face of exception specification. They often generate extra code and may disable inlining. See boost guideline for detailed explanation: http://www.boost.org/more/lib_guide.htm#Exception-specification.

Recommendation: Document exception thrown by functions with comment

Example:

double getValueAt( int index ) throw(IndexError); // BAD

// / \exception IndexError is raised if the provided index is invalid.
double getValueAt( int index ); // GOOD

Resource Acquisition Is Initialization principle (RAII)

The essence of this principle is simple:

In the most simple case, resource is memory. A very common usage of this principle is probably for locking/unlocking exclusive lock.

C++ guaranty that the destructor will always be called if the function returns or an exception is thrown.

CppTL::ScopedPtr and CppTL::Mutex::ScopedLockGuard are examples of such objects.

Todo:

SourceForge Logo hosts this site. Send comments to:
CppUnit Developers