me
me copied to clipboard
学习 C/C++ (Part 19: unit test - googletest)
frameworks:
- google/googletest: GoogleTest - Google Testing and Mocking Framework 26.4k stars
- CUnit | A Unit Testing Framework for C n/a
- Check | Unit testing framework for C 874 stars
从人气来看googletest完胜。
googletest
install
-
git clone https://github.com/google/googletest
-
mkdir build && cd $_ && cmake -Dgtest_build_samples=ON .. && make
- run test:
./googletest/sample1_unittest
./googletest/sample1_unittest
Running main() from /Users/nonocast/Develop/vendors/googletest/googletest/src/gtest_main.cc
[==========] Running 6 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 3 tests from FactorialTest
[ RUN ] FactorialTest.Negative
[ OK ] FactorialTest.Negative (0 ms)
[ RUN ] FactorialTest.Zero
[ OK ] FactorialTest.Zero (0 ms)
[ RUN ] FactorialTest.Positive
[ OK ] FactorialTest.Positive (0 ms)
[----------] 3 tests from FactorialTest (0 ms total)
[----------] 3 tests from IsPrimeTest
[ RUN ] IsPrimeTest.Negative
[ OK ] IsPrimeTest.Negative (0 ms)
[ RUN ] IsPrimeTest.Trivial
[ OK ] IsPrimeTest.Trivial (0 ms)
[ RUN ] IsPrimeTest.Positive
[ OK ] IsPrimeTest.Positive (0 ms)
[----------] 3 tests from IsPrimeTest (0 ms total)
[----------] Global test environment tear-down
[==========] 6 tests from 2 test suites ran. (0 ms total)
[ PASSED ] 6 tests.
-
sudo make install
- double check:
png-config --cflags --libs gtest
% pkg-config --cflags --libs gtest
-DGTEST_HAS_PTHREAD=1 -I/usr/local/include -L/usr/local/lib -lgtest
hello world (C++)
hello.cc
#include <gtest/gtest.h>
int add(int a, int b) { return a + b; }
TEST(suite1, test1) { EXPECT_EQ(3, add(1, 2)); }
int main(int argc, char *argv[]) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
clang++ -std=c++11 `pkg-config --cflags --libs gtest` -o hello hello.cc
运行后输出:
% ./hello
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from suite1
[ RUN ] suite1.test1
[ OK ] suite1.test1 (0 ms)
[----------] 1 test from suite1 (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
test c object file
hello.c
int add(int a, int b) { return a + b; }
hello_test.cc
#include <gtest/gtest.h>
extern "C" {
#include "hello.h"
}
TEST(suite1, test1) { EXPECT_EQ(3, add(1, 2)); }
compile & link
- hello.o:
clang -c hello.c
- hello_test.o:
clang ++ -std=c++11 -c hello_test.cc
- hello_test:
clang++ `pkg-config --cflags --libs gtest` -lgtest_main -o hello_test hello.o hello_test.o
run:
./hello_test
Running main() from /Users/nonocast/Develop/vendors/googletest/googletest/src/gtest_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from suite1
[ RUN ] suite1.test1
[ OK ] suite1.test1 (0 ms)
[----------] 1 test from suite1 (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
Demo
搞googletest就是为了通过sps/pps生成AVCDecoderConfigurationRecord,
先写一个test,
#include <gtest/gtest.h>
extern "C" {
#include "../src/bridge.h"
#include <librtmp/log.h>
}
typedef uint8_t byte;
TEST(rtmpext, avcheader) {
RTMP_LogSetLevel(RTMP_LOGALL);
size_t sps_size = 15;
const byte sps[] = {0x27, 0x4d, 0x00, 0x15, 0xab, 0x61, 0xa3, 0x7c, 0xb2, 0xcd, 0x40, 0x40, 0x40, 0x40, 0x80};
size_t pps_size = 4;
const byte pps[] = {0x28, 0xee, 0x3c, 0x80};
size_t buffer_size = 512;
byte buffer[buffer_size];
memset(buffer, 0, buffer_size);
buffer[0] = 0x01;
size_t expected_size = 30;
const byte expected[] = {0x01, 0x4d, 0x00, 0x15, 0xff, 0xe1, 0x00, 0x0f, 0x27, 0x4d, 0x00, 0x15, 0xab, 0x61, 0xa3,
0x7c, 0xb2, 0xcd, 0x40, 0x40, 0x40, 0x40, 0x80, 0x01, 0x00, 0x04, 0x28, 0xee, 0x3c, 0x80};
int32_t result_size = RTMPEXT_MakeAVCDecoderConfigurationRecord(sps, sps_size, pps, pps_size, buffer, buffer_size);
RTMP_LogHex(RTMP_LOGINFO, buffer, expected_size);
EXPECT_EQ(result_size, expected_size);
EXPECT_EQ(memcmp(buffer, expected, expected_size), 0);
}
有了脚手架,一步步来磨生成函数,毕竟对指针毫无抵抗,
#include <librtmp/log.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
size_t RTMPEXT_MakeAVCDecoderConfigurationRecord(const uint8_t *sps, size_t sps_size, const uint8_t *pps, size_t pps_size, uint8_t *buffer, size_t buffer_size) {
uint8_t *p = buffer;
// byte 1: version
*p++ = 0x01;
// byte 2-4: sps 1-3
for (int i = 0; i < 3; ++i) {
*p++ = *(sps + 1 + i);
}
// byte 5
*p++ = 0xff;
// byte 6: 低4位表示sps num
*p++ = 0xe1;
// byte 7-8: sps_size
// pps_size: 0x0f (15): 0f 00 00 00 00 00 00 00
uint8_t *sps_size_ptr = (uint8_t *) (&sps_size);
*p++ = *(sps_size_ptr + 1);
*p++ = *sps_size_ptr;
// byte 9-(9+sps_size): sps
for (int i = 0; i < sps_size; ++i) {
*p++ = *(sps + i);
}
// byte (9+sps_size+1): pps num
*p++ = 0x01;
uint8_t *pps_size_ptr = (uint8_t *) (&pps_size);
*p++ = *(pps_size_ptr + 1);
*p++ = *pps_size_ptr;
// byte (9+sps_size+2 - 9+sps_size+2+pps_size)
for (int i = 0; i < pps_size; ++i) {
*p++ = *(pps + i);
}
return p - buffer;
}
SetUp
#include <gtest/gtest.h>
extern "C" {
#include "../src/bridge.h"
#include <librtmp/log.h>
}
typedef uint8_t byte;
namespace {
class RTMPExtTest : public testing::Test {
protected:
void SetUp() override { RTMP_LogSetLevel(RTMP_LOGALL); }
};
TEST_F(RTMPExtTest, tag) {
//
}
TEST_F(RTMPExtTest, avcheader) {
size_t sps_size = 15;
const byte sps[] = {0x27, 0x4d, 0x00, 0x15, 0xab, 0x61, 0xa3, 0x7c, 0xb2, 0xcd, 0x40, 0x40, 0x40, 0x40, 0x80};
size_t pps_size = 4;
const byte pps[] = {0x28, 0xee, 0x3c, 0x80};
size_t buffer_size = 512;
byte buffer[buffer_size];
memset(buffer, 0, buffer_size);
buffer[0] = 0x01;
size_t expected_size = 30;
const byte expected[] = {0x01, 0x4d, 0x00, 0x15, 0xff, 0xe1, 0x00, 0x0f, 0x27, 0x4d, 0x00, 0x15, 0xab, 0x61, 0xa3,
0x7c, 0xb2, 0xcd, 0x40, 0x40, 0x40, 0x40, 0x80, 0x01, 0x00, 0x04, 0x28, 0xee, 0x3c, 0x80};
int32_t result_size = RTMPEXT_MakeAVCDecoderConfigurationRecord(sps, sps_size, pps, pps_size, buffer, buffer_size);
RTMP_LogHex(RTMP_LOGINFO, buffer, expected_size);
EXPECT_EQ(result_size, expected_size);
EXPECT_EQ(memcmp(buffer, expected, expected_size), 0);
}
} // namespace