test: add more test

This commit is contained in:
Zxilly 2025-09-12 11:39:45 +08:00
parent 51bcf099f4
commit 9d94b7957c
5 changed files with 308 additions and 0 deletions

View File

@ -213,8 +213,12 @@ if (UA2F_BUILD_TESTS)
ua2f_test
test/util_test.cc
test/cache_test.cc
test/statistics_test.cc
test/cli_test.cc
src/util.c
src/cache.c
src/statistics.c
src/cli.c
)
target_link_libraries(
ua2f_test

View File

@ -46,4 +46,73 @@ TEST_F(CacheTest, CacheDoesNotContainNonexistentEntry) {
addr_port nonexistent_addr{};
nonexistent_addr.addr.ip4 = 54321;
EXPECT_FALSE(cache_contains(nonexistent_addr));
}
TEST_F(CacheTest, MultipleDifferentAddresses) {
addr_port addr1{}, addr2{}, addr3{};
addr1.addr.ip4 = 1001;
addr1.port = 80;
addr2.addr.ip4 = 1002;
addr2.port = 443;
addr3.addr.ip4 = 1003;
addr3.port = 8080;
// Initially none should be in cache
EXPECT_FALSE(cache_contains(addr1));
EXPECT_FALSE(cache_contains(addr2));
EXPECT_FALSE(cache_contains(addr3));
// Add all to cache
cache_add(addr1);
cache_add(addr2);
cache_add(addr3);
// All should now be in cache
EXPECT_TRUE(cache_contains(addr1));
EXPECT_TRUE(cache_contains(addr2));
EXPECT_TRUE(cache_contains(addr3));
}
TEST_F(CacheTest, SameAddressDifferentPorts) {
addr_port addr1{}, addr2{};
addr1.addr.ip4 = 2000;
addr1.port = 80;
addr2.addr.ip4 = 2000; // Same IP
addr2.port = 443; // Different port
cache_add(addr1);
EXPECT_TRUE(cache_contains(addr1));
EXPECT_FALSE(cache_contains(addr2)); // Different port should not match
}
TEST_F(CacheTest, CacheRefreshOnAccess) {
addr_port addr{};
addr.addr.ip4 = 3000;
addr.port = 80;
cache_add(addr);
EXPECT_TRUE(cache_contains(addr));
// Access the cache multiple times - this should refresh the last_time
for (int i = 0; i < 5; i++) {
EXPECT_TRUE(cache_contains(addr));
sleep(1); // Small delay
}
// Should still be in cache after multiple accesses
EXPECT_TRUE(cache_contains(addr));
}
TEST_F(CacheTest, DuplicateAddDoesNotCrash) {
addr_port addr{};
addr.addr.ip4 = 4000;
addr.port = 80;
// Add the same address multiple times
cache_add(addr);
cache_add(addr);
cache_add(addr);
EXPECT_TRUE(cache_contains(addr));
}

64
test/cli_test.cc Normal file
View File

@ -0,0 +1,64 @@
#include <gtest/gtest.h>
#include <cstdlib>
#include <unistd.h>
extern "C" {
#include <cli.h>
}
class CLITest : public ::testing::Test {
protected:
void SetUp() override {
// Capture original uid for cleanup
original_uid = geteuid();
}
void TearDown() override {
// Reset to original state if needed
}
uid_t original_uid;
};
TEST_F(CLITest, TryPrintInfoNoArgs) {
char *argv[] = {(char*)"ua2f"};
int argc = 1;
// Should not crash with no arguments
EXPECT_NO_THROW(try_print_info(argc, argv));
}
TEST_F(CLITest, TryPrintInfoVersion) {
char *argv[] = {(char*)"ua2f", (char*)"--version"};
int argc = 2;
// --version should exit, but we can't easily test exit behavior in unit tests
// Just make sure the function exists and can be called without segfault
EXPECT_EXIT(try_print_info(argc, argv), ::testing::ExitedWithCode(EXIT_SUCCESS), ".*");
}
TEST_F(CLITest, TryPrintInfoHelp) {
char *argv[] = {(char*)"ua2f", (char*)"--help"};
int argc = 2;
// --help should exit with success
EXPECT_EXIT(try_print_info(argc, argv), ::testing::ExitedWithCode(EXIT_SUCCESS), ".*");
}
TEST_F(CLITest, TryPrintInfoUnknownOption) {
char *argv[] = {(char*)"ua2f", (char*)"--unknown"};
int argc = 2;
// Unknown option should exit with failure
EXPECT_EXIT(try_print_info(argc, argv), ::testing::ExitedWithCode(EXIT_FAILURE), ".*");
}
TEST_F(CLITest, RequireRootWhenRoot) {
if (geteuid() == 0) {
// If we're actually root, this should not exit
EXPECT_NO_THROW(require_root());
} else {
// If we're not root, this should exit with failure
EXPECT_EXIT(require_root(), ::testing::ExitedWithCode(EXIT_FAILURE), ".*");
}
}

101
test/statistics_test.cc Normal file
View File

@ -0,0 +1,101 @@
#include <gtest/gtest.h>
#include <cstring>
extern "C" {
#include <statistics.h>
}
class StatisticsTest : public ::testing::Test {
protected:
void SetUp() override {
init_statistics();
}
};
TEST_F(StatisticsTest, InitializeStatistics) {
// Statistics should be initialized without error
EXPECT_NO_THROW(init_statistics());
}
TEST_F(StatisticsTest, CountUserAgentPacket) {
EXPECT_NO_THROW(count_user_agent_packet());
// Call multiple times to test counting
for (int i = 0; i < 5; i++) {
count_user_agent_packet();
}
}
TEST_F(StatisticsTest, CountTcpPacket) {
EXPECT_NO_THROW(count_tcp_packet());
// Call multiple times to test counting
for (int i = 0; i < 10; i++) {
count_tcp_packet();
}
}
TEST_F(StatisticsTest, CountHttpPacket) {
EXPECT_NO_THROW(count_http_packet());
// Call multiple times to test counting
for (int i = 0; i < 3; i++) {
count_http_packet();
}
}
TEST_F(StatisticsTest, CountIpv4Packet) {
EXPECT_NO_THROW(count_ipv4_packet());
// Call multiple times to test counting
for (int i = 0; i < 7; i++) {
count_ipv4_packet();
}
}
TEST_F(StatisticsTest, CountIpv6Packet) {
EXPECT_NO_THROW(count_ipv6_packet());
// Call multiple times to test counting
for (int i = 0; i < 4; i++) {
count_ipv6_packet();
}
}
TEST_F(StatisticsTest, TryPrintStatistics) {
// Should not crash when called
EXPECT_NO_THROW(try_print_statistics());
// Generate some statistics and try printing
for (int i = 0; i < 100; i++) {
count_user_agent_packet();
count_tcp_packet();
count_http_packet();
count_ipv4_packet();
}
EXPECT_NO_THROW(try_print_statistics());
}
// Test time string formatting function if accessible
extern "C" char *fill_time_string(const double sec);
TEST_F(StatisticsTest, TimeStringFormatting) {
char *result;
// Test seconds
result = fill_time_string(30.0);
EXPECT_TRUE(strstr(result, "seconds") != nullptr);
// Test minutes
result = fill_time_string(150.0);
EXPECT_TRUE(strstr(result, "minutes") != nullptr);
EXPECT_TRUE(strstr(result, "seconds") != nullptr);
// Test hours
result = fill_time_string(3700.0);
EXPECT_TRUE(strstr(result, "hours") != nullptr);
EXPECT_TRUE(strstr(result, "minutes") != nullptr);
EXPECT_TRUE(strstr(result, "seconds") != nullptr);
// Test days
result = fill_time_string(90000.0);
EXPECT_TRUE(strstr(result, "days") != nullptr);
EXPECT_TRUE(strstr(result, "hours") != nullptr);
EXPECT_TRUE(strstr(result, "minutes") != nullptr);
EXPECT_TRUE(strstr(result, "seconds") != nullptr);
}

View File

@ -84,4 +84,74 @@ TEST(HttpProtocolTest, RealWorldRequests) {
// Check that these cases return false
EXPECT_FALSE(is_http_protocol(invalidPayload, strlen(invalidPayload))) << "Invalid method passed";
}
TEST(HttpProtocolTest, AllHttpMethods) {
// Test all supported HTTP methods
EXPECT_TRUE(is_http_protocol("GET /", 5));
EXPECT_TRUE(is_http_protocol("POST /", 6));
EXPECT_TRUE(is_http_protocol("OPTIONS /", 9));
EXPECT_TRUE(is_http_protocol("HEAD /", 6));
EXPECT_TRUE(is_http_protocol("PUT /", 5));
EXPECT_TRUE(is_http_protocol("DELETE /", 8));
EXPECT_TRUE(is_http_protocol("TRACE /", 7));
EXPECT_TRUE(is_http_protocol("CONNECT /", 9));
}
TEST(HttpProtocolTest, EdgeCases) {
// Empty payload
EXPECT_FALSE(is_http_protocol("", 0));
// Too short for any method
EXPECT_FALSE(is_http_protocol("G", 1));
EXPECT_FALSE(is_http_protocol("GE", 2));
// Incomplete methods
EXPECT_FALSE(is_http_protocol("GE", 2));
EXPECT_FALSE(is_http_protocol("POS", 3));
// Case sensitivity
EXPECT_FALSE(is_http_protocol("get /", 5));
EXPECT_FALSE(is_http_protocol("Post /", 6));
// Non-HTTP protocols
EXPECT_FALSE(is_http_protocol("FTP /", 5));
EXPECT_FALSE(is_http_protocol("SSH /", 5));
EXPECT_FALSE(is_http_protocol("HTTPS /", 7));
}
TEST(MemNCaseMemTest, CaseInsensitiveSearch) {
const char *l = "HELLO WORLD";
size_t l_len = 11;
// Test case insensitive matching
EXPECT_EQ(memncasemem(l, l_len, "hello", 5), (void *)l);
EXPECT_EQ(memncasemem(l, l_len, "HELLO", 5), (void *)l);
EXPECT_EQ(memncasemem(l, l_len, "HeLLo", 5), (void *)l);
EXPECT_EQ(memncasemem(l, l_len, "world", 5), (void *)(l + 6));
EXPECT_EQ(memncasemem(l, l_len, "WORLD", 5), (void *)(l + 6));
EXPECT_EQ(memncasemem(l, l_len, "WoRLd", 5), (void *)(l + 6));
}
TEST(MemNCaseMemTest, NotFoundCases) {
const char *l = "Hello World";
size_t l_len = 11;
// Search for non-existent strings
EXPECT_EQ(memncasemem(l, l_len, "xyz", 3), nullptr);
EXPECT_EQ(memncasemem(l, l_len, "foo", 3), nullptr);
EXPECT_EQ(memncasemem(l, l_len, "hello world!", 12), nullptr); // Longer than haystack
}
TEST(MemNCaseMemTest, MultipleOccurrences) {
const char *l = "hello hello hello";
size_t l_len = 17;
// Should find the first occurrence
void *result = memncasemem(l, l_len, "hello", 5);
EXPECT_EQ(result, (void *)l);
// Search from different starting positions
void *result2 = memncasemem(l + 6, l_len - 6, "hello", 5);
EXPECT_EQ(result2, (void *)(l + 6));
}