mirror of
https://github.com/decompals/wibo.git
synced 2025-10-16 07:05:11 +00:00
195 lines
6.2 KiB
C
195 lines
6.2 KiB
C
#include <windows.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#include "test_assert.h"
|
|
|
|
static uint64_t filetime_to_u64(const FILETIME *ft) {
|
|
ULARGE_INTEGER li;
|
|
li.LowPart = ft->dwLowDateTime;
|
|
li.HighPart = ft->dwHighDateTime;
|
|
return li.QuadPart;
|
|
}
|
|
|
|
static FILETIME u64_to_filetime(uint64_t value) {
|
|
ULARGE_INTEGER li;
|
|
li.QuadPart = value;
|
|
FILETIME ft;
|
|
ft.dwLowDateTime = li.LowPart;
|
|
ft.dwHighDateTime = li.HighPart;
|
|
return ft;
|
|
}
|
|
|
|
static uint64_t abs_u64_diff(uint64_t a, uint64_t b) {
|
|
return (a > b) ? (a - b) : (b - a);
|
|
}
|
|
|
|
static void test_systemtime_roundtrip(void) {
|
|
SYSTEMTIME st = {
|
|
.wYear = 2023,
|
|
.wMonth = 7,
|
|
.wDay = 15,
|
|
.wHour = 12,
|
|
.wMinute = 34,
|
|
.wSecond = 56,
|
|
.wMilliseconds = 789
|
|
};
|
|
|
|
FILETIME ft;
|
|
TEST_CHECK(SystemTimeToFileTime(&st, &ft));
|
|
|
|
SYSTEMTIME converted = {0};
|
|
TEST_CHECK(FileTimeToSystemTime(&ft, &converted));
|
|
|
|
TEST_CHECK_EQ(st.wYear, converted.wYear);
|
|
TEST_CHECK_EQ(st.wMonth, converted.wMonth);
|
|
TEST_CHECK_EQ(st.wDay, converted.wDay);
|
|
TEST_CHECK_EQ(st.wHour, converted.wHour);
|
|
TEST_CHECK_EQ(st.wMinute, converted.wMinute);
|
|
TEST_CHECK_EQ(st.wSecond, converted.wSecond);
|
|
TEST_CHECK_EQ(st.wMilliseconds, converted.wMilliseconds);
|
|
|
|
SetLastError(0);
|
|
SYSTEMTIME invalid = st;
|
|
invalid.wMonth = 13;
|
|
TEST_CHECK(!SystemTimeToFileTime(&invalid, &ft));
|
|
TEST_CHECK_EQ(ERROR_INVALID_PARAMETER, GetLastError());
|
|
}
|
|
|
|
static void test_filetime_known_timestamp(void) {
|
|
/* 2023-01-01 00:00:00 UTC */
|
|
const uint64_t expected_ticks = 133170048000000000ULL;
|
|
FILETIME ft = u64_to_filetime(expected_ticks);
|
|
|
|
SYSTEMTIME st = {0};
|
|
TEST_CHECK(FileTimeToSystemTime(&ft, &st));
|
|
TEST_CHECK_EQ(2023, st.wYear);
|
|
TEST_CHECK_EQ(1, st.wMonth);
|
|
TEST_CHECK_EQ(1, st.wDay);
|
|
TEST_CHECK_EQ(0, st.wHour);
|
|
TEST_CHECK_EQ(0, st.wMinute);
|
|
TEST_CHECK_EQ(0, st.wSecond);
|
|
TEST_CHECK_EQ(0, st.wMilliseconds);
|
|
|
|
FILETIME back;
|
|
TEST_CHECK(SystemTimeToFileTime(&st, &back));
|
|
TEST_CHECK_U64_EQ(expected_ticks, filetime_to_u64(&back));
|
|
}
|
|
|
|
static void test_getsystemtimeasfiletime(void) {
|
|
FILETIME from_api;
|
|
GetSystemTimeAsFileTime(&from_api);
|
|
|
|
SYSTEMTIME sys_now;
|
|
GetSystemTime(&sys_now);
|
|
FILETIME from_system;
|
|
TEST_CHECK(SystemTimeToFileTime(&sys_now, &from_system));
|
|
|
|
uint64_t delta = abs_u64_diff(filetime_to_u64(&from_api), filetime_to_u64(&from_system));
|
|
/* allow 1 second of skew between calls */
|
|
TEST_CHECK_MSG(delta < 10000000ULL, "GetSystemTimeAsFileTime skew too large: %llu", (unsigned long long)delta);
|
|
}
|
|
|
|
static void test_gettickcount_progresses(void) {
|
|
DWORD start = GetTickCount();
|
|
Sleep(60);
|
|
DWORD end = GetTickCount();
|
|
DWORD diff = end - start;
|
|
|
|
TEST_CHECK_MSG(diff >= 40, "GetTickCount diff too small: %lu", (unsigned long)diff);
|
|
TEST_CHECK_MSG(diff <= 5000, "GetTickCount diff too large: %lu", (unsigned long)diff);
|
|
}
|
|
|
|
static void test_setfiletime_roundtrip(void) {
|
|
char temp_path[MAX_PATH];
|
|
char temp_file[MAX_PATH];
|
|
|
|
DWORD path_len = GetTempPathA(sizeof(temp_path), temp_path);
|
|
TEST_CHECK(path_len > 0 && path_len < sizeof(temp_path));
|
|
|
|
UINT unique = GetTempFileNameA(temp_path, "TST", 0, temp_file);
|
|
TEST_CHECK(unique != 0);
|
|
|
|
HANDLE handle = CreateFileA(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
TEST_CHECK(handle != INVALID_HANDLE_VALUE);
|
|
|
|
FILETIME original_creation = {0}, original_access = {0}, original_write = {0};
|
|
TEST_CHECK(GetFileTime(handle, &original_creation, &original_access, &original_write));
|
|
|
|
SYSTEMTIME desired = {
|
|
.wYear = 2022,
|
|
.wMonth = 12,
|
|
.wDay = 31,
|
|
.wHour = 5,
|
|
.wMinute = 45,
|
|
.wSecond = 12,
|
|
.wMilliseconds = 123
|
|
};
|
|
FILETIME desired_ft;
|
|
TEST_CHECK(SystemTimeToFileTime(&desired, &desired_ft));
|
|
|
|
TEST_CHECK(SetFileTime(handle, NULL, NULL, &desired_ft));
|
|
|
|
FILETIME updated_creation = {0}, updated_access = {0}, updated_write = {0};
|
|
TEST_CHECK(GetFileTime(handle, &updated_creation, &updated_access, &updated_write));
|
|
TEST_CHECK_U64_EQ(filetime_to_u64(&desired_ft), filetime_to_u64(&updated_write));
|
|
|
|
FILETIME zero = {0, 0};
|
|
TEST_CHECK(SetFileTime(handle, NULL, &zero, NULL));
|
|
|
|
FILETIME final_creation = {0}, final_access = {0}, final_write = {0};
|
|
TEST_CHECK(GetFileTime(handle, &final_creation, &final_access, &final_write));
|
|
TEST_CHECK_U64_EQ(filetime_to_u64(&updated_access), filetime_to_u64(&final_access));
|
|
TEST_CHECK_U64_EQ(filetime_to_u64(&updated_write), filetime_to_u64(&final_write));
|
|
|
|
CloseHandle(handle);
|
|
DeleteFileA(temp_file);
|
|
}
|
|
|
|
static void test_local_filetime_conversions(void) {
|
|
/* Choose a time likely to be affected by DST in many zones */
|
|
SYSTEMTIME utc_time = {
|
|
.wYear = 2021,
|
|
.wMonth = 6,
|
|
.wDay = 15,
|
|
.wHour = 18,
|
|
.wMinute = 0,
|
|
.wSecond = 0,
|
|
.wMilliseconds = 0
|
|
};
|
|
|
|
FILETIME utc_ft;
|
|
TEST_CHECK(SystemTimeToFileTime(&utc_time, &utc_ft));
|
|
|
|
FILETIME local_ft;
|
|
TEST_CHECK(FileTimeToLocalFileTime(&utc_ft, &local_ft));
|
|
|
|
FILETIME roundtrip;
|
|
TEST_CHECK(LocalFileTimeToFileTime(&local_ft, &roundtrip));
|
|
TEST_CHECK_U64_EQ(filetime_to_u64(&utc_ft), filetime_to_u64(&roundtrip));
|
|
|
|
/* Local filetime should convert back to the original system time when interpreted locally */
|
|
SYSTEMTIME local_st = {0};
|
|
TEST_CHECK(FileTimeToSystemTime(&local_ft, &local_st));
|
|
SYSTEMTIME utc_from_roundtrip = {0};
|
|
TEST_CHECK(FileTimeToSystemTime(&roundtrip, &utc_from_roundtrip));
|
|
TEST_CHECK_EQ(utc_time.wYear, utc_from_roundtrip.wYear);
|
|
TEST_CHECK_EQ(utc_time.wMonth, utc_from_roundtrip.wMonth);
|
|
TEST_CHECK_EQ(utc_time.wDay, utc_from_roundtrip.wDay);
|
|
TEST_CHECK_EQ(utc_time.wHour, utc_from_roundtrip.wHour);
|
|
TEST_CHECK_EQ(utc_time.wMinute, utc_from_roundtrip.wMinute);
|
|
TEST_CHECK_EQ(utc_time.wSecond, utc_from_roundtrip.wSecond);
|
|
}
|
|
|
|
int main(void) {
|
|
test_systemtime_roundtrip();
|
|
test_filetime_known_timestamp();
|
|
test_getsystemtimeasfiletime();
|
|
test_gettickcount_progresses();
|
|
test_setfiletime_roundtrip();
|
|
test_local_filetime_conversions();
|
|
return 0;
|
|
}
|
|
|