C++ GMock

add it to cmake

target_link_libraries (target_name gtest_main gmock_main gtest )

Matchers

MATCHER_P(M1,p,""){
return p>10;
}

TEST(TESTS,t1){
    testing::Matcher<int> m1(12);
    EXPECT_THAT(12,m1);
    EXPECT_THAT(true,M1(12));
    EXPECT_TRUE(m1.Matches(12));
    EXPECT_THAT(12,testing::AllOf(testing::Gt(0),testing::Lt(100)));
}

expect call

class A{
public:
    virtual void fun()const=0;
    virtual void fun2(int l)const=0;
};
class MockA:public A{
public:
    MOCK_METHOD(void,fun,(),(const override));
    MOCK_METHOD(void,fun2,(int),(const override));
};

using ::testing::AtLeast;                         // #1

TEST(PainterTest, CanDrawSomething) {
    MockA turtle;
    EXPECT_CALL(turtle, fun2(22))                  // #3
            .Times(2);//expect call this function twice with argument 22
    turtle.fun2(22);// #2//first call
    turtle.fun2(22);// #2// second call 
    // test passed because this function called twice
}

C++ GTest

install GTest with CMake

https://google.github.io/googletest/quickstart-cmake.html

include(FetchContent)
FetchContent_Declare(
        googletest
        URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
enable_testing()

target_link_libraries(
        target_name
        gtest_main gtest
)

first example

#include <gtest/gtest.h>
#include "random"

TEST(test1,t1){
    std::default_random_engine re(std::chrono::system_clock::now().time_since_epoch().count());
    std::uniform_int_distribution<uint8_t>rn(0,10);
    int v1=rn(re),v2=rn(re);
    EXPECT_EQ(v1,v2) << "Vectors x and y are of unequal length";
}
int main(int argc, char *argv[]) {
    testing::InitGoogleTest(&argc,argv);
    return RUN_ALL_TESTS();
}
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from test1
[ RUN      ] test1.t1
[       OK ] test1.t1 (0 ms)
[----------] 1 test from test1 (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.

EXPECT AND ASSERT

  • ASSERT: Fails fast, aborting the current function.
  • EXPECT: Continues after the failure.

expect throw and death

Test Fixture

class MyTest : public ::testing::Test {

protected:
    void SetUp()override { //done before test like MyTest constructor
        val=12;
    }
    void TearDown()override{//done after test like ~MyTest

    }
    void add(){
        val+=12;
    }
    int val;
};

TEST_F(MyTest, t1) {
    add();
    EXPECT_EQ(val,66)<<string(__FILE__)+":"+string(std::to_string(__LINE__));
}

Disabling and Skipping Tests

Test Filtering

you can run it with parameters to add more options for testing
for filtering, you can add

--gtest_filter=*.f*

Parametrized Test

class LeapYearParameterizedTestFixture :public ::testing::TestWithParam<int> {
protected:
    int val;
};

TEST_P(LeapYearParameterizedTestFixture, OddYearsAreNotLeapYears) {
    val = GetParam();
    ASSERT_EQ(val,12);
}

INSTANTIATE_TEST_CASE_P(
        LeapYearTests,
        LeapYearParameterizedTestFixture,
        ::testing::Values(
                1, 711, 12, 2013
        ));

Mastering CMake (2)

Setting Up Your First CMake Project

cmake_minimum_required(VERSION 3.20)
project(Hello)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(Hello hello.cpp)

project(<PROJECT-NAME>
        [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
        [DESCRIPTION <project-description-string>]
        [HOMEPAGE_URL <url-string>]
        [LANGUAGES <language-name>...])

cmake_minimum_required(VERSION 3.20.0)
project(Rental CXX)
add_executable(Rental
               main.cpp
               cars/car.cpp  
               # more files in other directories 
)

Working with Targets

Essentially, it’s a recipe that a buildsystem uses to compile a list of files into another file. It can be a .cpp implementation file compiled into an .o object file, a group of .o files packaged into an .a static library, and many other combinations.

All that’s required is an add_executable() command with the name of the executable target and a list of the files that are to be its elements

In CMake, we can create a target using one of three commands:

  • add_executable()
  • add_library()
  • add_custom_target()

add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [<source>...])

add_executable(<name> [WIN32] [MACOSX_BUNDLE]
               [EXCLUDE_FROM_ALL]
               [source1] [source2 ...])

for build you can specify a target or build all project

--build binary_directroy --target [all|target]

add source to target

add_executable(main main.cpp)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
  target_sources(main PRIVATE gui_linux.cpp)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  target_sources(main PRIVATE gui_windows.cpp)
endif()

preprocessing definitions

add paths to include

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [item1...]
  [<INTERFACE|PUBLIC|PRIVATE> [item2...] ...])

add definition

set(VAR 8)
add_executable(defined definitions.cpp)
target_compile_definitions(defined PRIVATE ABC
  "DEF=${VAR}")
int main() {
#if defined(ABC)
    std::cout << "ABC is defined!" << std::endl;
#endif
#if (DEF < 2*4-3)
    std::cout << "DEF is greater than 5!" << std::endl;
#endif
}

compiler flags

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")

Managing Dependencies with CMake

  • A static library has a .a extension on Unix-like systems and .lib on Windows.
  • Shared libraries have a .so extension on Unix-like systems and .dll on Windows.

if you install library like

apt install protobuf-compiler libprotobuf-dev

find_package(Protobuf REQUIRED)
target_link_libraries(main PRIVATE ${Protobuf_LIBRARIES})
target_include_directories(main PRIVATE 
  ${Protobuf_INCLUDE_DIRS}
  ${CMAKE_CURRENT_BINARY_DIR})

find_package(Protobuf REQUIRED) asks CMake to run the bundled FindProtobuf.cmake find-module and set up the Protobuf library for us. That find-module will scan commonly used paths and (because we provided the REQUIRED keyword) terminate if a library is not found. It will also specify useful variables and functions (such as the one on the next line).
target_link_libraries adds libraries (static or shared) found by find_package() to the linking command of our main target.

  • <PKG_NAME>_FOUND
  • <PKG_NAME>_INCLUDE_DIRS or <PKG_NAME>_INCLUDES
  • <PKG_NAME>_LIBRARIES or <PKG_NAME>_LIBRARIES or <PKG_NAME>_LIBS
  • <PKG_NAME>_DEFINITIONS
  • IMPORTED targets specified by the find-module or config-file

find_package(<Name> [version] [EXACT] [QUIET] [REQUIRED])

for cmake files have format <package>Config.cmake

find_package(Foo CONFIG REQUIRED)
target_link_libraries(boo foo)
add_library(MyLib SHARED ./lib/MyLib.cpp)
target_link_directories(MyLib PUBLIC ./lib)
target_include_directories(MyLib PUBLIC ./lib)
find_package(TBB REQUIRED)
target_link_libraries(MyLib PUBLIC tbb)

#libraries linked to MyLib target like tbb will used inside test target because it linked with MyLib and MyLib is public link with tbb

add_executable(test main.cpp ${res_files})
find_package(Qt6 REQUIRED COMPONENTS Core)
target_link_libraries(test PRIVATE Qt6::Core)
target_link_libraries(test  PUBLIC MyLib)

Mastering CMake (1)

Command Lines

Generating a project buildsystem

cmake [<options>] -S <path-to-source> -B <path-to-build>
cmake [<options>] <path-to-source>
cmake [<options>] <path-to-existing-build>
#Build in the ./build directory, and use a source from the current directory:
cmake -B build
#Build in the current directory, but take the source from one directory up (note that -S is optional):
cmake -S ..

choose generator
This can be overridden by the CMAKE_GENERATOR environment variable or by specifying the generator directly on the command line

cmake -G <generator-name> <path-to-source>

We can provide a path to the CMake script, which (only) contains a list of set() commands to specify variables that will be used to initialize an empty build tree.

cmake -D <var>[:<type>]=<value> <path-to-source>
cmake -S . -B build -D CMAKE_BUILD_TYPE=Release

to build project

cmake --build <dir>

Options for parallel builds

cmake --build <dir> --parallel [<number-of-jobs>]
cmake --build <dir> -j [<number-of-jobs>]

CMake Language

 the execution begins from the root file of the source tree (CMakeLists.txt) or a .cmake script file that was passed as an argument to cmake

Comments

# single-line comments start with a hash sign "#"
# they can be placed on an empty line
message("Hi"); # or after a command like here.
#[=[ 
bracket comment
  #[[
    nested bracket comment
  #]]
#]=]

Command invocations

command(argument1 "argument2" argument3) # comment
#[[ multiline comment ]] 

double qouted

message(${OpenCL_LIBRARY})
message("1. escape sequence: \" \n in a quoted argument")
message("2. multi...
  line")
message("3. and a variable reference: ${CMAKE_VERSION}")

Working with variables

1- Variable names are case-sensitive and can include almost any character.
2-All variables are stored internally as strings, even if some commands can interpret them as values of other data types (even lists!).
3-The basic variable manipulation commands are set() and unset(), but there are other commands that can affect variables, such as string() and list().

set(MyString1 "Text1")
set([[My String2]] "Text2")
set("My String 3" "Text3")
message(${MyString1})
message(${My\ String2})
message(${My\ String\ 3})
  • If the following reference is encountered – ${MyOuter${MyInner}} – CMake will try to evaluate MyInner first, rather than searching for a variable named MyOuter${MyInner}.
  • If the MyInner variable is successfully expanded, CMake will repeat the expansion process until no further expansion is possible.
  • The ${} syntax is used to reference normal or cache variables.
  • The $ENV{} syntax is used to reference environment variables.
  • The $CACHE{} syntax is used to reference cache variables.
set(ENV{CXX} "clang++")
cmake_minimum_required(VERSION 3.20.0)
project(Environment)
message("generated with " $ENV{myenv})

#!/bin/bash
export myenv=first
echo myenv is now $myenv
cmake -B build .
cd build
export myenv=second
echo myenv is now $myenv
cmake --build .
$ ./build.sh | grep -v "\-\-"
myenv is now first
generated with first
myenv is now second
Scanning dependencies of target EchoEnv
myenv in build is first
Built target EchoEnv

scope of variables

function(Inner)
  message("  > Inner: ${V}")
  set(V 3)
  message("  < Inner: ${V}")
endfunction()
function(Outer)
  message(" > Outer: ${V}")
  set(V 2)
  Inner()
  message(" < Outer: ${V}")
endfunction()
set(V 1)
message("> Global: ${V}")
Outer()
message("< Global: ${V}")
> Global: 1
 > Outer: 1
  > Inner: 2
  < Inner: 3
 < Outer: 2
< Global: 1
set(V 3 PARENT_SCOPE)
> Global: 1
 > Outer: 1
  > Inner: 2
  < Inner: 2
 < Outer: 3
< Global: 1

Lists

set(myList 1 2 3 4)
set(myList "a;list;of;five;elements")
set(myList a list "of;five;elements")

message("the list is:" ${myList}) 

The message() command will receive here six arguments: “the list is:“, “a“, “list“, “of“, “five“, “elements“.

list(LENGTH <list> <out-var>)
list(GET <list> <element index> [<index> ...] <out-var>)
list(JOIN <list> <glue> <out-var>)
list(SUBLIST <list> <begin> <length> <out-var>)
list(FIND <list> <value> <out-var>)
list(APPEND <list> [<element>...])
list(FILTER <list> {INCLUDE | EXCLUDE} REGEX <regex>)
list(INSERT <list> <index> [<element>...])
list(POP_BACK <list> [<out-var>...])
list(POP_FRONT <list> [<out-var>...])
list(PREPEND <list> [<element>...])
list(REMOVE_ITEM <list> <value>...)
list(REMOVE_AT <list> <index>...)
list(REMOVE_DUPLICATES <list>)
list(TRANSFORM <list> <ACTION> [...])
list(REVERSE <list>)
list(SORT <list> [...])

Understanding control structures in CMake

if(<condition>)
  <commands>
elseif(<condition>) # optional block, can be repeated
  <commands>
else()              # optional block
  <commands>
endif()

The provided <condition> expression is evaluated according to a very simple syntax.

The same syntax is valid for if()elseif(), and while() commands.

The if() conditions support the NOTAND, and OR logical operators:

  • NOT <condition>
  • <condition> AND <condition>
  • <condition> OR <condition>
  • (<condition>) AND (<condition> OR (<condition>))
  • EQUALLESSLESS_EQUALGREATER, and GREATER_EQUAL
  • “A” STREQUAL “${B}”
  • <file1> IS_NEWER_THAN <file2>: Checks which file is newe
  •  <VARIABLE|STRING> IN_LIST <VARIABLE>
  • <VARIABLE|STRING> MATCHES <regex>
set(VAR1 FALSE)
set(VAR2 "VAR1")
if(${VAR2})
  • ONYYES, or TRUE
  • A non-zero number
  • OFFNOFALSENIGNORENOTFOUND
  • A string ending with -NOTFOUND
  • An empty string
  • Zero

Loops

while(<condition>)
  <commands>
endwhile()
foreach(<loop_variable> IN [LISTS <lists>] [ITEMS <items>])
set(MY_LIST 1 2 3) #set(MY_LIST "1;2;3")
foreach(VAR IN LISTS MY_LIST)
  message(${VAR})
endforeach()

Command definitions

  • macro() command works more like a find-and-replace instruction than an actual subroutine call such as function().
  • The function() command creates a separate scope for local variables, unlike the macro() command, which works in the variable scope of a caller.
macro(<name> [<argument>…])
  <commands>
endmacro()
function(<name> [<argument>…])
  <commands>
endfunction()
macro(MyMacro myVar)
  set(myVar "new value")
  message("argument: ${myVar}")
endmacro()
set(myVar "first value")
message("myVar is now: ${myVar}")
MyMacro("called value")
message("myVar is now: ${myVar}")

Useful commands

execute_process to run external command

execute_process(COMMAND echo "hello world")

execute_process(COMMAND <cmd1> [args1...]]
                [COMMAND <cmd2> [args2...] [...]]
                [WORKING_DIRECTORY <directory>]
                [TIMEOUT <seconds>]
                [RESULT_VARIABLE <variable>]
                [OUTPUT_VARIABLE <variable>]
                [ERROR_VARIABLE <variable>]
                [INPUT_FILE <file>]
                [OUTPUT_FILE <file>]
                [ERROR_FILE <file>]
                [OUTPUT_QUIET]
                [ERROR_QUIET]
                [OUTPUT_STRIP_TRAILING_WHITESPACE]
                [ERROR_STRIP_TRAILING_WHITESPACE])

file to read or write from or to file

file(READ <filename> <out-var> [...])
file({WRITE | APPEND} <filename> <content>...)
file(DOWNLOAD <url> [<file>] [...])
file(GLOB_RECURSE QMLS "${QML_FOLDER}/*.qml") #get files with format as QMLS list
file(COPY ${QMLS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${QML_FOLDER}) #Copy files

include to add and execute other CMake file

include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>])

