Add GTest

This commit is contained in:
2024-06-20 10:09:13 +08:00
parent 33106b9fbd
commit e2e39f6163
6 changed files with 305 additions and 0 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
build/ build/
.vscode/

View File

@@ -6,6 +6,7 @@ option(ENABLE_CXX17 "Enable C++ 17" OFF)
option(INSTALL_DEP_FILES "Install a file with dependences." OFF) option(INSTALL_DEP_FILES "Install a file with dependences." OFF)
option(ENABLE_SSL "Enable SSL" OFF) option(ENABLE_SSL "Enable SSL" OFF)
option(ENABLE_ZLIB "Use Zlib to uncompress http data." OFF) option(ENABLE_ZLIB "Use Zlib to uncompress http data." OFF)
option(ENABLE_UTILS_TESTING "Test utils with GTest." OFF)
if (ENABLE_STANDALONE) if (ENABLE_STANDALONE)
project(utils) project(utils)
@@ -142,6 +143,8 @@ set(SOURCE_FILE_HEADERS
file_reader.h file_reader.h
urlparse.h urlparse.h
http_client.h http_client.h
stack.h
linked_stack.h
) )
if (NOT HAVE_STRPTIME) if (NOT HAVE_STRPTIME)
@@ -185,3 +188,14 @@ if (INSTALL_DEP_FILES)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/utils_dep.txt" DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/utils_dep.txt" DESTINATION ${CMAKE_INSTALL_PREFIX})
endif() endif()
endif() endif()
if (ENABLE_UTILS_TESTING)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(googletest)
enable_testing()
add_executable(stack_test test/stack_test.cpp)
target_link_libraries(stack_test GTest::gtest_main utils)
include(GoogleTest)
gtest_discover_tests(stack_test)
endif()

1
googletest Submodule

Submodule googletest added at 1d17ea141d

81
linked_stack.h Normal file
View File

@@ -0,0 +1,81 @@
#ifndef _UTIL_LINKED_STACK_H
#define _UTIL_LINKED_STACK_H
#include <functional>
#include <stddef.h>
#include <malloc.h>
template <typename T>
struct LinkedStack {
T d;
struct LinkedStack* next;
};
template <typename T>
size_t linked_stack_length(struct LinkedStack<T>* top) {
if (!top) return 0;
struct LinkedStack<T>* now = top;
size_t i = 1;
while (now->next) {
now = now->next;
i += 1;
}
return i;
}
template <typename T>
void linked_stack_clear(struct LinkedStack<T>*& top, std::function<void(T)> free_func = std::function<void(T)>()) {
if (!top) return;
struct LinkedStack<T>* tmp;
do {
if (free_func) {
free_func(top->d);
}
tmp = top;
top = top->next;
free(tmp);
} while (top);
}
template <typename T, class F>
void linked_stack_clear(struct LinkedStack<T>*& top, F free_func) {
linked_stack_clear(top, std::function<void(T)>(free_func));
}
template <typename T>
bool linked_stack_push(struct LinkedStack<T>*& top, T ele) {
struct LinkedStack<T>* t = (struct LinkedStack<T>*)malloc(sizeof(struct LinkedStack<T>));
if (!t) {
return false;
}
t->d = ele;
t->next = top;
top = t;
return true;
}
template <typename T>
bool linked_stack_pop(struct LinkedStack<T>*& top, T& ele) {
if (!top) return false;
ele = top->d;
struct LinkedStack<T>* tmp = top;
top = top->next;
free(tmp);
return true;
}
template <typename T, typename ... Args>
void linked_stack_iter(struct LinkedStack<T>* top, std::function<void(T, Args...)> callback, Args... args) {
if (!top || !callback) return;
struct LinkedStack<T>* now = top;
do {
callback(now->d, args...);
now = now->next;
} while (now);
}
template <typename T, class F, typename ... Args>
void linked_stack_iter(struct LinkedStack<T>* top, F callback, Args... args) {
linked_stack_iter(top, std::function<void(T, Args...)>(callback), args...);
}
#endif

130
stack.h Normal file
View File

