Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions test/coverage/.bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
common --registry=https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/
common --registry=https://bcr.bazel.build
34 changes: 34 additions & 0 deletions test/coverage/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
cc_library(
name = "coverage_lib",
srcs = ["coverage.cpp"],
hdrs = ["coverage.h"],
deps = ["//greeting:greeting"],
)

cc_binary(
name = "coverage",
srcs = ["main.cpp"],
deps = [
":coverage_lib",
],
)

cc_test(
name = "coverage_test",
srcs = ["coverage_test.cpp"],
deps = [
":coverage_lib",
"//greeting:greeting",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
size="small",
)

# Test suite for all components (individual tests)
test_suite(
name = "all_tests",
tests = [
":coverage_test",
],
)
23 changes: 23 additions & 0 deletions test/coverage/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module(
name = "coverage_test",
version = "0.1.0",
compatibility_level = 0,
)

# bazel cc rules
bazel_dep(name = "rules_cc", version = "0.1.1")

#score gcc toolchain
bazel_dep(name = "score_toolchains_gcc", version = "0.5", dev_dependency = False)

gcc = use_extension("@score_toolchains_gcc//extentions:gcc.bzl", "gcc", dev_dependency = False)
gcc.toolchain(
sha256 = "8fa85c2a93a6bef1cf866fa658495a2416dfeec692e4246063b791abf18da083",
strip_prefix = "x86_64-unknown-linux-gnu",
url = "https://github.com/eclipse-score/toolchains_gcc_packages/releases/download/v0.0.3/x86_64-unknown-linux-gnu_gcc12.tar.gz",
)
use_repo(gcc, "gcc_toolchain", "gcc_toolchain_gcc")

register_toolchains("@gcc_toolchain//:all")

bazel_dep(name = "googletest", version = "1.17.0.bcr.1", dev_dependency = True)
50 changes: 50 additions & 0 deletions test/coverage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Sample to generate coverage data
================================

This directory contains a sample C++ project with test coverage capabilities using Bazel and GCC's gcov/lcov tools.

## Prerequisites

Ensure you have the following tools installed:
- Bazel
- lcov (Linux Test Project coverage tools)

On Ubuntu/Debian:
```bash
sudo apt-get install lcov
```

## Running Tests with Coverage

### Step 1: Run tests with coverage collection

To generate coverage data for the `all_tests` target, run:

```bash
$ bazel coverage --combined_report=lcov --subcommands -- //:all_tests
```

### Step 2: View coverage summary with lcov

To get a quick coverage summary using lcov, you need to find the generated coverage files and use lcov:

```bash
$ lcov --summary --rc branch_coverage=1 bazel-out/_coverage/_coverage_report.dat
Summary coverage rate:
lines......: 100.0% (10 of 10 lines)
functions..: 100.0% (2 of 2 functions)
branches...: 100.0% (4 of 4 branches)
```

Alternatively, you can use the coverage files directly from the bazel-out directory:

```bash
# Find all .gcno and .gcda files
find -L bazel-out/ -name "*.gcda" -o -name "*.gcno" | head -10

# Generate coverage info file
lcov --capture --directory bazel-out --output-file coverage.info

# Show coverage summary
lcov --summary coverage.info
```
15 changes: 15 additions & 0 deletions test/coverage/coverage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "coverage.h"
#include "greeting/greeting.h"

namespace coverage {

// Extracted main logic for testing
void runMain(int argc, char* argv[]) noexcept {
if (argc > 1) {
greeting::printGreeting(argv[1]);
} else {
greeting::printGreeting("World");
}
}

} // namespace coverage
11 changes: 11 additions & 0 deletions test/coverage/coverage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef COVERAGE_COVERAGE_H
#define COVERAGE_COVERAGE_H

namespace coverage {

// Function to run main logic (extracted for testing)
void runMain(int argc, char* argv[]) noexcept;

} // namespace coverage

#endif // COVERAGE_COVERAGE_H
189 changes: 189 additions & 0 deletions test/coverage/coverage_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#include "coverage.h"
#include "greeting/greeting.h"
#include <gtest/gtest.h>
#include <sstream>
#include <iostream>

// Helper class to capture cout output
class CoutCapture {
public:
CoutCapture() {
old_cout_buffer = std::cout.rdbuf();
std::cout.rdbuf(captured_output.rdbuf());
}

~CoutCapture() {
std::cout.rdbuf(old_cout_buffer);
}

std::string getOutput() {
return captured_output.str();
}

private:
std::streambuf* old_cout_buffer;
std::ostringstream captured_output;
};

// =============================================================================
// MAIN FUNCTION TESTS
// =============================================================================

// Test fixture class for main functionality
class CoverageTest : public ::testing::Test {
protected:
void SetUp() override {
// Setup code if needed
}

void TearDown() override {
// Cleanup code if needed
}
};

// Test main function with no arguments (argc = 1) - should greet "World"
TEST_F(CoverageTest, MainWithNoArguments) {
CoutCapture capture;
const char* argv[] = {"./hello"};
coverage::runMain(1, const_cast<char**>(argv));
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, World!\n");
}

// Test main function with one argument - should greet that argument
TEST_F(CoverageTest, MainWithOneArgument) {
CoutCapture capture;
const char* argv[] = {"./hello", "Alice"};
coverage::runMain(2, const_cast<char**>(argv));
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, Alice!\n");
}

// Test main function with "Uwe" argument - should trigger special greeting
TEST_F(CoverageTest, MainWithUweArgument) {
CoutCapture capture;
const char* argv[] = {"./hello", "Uwe"};
coverage::runMain(2, const_cast<char**>(argv));
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello there, Uwe! Great to see you!\n");
}

// Test main function with multiple arguments - should only use the first one
TEST_F(CoverageTest, MainWithMultipleArguments) {
CoutCapture capture;
const char* argv[] = {"./hello", "Bob", "Charlie", "David"};
coverage::runMain(4, const_cast<char**>(argv));
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, Bob!\n");
}

// Test edge case: argc = 0 (unusual but possible)
TEST_F(CoverageTest, MainWithZeroArgc) {
CoutCapture capture;
const char* argv[] = {};
coverage::runMain(0, const_cast<char**>(argv));
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, World!\n");
}

// =============================================================================
// GREETING LIBRARY TESTS
// =============================================================================

// Test fixture class for greeting library
class GreetingTest : public ::testing::Test {
protected:
void SetUp() override {
// Setup code if needed
}

void TearDown() override {
// Cleanup code if needed
}
};

// Test case for greeting "Uwe" - should trigger special greeting
TEST_F(GreetingTest, GreetingForUwe) {
CoutCapture capture;
greeting::printGreeting("Uwe");
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello there, Uwe! Great to see you!\n");
}

// Test case for greeting any other name - should trigger regular greeting
TEST_F(GreetingTest, GreetingForRegularName) {
CoutCapture capture;
greeting::printGreeting("Alice");
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, Alice!\n");
}

// Test case for empty string
TEST_F(GreetingTest, GreetingForEmptyString) {
CoutCapture capture;
greeting::printGreeting("");
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, !\n");
}

// Test case for "World" - typical default case
TEST_F(GreetingTest, GreetingForWorld) {
CoutCapture capture;
greeting::printGreeting("World");
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, World!\n");
}

// Test case for case sensitivity - "uwe" (lowercase) should not trigger special greeting
TEST_F(GreetingTest, GreetingForLowercaseUwe) {
CoutCapture capture;
greeting::printGreeting("uwe");
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, uwe!\n");
}

// Test case for case sensitivity - "UWE" (uppercase) should not trigger special greeting
TEST_F(GreetingTest, GreetingForUppercaseUWE) {
CoutCapture capture;
greeting::printGreeting("UWE");
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, UWE!\n");
}

// Test case for string containing "Uwe" but not exactly "Uwe"
TEST_F(GreetingTest, GreetingForStringContainingUwe) {
CoutCapture capture;
greeting::printGreeting("Uwe Müller");
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, Uwe Müller!\n");
}

// Test case for numeric input
TEST_F(GreetingTest, GreetingForNumericInput) {
CoutCapture capture;
greeting::printGreeting("123");
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, 123!\n");
}

// Test case for special characters
TEST_F(GreetingTest, GreetingForSpecialCharacters) {
CoutCapture capture;
greeting::printGreeting("@#$%");
std::string output = capture.getOutput();

EXPECT_EQ(output, "Hello, @#$%!\n");
}
6 changes: 6 additions & 0 deletions test/coverage/greeting/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cc_library(
name = "greeting",
srcs = ["greeting.cpp"],
hdrs = ["greeting.h"],
visibility = ["//:__subpackages__"],
)
14 changes: 14 additions & 0 deletions test/coverage/greeting/greeting.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "greeting.h"
#include <iostream>

namespace greeting {

void printGreeting(const std::string& name) noexcept {
if (name == "Uwe") {
std::cout << "Hello there, Uwe! Great to see you!" << std::endl;
} else {
std::cout << "Hello, " << name << "!" << std::endl;
}
}

} // namespace greeting
12 changes: 12 additions & 0 deletions test/coverage/greeting/greeting.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef GREETING_GREETING_H
#define GREETING_GREETING_H

#include <string>

namespace greeting {

void printGreeting(const std::string& name) noexcept;

} // namespace greeting

#endif // GREETING_GREETING_H
6 changes: 6 additions & 0 deletions test/coverage/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "coverage.h"

int main(int argc, char* argv[]) {
coverage::runMain(argc, argv);
return 0;
}