Conan C++ Package Manager

install conan

sudo apt install python3-pip
pip install conan

looking for library

conan search poco --remote=conancenter
poco/1.8.1
poco/1.9.3
poco/1.9.4

creating a conanfile.txt inside our project’s folder with the following content:

[requires]
 poco/1.9.4

 [generators]
 cmake

Next step: We are going to install the required dependencies and generate the information for the build system:

$ conan profile new default --detect  # Generates default profile detecting GCC and sets old ABI
$ conan profile update settings.compiler.libcxx=libstdc++11 default  # Sets libcxx to C++11 ABI
$ mkdir build && cd build  #create build folder of cmake binary
$ conan install ..           #install libraries
#or conan install .. --settings os="Linux" --settings compiler="gcc"

Now let’s create our build file. To inject the Conan information, include the generated conanbuildinfo.cmake file like this:

 cmake_minimum_required(VERSION 2.8.12)
 project(MD5Encrypter)

 add_definitions("-std=c++11")

 include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
 conan_basic_setup()

 add_executable(md5 md5.cpp)
 target_link_libraries(md5 ${CONAN_LIBS})

C Libraries

stdlib

double atof(const char *str)
Converts the string pointed to, by the argument str to a floating-point number (type double).
int atoi(const char *str)
Converts the string pointed to, by the argument str to an integer (type int).
long int atol(const char *str)
Converts the string pointed to, by the argument str to a long integer (type long int).
double strtod(const char *str, char **endptr)
Converts the string pointed to, by the argument str to a floating-point number (type double).
long int strtol(const char *str, char **endptr, int base)
Converts the string pointed to, by the argument str to a long integer (type long int).
unsigned long int strtoul(const char *str, char **endptr, int base)
Converts the string pointed to, by the argument str to an unsigned long integer (type unsigned long int).
void *calloc(size_t nitems, size_t size)
Allocates the requested memory and returns a pointer to it.
void free(void *ptr)
Deallocates the memory previously allocated by a call to calloc, malloc, or realloc.
void *malloc(size_t size)Allocates the requested memory and returns a pointer to it.
void *realloc(void *ptr, size_t size)
Attempts to resize the memory block pointed to by ptr that was previously allocated with a call to malloc or calloc.
void abort(void)
Causes an abnormal program termination.
int atexit(void (*func)(void))
Causes the specified function func to be called when the program terminates normally.
void exit(int status)
Causes the program to terminate normally.
char *getenv(const char *name)
Searches for the environment string pointed to by name and returns the associated value to the string.
int system(const char *string)
The command specified by string is passed to the host environment to be executed by the command processor.
void *bsearch(const void *key, const void *base, size_t nitems, size_t size, int (*compar)(const void *, const void *))
Performs a binary search.
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
Sorts an array.
int abs(int x)
Returns the absolute value of x.
div_t div(int numer, int denom)
Divides numer (numerator) by denom (denominator).
long int labs(long int x)
Returns the absolute value of x.
ldiv_t ldiv(long int numer, long int denom)
Divides numer (numerator) by denom (denominator).
int rand(void)
Returns a pseudo-random number in the range of 0 to RAND_MAX.
void srand(unsigned int seed)
This function seeds the random number generator used by the function rand.
int mblen(const char *str, size_t n)
Returns the length of a multibyte character pointed to by the argument str.
size_t mbstowcs(schar_t *pwcs, const char *str, size_t n)
Converts the string of multibyte characters pointed to by the argument str to the array pointed to by pwcs.
int mbtowc(whcar_t *pwc, const char *str, size_t n)
Examines the multibyte character pointed to by the argument str.
size_t wcstombs(char *str, const wchar_t *pwcs, size_t n)
Converts the codes stored in the array pwcs to multibyte characters and stores them in the string str.
int wctomb(char *str, wchar_t wchar)
Examines the code which corresponds to a multibyte character given by the argument wchar.
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main () {
   int n=4;//number of elements
   int *a;
   a = (int*)calloc(n, sizeof(int));

   char *str;
   str = (char *) malloc(15);
   strcpy(str, "tutorialspoint");
   str = (char *) realloc(str, 25);
   strcat(str, ".com");//append string

   free(str);
   free( a );
   
   return(0);
}