## GTEST

* <!-- .element: class="fragment fade-in" --> <code>TEST(...)</code> Create single test
* <!-- .element: class="fragment fade-in" --> <code>TEST_F(...)</code> Use fixtures for testing
* <!-- .element: class="fragment fade-in" --> <code>TEST_P(...)</code> Use package of parameters for all tests
* <!-- .element: class="fragment fade-in" --> <code>EXPECT_*</code> Check condition
* <!-- .element: class="fragment fade-in" --> <code>ASSERT_*</code> Check condition and stop test if fails.
* <!-- .element: class="fragment fade-in" --> <code>EXPECT_PRED*</code> Allow to create own predicate, and other format of display errors
* <!-- .element: class="fragment fade-in" --> <code>testing::FloatLE</code> and <code>testing::DoubleLE</code> can be use for <code>EXPECT_PRED_FORMAT*</code> for floating-point comparison
* <!-- .element: class="fragment fade-in" --> <code>GTEST_SKIP()</code> can be use for skipping the test
* <!-- .element: class="fragment fade-in" --> <code>EXPECT_EXIT</code> can test signall which end program, like: <code>SIGKILL</code>
* <!-- .element: class="fragment fade-in" --> <code>EXPECT_THROW</code> will catch and check exceptions

___

## TEST

To create a simple test we can use `TEST` macro

```C++
class Calculator {
public:
    int add(int lsh, int rhs) { return lhs + rhs; }
};

TEST(CalculatorTest, ShouldAddTwoValues) {
    Calculator calc;
    EXPECT_EQ(calc.add(10, 20), 10 + 20);
}
```

<!-- .slide: data-background="#ccc" -->
___

## TEST_F

If we need to set up some structures before creating a test, we shouldn't do this every test, but instead create a test fixture that sets everything up during construction. It also provides useful methods which we can use in every test. This fixture is created first, then a test starts.

```C++
class DownloaderTest : public testing::Test {
public:
    DownloaderTest() {
        _connection = std::make_unique<TcpConnection>();
        _connection->set_certificates(_certificateMock);
        _downloader = std::make_unqiue<UrlDownloader>(_connection.get());
    }

    CertificateMock _certificateMock;
    std::unqiue_ptr<Connection> _connection;
    std::unique_ptr<Downloader> _downloader;
};

TEST_F(DownloaderTest, shouldDownloadImage) {
    EXPECT_CALL(_certificateMock, validate).WillOnce(Return(true));
    EXPECT_TRUE(_downloader.downloadImage("exampleImg"));
}
```
<!-- .slide: style="font-size: 0.77em" -->
___

## TEST_P (1)

Whenever we need to run the same test but with a different set of parameters we should use `TEST_P`

```C++
class Firewall {
public:
    virtual ~Firewall() = default;

    virtual bool block(const std::string& ipAddress) = 0;
};

class WhiteListFirewall : public Firewall {
public:
    void addToWhitelist(const std::string& ipAddress) {
        whiteList_.push_back(ipAddress);
    }

    bool block(const std::string& ipAddress) override {
        return std::find(cbegin(whiteList_), cend(whiteList_), ipAddress) == std::cend(whiteList_);
    }

private:
    std::vector<std::string> whiteList_;
};

```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.77em" -->
___
<!-- .slide: data-background="#ccc" -->
## TEST_P (2)

