自制 Cpp 測試框架(二)
阿新 • • 發佈:2021-01-05
技術標籤:Cpp
實戰專案中的腦補能力
- 實現除錯資訊 LOG日誌列印功能
- 實現 EXPECT系列封裝
- 實現 COLOR系列封裝
- 使用 __attribute__ 完成函式註冊
- 完善功能:測試框架初養成
實現除錯資訊 LOG日誌列印功能
從理解 LOG 日誌功能需求開始
預測處理命令-巨集定義
// 定義符號常量:
#define PI 3.1415926
#define MAX_N 10000
// 定義傻瓜表示式
#define MAX(a, b) (a) > (b) ? (a) : (b)
#define S(a, b) a * b
// 定義程式碼段
#define P(a) {
printf ("%d\n", a);
}
預處理命令-預定義的巨集
巨集 | 說明 |
---|---|
__DATE__ | 日期:Mmm dd yyyy |
__TIME__ | 時間:hh:mm:ss |
__LINE__ | 行號 |
__FILE__ | 檔名 |
__func__ | 函式名/非標準 |
__FUNC__ | 函式名/非標準 |
__PRETTY_FUNCTION__ | 更詳細的函式資訊/非標準 |
#include<stdio.h>
int main() {
printf("__LINE__ = %d\n", __LINE__);
printf("__FILE__ = %s\n", __FILE__) ;
printf("__func__ = %s\n", __func__);
printf("__PRETTY_FUNCTION__ = %s\n", __PRETTY_FUNCTION__);
return 0;
}
//__LINE__ = 3
//__FILE__ = /Users/harrytsz/Documents/Workspaces/harrytsz-cpp/ShaoFaBook/main.cpp
//__func__ = main
//__PRETTY_FUNCTION__ = int main()
#include<stdio.h>
// '\' 表示換行符,巨集定義只有一行
#define LOG(frm, args...) { \
printf("\033[0;33m[%s : %s : %d] \033[0m", __FILE__, __func__, __LINE__);\
printf(frm, ##args);\
printf("\n");\
}
void test() {
LOG("hello world");
return ;
}
int main() {
LOG("Hello World");
test();
return 0;
}
// [/Users/harrytsz/Documents/Workspaces/harrytsz-cpp/ShaoFaBook/main.cpp : main : 16] Hello World
// [/Users/harrytsz/Documents/Workspaces/harrytsz-cpp/ShaoFaBook/main.cpp : test : 11] hello world
#include<stdio.h>
// ## 表示連線的作用
#define CAT(a, b) a##_##b
int main() {
int kaikeba_var = 9973;
CAT(kaikeba, var) = 1000;
LOG("kaikeba_var = %d", kaikeba_var);
return 0;
}
// [/Users/harrytsz/Documents/Workspaces/harrytsz-cpp/ShaoFaBook/main.cpp : main : 20] kaikeba_var = 1000
開啟或關閉日誌
- 第一種方法:設定判斷變數
#include<stdio.h>
int log_flag = 1; // 1 輸出日誌; 0 關閉日誌
// '\' 表示換行符,巨集定義只有一行
#define LOG(frm, args...) do { \
if (log_flag == 0) break; \
printf("\033[0;33m[%s : %s : %d] \033[0m", __FILE__, __func__, __LINE__);\
printf(frm, ##args);\
printf("\n");\
} while (0);
void test() {
LOG("hello world");
int a = 1, b = 2;
printf("%d %d\n", a, b);
return ;
}
int main() {
LOG("Hello World");
int a = 1, b = 2;
test();
return 0;
}
// [/Users/harrytsz/Documents/Workspaces/harrytsz-cpp/ShaoFaBook/main.cpp : main : 20] Hello World
// [/Users/harrytsz/Documents/Workspaces/harrytsz-cpp/ShaoFaBook/main.cpp : test : 13] hello world
// 1 2
- 第 2 種方法:刪除巨集定義,並修改巨集定義
#include<stdio.h>
// '\' 表示換行符,巨集定義只有一行
#define LOG(frm, args...) do { \
printf("\033[0;33m[%s : %s : %d] \033[0m", __FILE__, __func__, __LINE__);\
printf(frm, ##args);\
printf("\n");\
}
// 刪除巨集定義,並重新定義巨集
#undef LOG
#define LOG(frm, args...)
void test() {
LOG("hello world");
int a = 1, b = 2;
printf("%d %d\n", a, b);
return ;
}
int main() {
LOG("Hello World");
int a = 1, b = 2;
test();
return 0;
}
// 1 2
預處理命令-條件式編譯
函式 | 說明 |
---|---|
#ifdef DEBUG | 是否定義了 DEBUG 巨集 |
#ifndef DEBUG | 是否沒定義 DEBUG 巨集 |
#if MAX_N == 5 | 巨集 MAX_N是否等於 5 |
#elif MAX_N == 4 | 否則巨集 MAX_N 是否等於 4 |
#else | 否則 |
#endif | 條件判斷結束 |
- 第 3 種方法:條件式編譯
#include<stdio.h>
#define DEBUG
#ifdef DEBUG
// '\' 表示換行符,巨集定義只有一行
#define LOG(frm, args...) {\
printf("\033[0;33m[%s : %s : %d] \033[0m", __FILE__, __func__, __LINE__);\
printf(frm, ##args);\
printf("\n");\
}
#else
#define LOG(frm, args...)
#endif
void test() {
LOG("hello world");
int a = 1, b = 2;
printf("%d %d\n", a, b);
return ;
}
int main() {
LOG("Hello World");
int a = 1, b = 2;
test();
return 0;
}
// [/Users/harrytsz/Documents/Workspaces/harrytsz-cpp/ShaoFaBook/main.cpp : main : 24] Hello World
// [/Users/harrytsz/Documents/Workspaces/harrytsz-cpp/ShaoFaBook/main.cpp : test : 17] hello world
// 1 2
//
// Created by harrytsz on 2021/1/4.
//
#ifndef SHAOFABOOK_KTEST_H
#define SHAOFABOOK_KTEST_H
#define EXPECT(a, cmp, b) { \
if(!((a) cmp (b))) { \
printf("error\n"); \
}\
}
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#endif //SHAOFABOOK_KTEST_H
實現 COLOR系列封裝
ktest.h
//
// Created by harrytsz on 2021/1/4.
//
#ifndef SHAOFABOOK_KTEST_H
#define SHAOFABOOK_KTEST_H
#define EXPECT(a, cmp, b) { \
if(!((a) cmp (b))) { \
printf("error\n"); \
}\
}
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define COLOR(msg, code) "\033[0;1;" #code "m" msg "\033[0m"
#define RED(msg) COLOR(msg, 31)
#define GREEN(msg) COLOR(msg, 32)
#define YELLOW(msg) COLOR(msg, 33)
#define BLUE(msg) COLOR(msg, 34)
#endif //SHAOFABOOK_KTEST_H
#include<stdio.h>
#include "ktest.h"
int main() {
printf("hello world\n");
printf(RED("hello world\n"));
printf(GREEN("hello world\n"));
printf(YELLOW("hello world\n"));
printf(BLUE("hello world\n"));
return 0;
}
使用 __attribute__ 完成函式註冊功能
#include<stdio.h>
__attribute__((constructor)) void test() {
printf("test : hello world\n");
return ;
}
int main() {
printf("main : hello world\n");
return 0;
}
// test : hello world
// main : hello world
完善功能:測試框架初養成
//
// Created by harrytsz on 2021/1/4.
//
#ifndef SHAOFABOOK_KTEST_H
#define SHAOFABOOK_KTEST_H
#define EXPECT(a, cmp, b) { \
__typeof(a) __a = (a), __b = (b); \
if(!((__a) cmp (__b))) { \
printf(YELLOW("%s:%d: Failure\n", __FILE__, __LINE__)); \
printf(YELLOW("Expected: (%s) %s (%s), actual : %d vs %d\n", \
#a, #cmp, #b, __a, __b)); \
}\
}
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define EXPECT_EQ(a, b) EXPECT(a, ==, b);
#define COLOR(msg, code) "\033[0;1;" #code "m" msg "\033[0m"
#define RED(msg) COLOR(msg, 31)
#define GREEN(msg) COLOR(msg, 32)
#define YELLOW(msg) COLOR(msg, 33)
#define BLUE(msg) COLOR(msg, 34)
#define TEST(a, b) \
void kaikeba_##a##_##b(); \
__attribute__((constructor)) \
void reg_##a##_##b() { \
add_test_func(kaikeba_##a##_##b, #a "." #b); \
} \
void kaikeba_##a##_##b()
struct {
void (*func)();
const char *func_name;
} func_arr[100];
int func_cnt = 0;
void add_test_func(void (*func)(), const char *str) {
func_arr[func_cnt].func = func;
func_arr[func_cnt].func_name = str;
func_cnt++;
return ;
}
int RUN_ALL_TESTS() {
// 遍歷所有的測試用例
// run each test case
for(int i = 0; i < func_cnt; i++) {
printf(GREEN("[ RUN ]") " %s\n", func_arr[i].func_name);
func_arr[i].func();
}
return 0;
}
#endif //SHAOFABOOK_KTEST_H