nonocast / me

记录和分享技术的博客
http://nonocast.cn
MIT License
20 stars 0 forks source link

学习 C/C++ (Part 19: unit test - googletest) #288

Open nonocast opened 2 years ago

nonocast commented 2 years ago

frameworks:

从人气来看googletest完胜。

googletest

install

 ./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.
% 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

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

参考阅读