@@ -0,0 +1,130 @@
#ifndef _UTIL_STACK_H
#define _UTIL_STACK_H
#include <functional>
#include <stddef.h>
#include <malloc.h>
template <typename T>
struct Stack {
T* base;
T* top;
size_t capacity;
size_t inc_step;
};
/**
* @brief Initailize stack and allocate memory for it.
* @param stack Stack
* @param capacity Default capacity
*/
template <typename T>
bool init_stack(struct Stack<T>& stack, size_t capacity = 1, size_t inc_step = 1) {
if (inc_step < 1) inc_step = 1;
if (capacity < 1) capacity = 1;
stack.base = (T*)malloc(capacity * sizeof(T));
if (!stack.base) return false;
stack.top = stack.base;
stack.capacity = capacity;
stack.inc_step = inc_step;
return true;
}
template <typename T>
void free_stack(struct Stack<T>& stack, std::function<void(T)> free_func = std::function<void(T)>()) {
if (!stack.base) return;
if (free_func) {
stack_iter(stack, free_func);
}
free(stack.base);
stack.base = nullptr;
stack.top = nullptr;
stack.capacity = 0;
stack.inc_step = 0;
}
template <typename T, class F>
inline void free_stack(struct Stack<T>& stack, F free_func) {
free_stack(stack, std::function<void(T)>(free_func));
}
template <typename T>
void clear_stack(struct Stack<T>& stack, std::function<void(T)> free_func = std::function<void(T)>()) {
if (!stack.base) return;
if (free_func) {
stack_iter(stack, free_func);
}
stack.top = stack.base;
}
template <typename T, class F>
inline void clear_stack(struct Stack<T>& stack, F free_func) {
clear_stack(stack, std::function<void(T)>(free_func));
}
template <typename T>
bool stack_is_empty(struct Stack<T>& stack) {
if (!stack.base) return true;
return stack.base == stack.top;
}
template <typename T>
size_t stack_length(struct Stack<T>& stack) {
if (!stack.base) return 0;
return stack.top - stack.base;
}
template <typename T>
bool stack_get_top(struct Stack<T>& stack, T& ele) {
if (!stack.base) return false;
if (stack.base == stack.top) return false;
ele = *(stack.top - 1);
return true;
}
template <typename T>
bool stack_push(struct Stack<T>& stack, T ele) {
if (!stack.base) return false;
if (stack.top - stack.base >= stack.capacity) {
T* obase = stack.base;
stack.base = (T*)realloc(stack.base, (stack.capacity + stack.inc_step) * sizeof(T));
if (!stack.base) {
/// Free original buffer
free(obase);
stack.top = nullptr;
stack.capacity = 0;
stack.inc_step = 0;
return false;
}
stack.top = stack.base + stack.capacity;
stack.capacity += stack.inc_step;
}
*(stack.top++) = ele;
return true;
}
template <typename T>
bool stack_pop(struct Stack<T>& stack, T& ele) {
if (!stack.base) return false;
if (stack.top == stack.base) return false;
ele = *(--stack.top);
return true;
}
template <typename T, typename ... Args>
void stack_iter(struct Stack<T>& stack, std::function<void(T, Args...)> callback, Args... args) {
if (!stack.base || !callback) return;
if (stack.top == stack.base) return;
T* now = stack.top;
while (now > stack.base) {
now -= 1;
callback(*now, args...);
}
}
template <typename T, class F, typename ... Args>
inline void stack_iter(struct Stack<T>& stack, F callback, Args... args) {
stack_iter(stack, std::function<void(T, Args...)>(callback), args...);
}
#endif

78
test/stack_test.cpp Normal file
View File

@@ -0,0 +1,78 @@
#include "gtest/gtest.h"
#include "stack.h"
#include "linked_stack.h"
#include <string>
TEST(Stack_Test, Stack1) {
struct Stack<int> stack;
ASSERT_EQ(init_stack(stack, 10), true) << "Can not initiailze stack.";
ASSERT_EQ(stack_is_empty(stack), true) << "Stack is not empty.";
ASSERT_EQ(stack_push(stack, 3), true) << "Failed to push elements to stack";
int top;
ASSERT_EQ(stack_get_top(stack, top), true) << "Failed to get top element.";
ASSERT_EQ(top, 3) << "Value is not expeced.";
ASSERT_EQ(stack_length(stack), 1) << "Length should be 1";
ASSERT_EQ(stack_is_empty(stack), false) << "Stack is empty.";
ASSERT_EQ(stack_push(stack, 5), true) << "Failed to push to stack.";
ASSERT_EQ(stack_length(stack), 2) << "Length should be 2";
std::string text;
stack_iter(stack, [&text](int ele) {
if (!text.empty()) {
text += ",";
}
text += std::to_string(ele);
});
ASSERT_EQ(text, "5,3") << "Failed to join.";
ASSERT_EQ(stack_pop(stack, top), true) << "Failed to pop.";
ASSERT_EQ(top, 5) << "Poped value not equal.";
ASSERT_EQ(stack_length(stack), 1) << "Length should be 1";
free_stack(stack);
}
TEST(Stack_Test, Stack2) {
struct Stack<int> stack;
ASSERT_EQ(init_stack(stack, 1, 2), true) << "Can not initiailze stack.";
ASSERT_EQ(stack_push(stack, 3), true) << "Failed to push elements to stack";
ASSERT_EQ(stack_push(stack, 4), true) << "Failed to push elements to stack";
ASSERT_EQ(stack.capacity, 3) << "Capacity not expected";
ASSERT_EQ(stack_push(stack, 5), true) << "Failed to push elements to stack";
ASSERT_EQ(stack_push(stack, 6), true) << "Failed to push elements to stack";
ASSERT_EQ(stack.capacity, 5) << "Capacity not expected";
std::string text;
stack_iter(stack, [&text](int ele) {
if (!text.empty()) {
text += ",";
}
text += std::to_string(ele);
});
ASSERT_EQ(text, "6,5,4,3") << "Failed to join.";
ASSERT_EQ(stack_length(stack), 4) << "Length should be 4";
free_stack(stack);
}
TEST(Stack_Test, LinkedStack1) {
struct LinkedStack<int>* top = nullptr;
EXPECT_EQ(linked_stack_push(top, 3), true);
EXPECT_EQ(top->next, nullptr);
EXPECT_EQ(top->d, 3);
EXPECT_EQ(linked_stack_push(top, 4), true);
EXPECT_EQ(top->d, 4);
EXPECT_EQ(top->next->d, 3);
int e;
EXPECT_EQ(linked_stack_pop(top, e), true);
EXPECT_EQ(e, 4);
EXPECT_EQ(linked_stack_push(top, 8), true);
EXPECT_EQ(linked_stack_push(top, 9), true);
EXPECT_EQ(linked_stack_push(top, 10), true);
std::string text;
linked_stack_iter(top, [&text](int ele) {
if (!text.empty()) {
text += ",";
}
text += std::to_string(ele);
});
EXPECT_EQ(text, "10,9,8,3");
EXPECT_EQ(linked_stack_length(top), 4);
linked_stack_clear(top);
EXPECT_EQ(top, nullptr);
}