```C++
class TestFirewall : public testing::TestWithParam<std::pair<std::string, bool>> {
};

TEST_P(TestFirewall, ShouldFilterAdresses) {
    auto firewall = std::make_unique<WhiteListFirewall>();
    firewall->addToWhitelist("192.201.1.12");
    firewall->addToWhitelist("192.122.1.12");

    const auto& [address, isBlock] = GetParam();
    EXPECT_EQ(firewall->block(address), isBlock);
}

INSTANTIATE_TEST_SUITE_P(TestFirewallParameters,
                         TestFirewall,
                         testing::Values(
                             std::pair<std::string, bool>{"192.178.1.12", true},
                             std::pair<std::string, bool>{"192.144.1.12", true},
                             std::pair<std::string, bool>{"192.188.1.12", true},
                             std::pair<std::string, bool>{"192.201.1.12", false},
                             std::pair<std::string, bool>{"192.122.1.12", false}));
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.8em" -->
___
<!-- .slide: data-background="#ccc" -->
## TEST_P (3)

```
[----------] 5 tests from TestFirewallParameters/TestFirewall
[ RUN      ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/0
[       OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/0 (0 ms)
[ RUN      ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/1
[       OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/1 (0 ms)
[ RUN      ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/2
[       OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/2 (0 ms)
[ RUN      ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/3
[       OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/3 (0 ms)
[ RUN      ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/4
[       OK ] TestFirewallParameters/TestFirewall.ShouldFilterAdresses/4 (0 ms)
[----------] 5 tests from TestFirewallParameters/TestFirewall (0 ms total)
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.8em" -->
___
<!-- .slide: data-background="#ccc" -->
## TEST_P - inherit from other test

```C++
class BlackListFirewall : public Firewall {
public:
    void addToBlacklist(const std::string& ipAddress) {
        blackList_.push_back(ipAddress);
    }

    bool block(const std::string& ipAddress) override {
        return std::find(cbegin(blackList_), cend(blackList_), ipAddress) != std::cend(blackList_);
    }

private:
    std::vector<std::string> blackList_;
};

class BaseTestBlackListFirewall : public testing::Test {
public:
    void SetUp() override {
        firewall_ = std::make_unique<BlackListFirewall>();

        firewall_->addToBlacklist("192.201.1.12");
        firewall_->addToBlacklist("192.122.1.12");
        firewall_->addToBlacklist("192.178.1.12");
        firewall_->addToBlacklist("192.144.1.12");
        firewall_->addToBlacklist("192.188.1.12");
    }

    BlackListFirewall* firewall() const { return firewall_.get(); }

private:
    std::unique_ptr<BlackListFirewall> firewall_;
};
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.62em" -->
___
<!-- .slide: data-background="#ccc" -->
## testing::WithParamInterface

```C++
class TestBlackListFirewall : public BaseTestBlackListFirewall,
                              public testing::WithParamInterface<std::string> {
};

TEST_P(TestBlackListFirewall, ShouldBlock) {
    EXPECT_TRUE(firewall()->block(GetParam()));
}

INSTANTIATE_TEST_SUITE_P(TestBlackListFirewallPackage,
                         TestBlackListFirewall,
                         testing::Values(
                             "192.178.1.12",
                             "192.144.1.12",
                             "192.188.1.12",
                             "192.201.1.12",
                             "192.122.1.12"));
```
<!-- .element: class="fragment fade-in" -->

```
[----------] 5 tests from TestBlackListFirewallPackage/TestBlackListFirewall
[ RUN      ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/0
[       OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/0 (0 ms)
[ RUN      ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/1
[       OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/1 (0 ms)
[ RUN      ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/2
[       OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/2 (0 ms)
[ RUN      ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/3
[       OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/3 (0 ms)
[ RUN      ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/4
[       OK ] TestBlackListFirewallPackage/TestBlackListFirewall.ShouldBlock/4 (0 ms)
[----------] 5 tests from TestBlackListFirewallPackage/TestBlackListFirewall (0 ms total)
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.7em" -->
___

<!-- .slide: data-background="#ccc" -->
## EXPECT_PRED* - own error message

```C++
testing::AssertionResult isBlocked(Firewall* firewall, const std::string& addr, bool block) {
    if (firewall->block(addr) == block) {
        return testing::AssertionSuccess();
    }

    return testing::AssertionFailure() << addr << (block ? " should be blocked" : " shouldn't be blocked");
}

TEST_F(BaseTestBlackListFirewall, ShouldFilter) {
    EXPECT_TRUE(isBlocked(firewall(), "192.188.1.12", true));
    EXPECT_TRUE(isBlocked(firewall(), "192.188.1.12", false));
}
```
<!-- .element: class="fragment fade-in" -->

```
[----------] 1 test from BaseTestBlackListFirewall
[ RUN      ] BaseTestBlackListFirewall.ShouldFilter
/home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:101: Failure
Value of: isBlocked(firewall(), "192.188.1.12", false)
  Actual: false (192.188.1.12 shouldn't be blocked)
Expected: true
[  FAILED  ] BaseTestBlackListFirewall.ShouldFilter (0 ms)
[----------] 1 test from BaseTestBlackListFirewall (0 ms total)
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.7em" -->
___
<!-- .slide: data-background="#ccc" -->
## EXPECT_PRED* - check string

```C++
for (const auto& str : {"There is a nauka!", "nauka.programowania.ma@gmail.com"}) {
    EXPECT_THAT(str, testing::MatchesRegex(
        "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$"));

    ASSERT_THAT(str, testing::HasSubstr("nauka"));
}
```
<!-- .element: class="fragment fade-in" -->

```
[ RUN      ] ExampleTest.ShouldFail
/home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:104: Failure
Value of: str
Expected: matches regular expression "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$"
  Actual: 0x5625cd2c080c pointing to "There is a nauka!" (of type char const*)
[  FAILED  ] ExampleTest.ShouldFail (0 ms)
[----------] 1 test from ExampleTest (0 ms total)
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.85em" -->
___
<!-- .slide: data-background="#ccc" -->
## EXPECT_PRED* - comparison of floating point numbers

```C++
std::vector<std::pair<double, double>> vec{
    {43.45, 43.45}, {44.34321, 45.1234}, {1.12, 1.1199999}};

for (const auto& [lhs, rhs] : vec) {
    EXPECT_PRED_FORMAT2(testing::FloatLE, lhs, rhs);
    EXPECT_PRED_FORMAT2(testing::DoubleLE, lhs, rhs);
}
```
<!-- .element: class="fragment fade-in" -->

```
[ RUN      ] ExampleTest.ShouldFail
/home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:108: Failure
Expected: (lhs) <= (rhs)
  Actual: 1.1200000000000001 vs 1.1199999
[  FAILED  ] ExampleTest.ShouldFail (0 ms)
[----------] 1 test from ExampleTest (0 ms total)

[----------] Global test environment tear-down
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.7em" -->
___
<!-- .slide: data-background="#ccc" -->
## GTEST_SKIP

```C++
TEST(ExampleTest, ShouldFail) {
    GTEST_SKIP() << "Skipping test PR12345";
    
    std::vector<std::pair<double, double>> vec{
        {43.45, 43.45}, {44.34321, 45.1234}, {1.12, 1.1199999}};

    for (const auto& [lhs, rhs] : vec) {
        EXPECT_PRED_FORMAT2(testing::FloatLE, lhs, rhs);
        EXPECT_PRED_FORMAT2(testing::DoubleLE, lhs, rhs);
    }
}
```
<!-- .element: class="fragment fade-in" -->

```
[ RUN      ] ExampleTest.ShouldFail
/home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:102: Skipped
Skipping test PR12345
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.7em" -->
___
<!-- .slide: data-background="#ccc" -->
## Skipp all fixture

```C++
class BaseTestBlackListFirewall : public testing::Test {
public:
    void SetUp() override {
        GTEST_SKIP() << "Skipping test PR12345";
        firewall_ = std::make_unique<BlackListFirewall>();

        firewall_->addToBlacklist("192.201.1.12");
        firewall_->addToBlacklist("192.122.1.12");
        firewall_->addToBlacklist("192.178.1.12");
        firewall_->addToBlacklist("192.144.1.12");
        firewall_->addToBlacklist("192.188.1.12");
    }

    BlackListFirewall* firewall() const { return firewall_.get(); }

private:
    std::unique_ptr<BlackListFirewall> firewall_;
};
```
<!-- .element: class="fragment fade-in" -->

```
[----------] 3 tests from BaseTestBlackListFirewall
[ RUN      ] BaseTestBlackListFirewall.ShouldFilter
/home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:76: Skipped
Skipping test PR12345
[  SKIPPED ] BaseTestBlackListFirewall.ShouldFilter (0 ms)
[ RUN      ] BaseTestBlackListFirewall.ShouldNotFilter
/home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:86: Skipped
Skipping test PR12345
[  SKIPPED ] BaseTestBlackListFirewall.ShouldNotFilter (0 ms)
[ RUN      ] BaseTestBlackListFirewall.ShouldReportError
/home/mateusz.adamski/Documents/repoGit/advanced_cpp/examples/gtest.cpp:96: Skipped
Skipping test PR12345
[  SKIPPED ] BaseTestBlackListFirewall.ShouldReportError (0 ms)
[----------] 3 tests from BaseTestBlackListFirewall (0 ms total)
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.60em" -->
___
<!-- .slide: data-background="#ccc" -->
## EXPECT_EXIT and EXPECT_THROW

```C++
TEST(MyDeathTest, NormalExit) {
    EXPECT_EXIT(normalExit(), testing::ExitedWithCode(0), "Succes");
}

TEST(MyDeathTest, KillProcess) {
    EXPECT_EXIT(killProcess(), testing::KilledBySignal(SIGKILL),
                "Sending myself unblockable signal");
}

void foo(int val) {
    if (val != 42) {
        throw std::runtime_error("Wrong number");
    }
}

TEST(MyDeathTest, NormalExit) {
    EXPECT_THROW(foo(5), std::runtime_error);
}
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.7em" -->
___
<!-- .slide: data-background="#ccc" -->
## Sharing Resources Between Tests 

```C++
struct Foo {
    std::string name_;
    int value_;
};

class FooTest : public testing::Test {
public:
    // Shared
    static void SetUpTestSuite() {
        if (!shared_resource_) {
            shared_resource_ = std::make_unique<Foo>();
            shared_resource_->name_ = "Shared Foo!\n";
            shared_resource_->value_ = 42;
        }
    }

    // Shared
    static void TearDownTestSuite() {
        shared_resource_ = nullptr;
    }

    // Per-test
    void SetUp() override {}

    // Per-test
    void TearDown() override {}

protected:
    inline static std::unique_ptr<Foo> shared_resource_;
};

TEST_F(FooTest, Test1) {
    EXPECT_EQ(FooTest::shared_resource_->name_, "Shared Foo!\n");
    EXPECT_EQ(FooTest::shared_resource_->value_, 42);
    FooTest::shared_resource_->name_ = "Foo!!!";
    FooTest::shared_resource_->value_ = 13;
}

TEST_F(FooTest, Test2) {
    EXPECT_EQ(FooTest::shared_resource_->name_, "Foo!!!");
    EXPECT_EQ(FooTest::shared_resource_->value_, 13);
}
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.7em" -->
___
<!-- .slide: data-background="#ccc" -->
## Testing private code - should be avoided

```C++
class Foo {
private:
    FRIEND_TEST(FooTest, PrivateTest);

    int doSth(int val) { return val; }
};

TEST(FooTest, PrivateTest) {
    Foo foo;
    EXPECT_EQ(foo.doSth(42), 42);
}
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.9em" -->
___

## Exercise 1

Open project **SHM** and write test for class `Ship.cpp` which will test it's interface. Remember to test edge cases :). Test it well and fix issues.

Go to `Presentation/exercises/SHM/build/test` and run test using command `./SHM_Tests`.
