mirror of
https://github.com/lifegpc/c-utils.git
synced 2026-06-06 05:08:45 +08:00
Add GTest
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
build/
|
||||
.vscode/
|
||||
|
||||
@@ -6,6 +6,7 @@ option(ENABLE_CXX17 "Enable C++ 17" OFF)
|
||||
option(INSTALL_DEP_FILES "Install a file with dependences." OFF)
|
||||
option(ENABLE_SSL "Enable SSL" OFF)
|
||||
option(ENABLE_ZLIB "Use Zlib to uncompress http data." OFF)
|
||||
option(ENABLE_UTILS_TESTING "Test utils with GTest." OFF)
|
||||
|
||||
if (ENABLE_STANDALONE)
|
||||
project(utils)
|
||||
@@ -142,6 +143,8 @@ set(SOURCE_FILE_HEADERS
|
||||
file_reader.h
|
||||
urlparse.h
|
||||
http_client.h
|
||||
stack.h
|
||||
linked_stack.h
|
||||
)
|
||||
|
||||
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})
|
||||
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
1
googletest
Submodule
Submodule googletest added at 1d17ea141d
81
linked_stack.h
Normal file
81
linked_stack.h
Normal 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
130
stack.h
Normal 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
78
test/stack_test.cpp
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user