Skip to content

Commit

Permalink
unitctest: Add C++ support
Browse files Browse the repository at this point in the history
Added initial support for C++ while keeping changes to a minimum.

Some caveats:
 - Comparisons rely on '==' operator of operands.
 - Compiler will signal errors if operand does not have '<<' implemented.
 - Currently mixing cerr with fprintf to take advantage of '<<'.
  • Loading branch information
luizinhosuraty committed Oct 18, 2022
1 parent 570c4ac commit 7485a81
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 12 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<h1>unitctest</h1>

![Standard](https://img.shields.io/badge/C-99/11/14/17-blue.svg)
![Standard](https://img.shields.io/badge/C++-11/14/17/20-blue.svg)
![License](https://img.shields.io/github/license/luizinhosuraty/unitctest)
![Lines of code](https://img.shields.io/tokei/lines/github/luizinhosuraty/unitctest?label=LoC-header)

Expand Down Expand Up @@ -57,10 +58,16 @@ Support for C++ is still under development.
Language | Version
----------------- | -----------------
C | C99*, C11, C14, C17
C++ | under development
C++** | C++1x, C++2x

*There is a known small issue with logging (related to print type)

** Some caveats :
- Comparisons rely on '==' operator of operands;
- Compiler will signal errors if operand does not have '<<' implemented;
- Currently mixing cerr with fprintf to take advantage of '<<'.


# Questions / FAQs

## Why another unit test framework ?
Expand Down
44 changes: 36 additions & 8 deletions include/unitctest/unitctest.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@
#ifndef _UNITCTEST_H
#define _UNITCTEST_H

#ifdef __cplusplus
#include <iostream>
#include <cstdio>
#else /* __cplusplus */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#endif /* __cplusplus */

#include <getopt.h>

/* -----------------------------------------------------------------------------
* Internal private structs and variables
Expand Down Expand Up @@ -45,7 +51,18 @@ extern struct __unitctest_ctx __ctx;
* Logs & co
* -----------------------------------------------------------------------------
*/
#ifdef __cplusplus

#define typeof decltype

#define __UNITCTEST_LOG_OPERAND(operand) std::cerr << operand;

#define __UNITCTEST_LOG_NAMESPACE std::

#else /* __cplusplus */

#if (__STDC_VERSION__ >= 201112L)

#define __UNITCTEST_LOG_FMT(x) \
_Generic((x), \
char: "%c", \
Expand All @@ -65,14 +82,26 @@ extern struct __unitctest_ctx __ctx;
char *: "%s", \
void *: "%p", \
default: "%p")
#else
#define __UNITCTEST_LOG_FMT(x) "%d"
#else /* __STDC_VERSION__ >= 201112L */

#define typeof __typeof__

#define __UNITCTEST_LOG_FMT(x) "%d"

#endif /* __STDC_VERSION__ >= 201112L */

#define __UNITCTEST_LOG(...) fprintf(stdout, __VA_ARGS__);
#define __UNITCTEST_LOG_OPERAND(operand) \
__UNITCTEST_LOG_ERR(__UNITCTEST_LOG_FMT(operand), operand);

#define __UNITCTEST_LOG_ERR(...) fprintf(stderr, __VA_ARGS__);
#define __UNITCTEST_LOG_NAMESPACE

#endif /* __cplusplus */

#define __UNITCTEST_LOG(...) \
__UNITCTEST_LOG_NAMESPACE fprintf(stdout, __VA_ARGS__);

#define __UNITCTEST_LOG_ERR(...) \
__UNITCTEST_LOG_NAMESPACE fprintf(stderr, __VA_ARGS__);

#define __UNITCTEST_LOG_TAP(...) __UNITCTEST_LOG(__VA_ARGS__);

Expand All @@ -88,7 +117,6 @@ extern struct __unitctest_ctx __ctx;
__UNITCTEST_LOG_TAP("ok %d - %s | %s # SKIP\n", \
__ctx.current_test->id, __ctx.current_test->name, \
__ctx.current_test->desc);

/* -----------------------------------------------------------------------------
* Asserts and Expects
* -----------------------------------------------------------------------------
Expand All @@ -104,9 +132,9 @@ extern struct __unitctest_ctx __ctx;
if (__ctx.verbosity) { \
__UNITCTEST_LOG_ERR(" %s:%d -> ", __FILE__, __LINE__); \
__UNITCTEST_LOG_ERR("%s(%s) failed (", type, #lhs #op #rhs); \
__UNITCTEST_LOG_ERR(__UNITCTEST_LOG_FMT(lhs), lhs); \
__UNITCTEST_LOG_OPERAND(lhs); \
__UNITCTEST_LOG_ERR(" %s ", #op); \
__UNITCTEST_LOG_ERR(__UNITCTEST_LOG_FMT(rhs), rhs); \
__UNITCTEST_LOG_OPERAND(rhs); \
__UNITCTEST_LOG_ERR(") -> %s", strerr); \
__UNITCTEST_LOG_ERR("\n"); \
}
Expand Down
12 changes: 9 additions & 3 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,31 @@ test_build_dir := build/
test_dir := ./
test_includes := $(addprefix -I, $(unitctest_framework))
test_cflags := -g -Wall $(test_includes)
test_depfiles = $(addprefix $(test_build_dir), $(targets:=.d))
test_cppflags := -g -Wall -std=c++1y $(test_includes)
ttest_depfiles = $(addprefix $(test_build_dir), $(targets:=.d))

targets := assert_true_false\
assert_int\
expect_true_false\
expect_int\
fixture\
test_skip
test_skip\
vectors

all : $(targets)

$(test_build_dir)%.o : %.c Makefile | $(test_build_dir)
@printf $(KBLUE)"---- building $@ ----\n"$(KNORM)
$(CC) $(test_cflags) -c -MMD -MP $< -o $@

$(test_build_dir)%.o : %.cpp Makefile | $(test_build_dir)
@printf $(KBLUE)"---- building $@ ----\n"$(KNORM)
$(CXX) $(test_cppflags) -c -MMD -MP $< -o $@

$(targets): %: $(test_build_dir)%.o
@printf $(KBLUE)"---- linking $@----\n"$(KNORM)
@printf "$(test_depfiles)"
$(CC) -o $@.test $<
$(CXX) -o $@.test $<

$(test_build_dir):
@printf $(KBLUE)"---- create $@ dir ----\n"$(KNORM)
Expand Down
39 changes: 39 additions & 0 deletions test/vectors.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* vector.cpp - Test C++ using vector type
*
* Copyright (c) 2022 Luiz Henrique Suraty Filho <[email protected]>
*
* SPDX-License-Identifier: MIT
*
*/

#include <vector>
#include "unitctest/unitctest.h"

template <typename T>
std::ostream &operator<<(std::ostream &out, const std::vector<T> &v)
{
out << "[";
for (std::vector<int>::size_type i = 0; i < v.size(); ++i) {
out << v[i];
if (i != v.size() - 1)
out << ", ";
}
out << "]";
return out;
}

/* Note that we rely on '==' operator for comparisons */
TEST(vector, "Check if two vectors are equal (a == b)")
{
std::vector<int> a = { 0, 0, 1, 0 };
std::vector<int> b = { 0, 0, 1, 0 };
EXPECT_EQ(a, b, "Both vectors should be '=='");

a.push_back(0);
EXPECT_NEQ(a, b, "a added 0, vectors should NOT be '=='");

b.push_back(0);
EXPECT_EQ(a, b, "Both vectors should be '==' again");
}

TEST_MAIN()

0 comments on commit 7485a81

Please sign in to comment.