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/
|
build/
|
||||||
|
.vscode/
|
||||||
|
|||||||
@@ -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
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