TmeLib tests
It is now possible to use the internal vscode test tool with the cmake plugin to test timelib
This commit is contained in:
32
CMakeLists.txt
Normal file
32
CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||||
|
|
||||||
|
project(Network_Clock LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
set (VERSION_MAJOR 1)
|
||||||
|
set (VERSION_MINOR 0)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
|
||||||
|
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
|
||||||
|
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
|
||||||
|
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
|
||||||
|
set(PROJECT_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
# defines targets and sources
|
||||||
|
# add_subdirectory(src)
|
||||||
|
|
||||||
|
# contains an "external" library we will link to
|
||||||
|
# add_subdirectory(external)
|
||||||
|
|
||||||
|
# defines the executable
|
||||||
|
# add_subdirectory(tools)
|
||||||
|
|
||||||
|
# enable testing and define tests
|
||||||
|
enable_testing()
|
||||||
|
add_subdirectory(tests)
|
||||||
30
tests/CMakeLists.txt
Normal file
30
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Third Party
|
||||||
|
include_directories(${GTEST_INCLUDE_DIR})
|
||||||
|
|
||||||
|
link_directories(${GTEST_LIB_DIR})
|
||||||
|
|
||||||
|
find_package(GTest REQUIRED)
|
||||||
|
|
||||||
|
# tests
|
||||||
|
file(GLOB_RECURSE TEST_SOURCES "*.cpp")
|
||||||
|
add_executable(tests ${TEST_SOURCES})
|
||||||
|
target_link_libraries(tests ${LIBS})
|
||||||
|
|
||||||
|
target_compile_options(tests PRIVATE $<$<CONFIG:Debug>:
|
||||||
|
-Wall -Wextra -pedantic-errors -Wconversion -Wsign-conversion
|
||||||
|
>)
|
||||||
|
target_link_libraries(tests
|
||||||
|
PRIVATE
|
||||||
|
gtest
|
||||||
|
GTest::gtest_main
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(tests
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
${PROJECT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
include(GoogleTest)
|
||||||
|
include (CTest)
|
||||||
|
gtest_discover_tests(tests)
|
||||||
159
tests/testTime.cpp
Normal file
159
tests/testTime.cpp
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "time.hpp"
|
||||||
|
|
||||||
|
// TEST(TestCaseName, IndividualTestName)
|
||||||
|
TEST(timeLib, isDST1)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
|
||||||
|
// 2022-10-5 00:00:00 UTC DST on
|
||||||
|
t.Wday = Wed;
|
||||||
|
t.Day = 5;
|
||||||
|
t.Month = 10;
|
||||||
|
t.Year = 2022 - 1970;
|
||||||
|
t.Hour = 0;
|
||||||
|
|
||||||
|
EXPECT_EQ(1, IsDST(&t));
|
||||||
|
}
|
||||||
|
TEST(timeLib, isDST2)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
|
||||||
|
// 2022-10-29 59:59:59 UTC DST still on
|
||||||
|
t.Wday = Sun;
|
||||||
|
t.Day = 29;
|
||||||
|
t.Month = 10;
|
||||||
|
t.Hour = 23;
|
||||||
|
t.Minute = 59;
|
||||||
|
t.Second = 59;
|
||||||
|
t.Year = 2022 - 1970;
|
||||||
|
|
||||||
|
EXPECT_EQ(1 ,IsDST(&t));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(timeLib, isDST3)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
|
||||||
|
// 2022-10-30 00:00:00 UTC DST ends
|
||||||
|
t.Wday = Sun;
|
||||||
|
t.Day = 30;
|
||||||
|
t.Month = 10;
|
||||||
|
t.Hour = 0;
|
||||||
|
t.Year = 2022 - 1970;
|
||||||
|
|
||||||
|
EXPECT_EQ(0 ,IsDST(&t));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(timeLib, isDST4)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
|
||||||
|
// 2022-11-23 00:00:00 UTC DST off
|
||||||
|
t.Wday = Wed;
|
||||||
|
t.Day = 23;
|
||||||
|
t.Month = 11;
|
||||||
|
t.Hour = 0;
|
||||||
|
t.Year = 2022 - 1970;
|
||||||
|
|
||||||
|
EXPECT_EQ(0 ,IsDST(&t));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(timeLib, isDST5)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
|
||||||
|
// 2022-03-25 23:59:59 UTC DST off
|
||||||
|
t.Wday = Sun;
|
||||||
|
t.Day = 25;
|
||||||
|
t.Month = 3;
|
||||||
|
t.Hour = 23;
|
||||||
|
t.Minute = 59;
|
||||||
|
t.Second = 59;
|
||||||
|
t.Year = 2023 - 1970;
|
||||||
|
|
||||||
|
EXPECT_EQ(0 ,IsDST(&t));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(timeLib, isDST6)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
|
||||||
|
// 2022-03-26 00:00:00 UTC DST starts
|
||||||
|
t.Wday = Sun;
|
||||||
|
t.Day = 26;
|
||||||
|
t.Month = 3;
|
||||||
|
t.Hour = 0;
|
||||||
|
t.Year = 2023 - 1970;
|
||||||
|
|
||||||
|
EXPECT_EQ(1 ,IsDST(&t));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(timeLib, isDST7)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
|
||||||
|
// 2022-03-27 00:00:00 UTC DST on
|
||||||
|
t.Wday = Mon;
|
||||||
|
t.Day = 27;
|
||||||
|
t.Month = 3;
|
||||||
|
t.Hour = 0;
|
||||||
|
t.Year = 2023 - 1970;
|
||||||
|
|
||||||
|
EXPECT_EQ(1 ,IsDST(&t));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(TestCaseName, IndividualTestName)
|
||||||
|
TEST(timeLib, breakTime)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
|
||||||
|
// 1669233881 = Wed 2022-11-23 20:04:41 UTC
|
||||||
|
breakTime(1669233881, &t);
|
||||||
|
|
||||||
|
EXPECT_EQ(Wed, t.Wday);
|
||||||
|
EXPECT_EQ(23, t.Day);
|
||||||
|
EXPECT_EQ(11, t.Month);
|
||||||
|
EXPECT_EQ(20, t.Hour);
|
||||||
|
EXPECT_EQ(4, t.Minute);
|
||||||
|
EXPECT_EQ(41, t.Second);
|
||||||
|
EXPECT_EQ(2022, t.Year + 1970);
|
||||||
|
EXPECT_EQ(0, t.IsDST);
|
||||||
|
EXPECT_EQ(1669233881, t.unixtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(timeLib, makeTime)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
t.Wday = Wed;
|
||||||
|
t.Day = 23;
|
||||||
|
t.Month = 11;
|
||||||
|
t.Hour = 20;
|
||||||
|
t.Minute = 4;
|
||||||
|
t.Second = 41;
|
||||||
|
t.Year = 2022 - 1970;
|
||||||
|
t.IsDST = 0;
|
||||||
|
t.unixtime = 1669233881;
|
||||||
|
EXPECT_EQ(1669233881, makeTime(&t));
|
||||||
|
EXPECT_EQ(1669233881, t.unixtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(timeLib, toTimeZone)
|
||||||
|
{
|
||||||
|
ts t;
|
||||||
|
t.Day = 23;
|
||||||
|
t.Month = 11;
|
||||||
|
t.Year = 2022 - 1970;
|
||||||
|
t.Hour = 20;
|
||||||
|
t.Minute = 4;
|
||||||
|
t.Second = 41;
|
||||||
|
|
||||||
|
ts local;
|
||||||
|
toTimeZone(&t, &local, 1);
|
||||||
|
EXPECT_EQ(23, local.Day);
|
||||||
|
EXPECT_EQ(11, local.Month);
|
||||||
|
EXPECT_EQ(2022, local.Year + 1970);
|
||||||
|
EXPECT_EQ(21, local.Hour);
|
||||||
|
EXPECT_EQ(4, local.Minute);
|
||||||
|
EXPECT_EQ(41, local.Second);
|
||||||
|
}
|
||||||
165
tests/time.cpp
Normal file
165
tests/time.cpp
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
#include "time.hpp"
|
||||||
|
|
||||||
|
static const uint8_t monthDays[] =
|
||||||
|
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // API starts months from 1, this array starts from 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn uint8_t IsDST(ts)
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @param tm
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
uint8_t IsDST(ts *tm)
|
||||||
|
{
|
||||||
|
uint8_t nextSunday;
|
||||||
|
uint16_t y, m, d;
|
||||||
|
//number of days of each month
|
||||||
|
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
|
// January, february, and december are out.
|
||||||
|
if (tm->Month < 3 || tm->Month > 10)
|
||||||
|
{
|
||||||
|
tm->IsDST = 0;
|
||||||
|
return tm->IsDST;
|
||||||
|
}
|
||||||
|
// April to september are in
|
||||||
|
if (tm->Month > 3 && tm->Month < 10)
|
||||||
|
{
|
||||||
|
tm->IsDST = 1;
|
||||||
|
return tm->IsDST;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = tm->Month;
|
||||||
|
y = tm->Year + 1970;
|
||||||
|
days[1] -= (y % 4) || (!(y % 100) && (y % 400));
|
||||||
|
d = days[m - 1];
|
||||||
|
|
||||||
|
/* dow is in normal format*/
|
||||||
|
nextSunday = days[m-1] - ((d += m < 3 ? y-- : y - 2, 23*m/9 + d + 4 + y/4- y/100 + y/400)%7);
|
||||||
|
// Start: Last Sunday in March
|
||||||
|
if (tm->Month == 3)
|
||||||
|
{
|
||||||
|
tm->IsDST = tm->Day >= nextSunday ? (tm->Day == nextSunday ? (tm->Hour >= 0) : 1) : 0;
|
||||||
|
return tm->IsDST;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End: Last Sunday in October
|
||||||
|
tm->IsDST = tm->Day >= nextSunday ? (tm->Day == nextSunday ? (tm->Hour < 0) : 0) : 1;
|
||||||
|
return tm->IsDST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* functions to convert to and from system time */
|
||||||
|
/* These are for interfacing with time services and are not normally needed in a sketch */
|
||||||
|
|
||||||
|
void breakTime(uint32_t timeInput, ts *tm)
|
||||||
|
{
|
||||||
|
// break the given time_t into time components
|
||||||
|
// this is a more compact version of the C library localtime function
|
||||||
|
// note that year is offset from 1970 !!!
|
||||||
|
|
||||||
|
uint8_t year;
|
||||||
|
uint8_t month, monthLength;
|
||||||
|
unsigned long days;
|
||||||
|
|
||||||
|
tm->unixtime = timeInput;
|
||||||
|
tm->Second = timeInput % 60;
|
||||||
|
timeInput /= 60; // now it is minutes
|
||||||
|
tm->Minute = timeInput % 60;
|
||||||
|
timeInput /= 60; // now it is hours
|
||||||
|
tm->Hour = timeInput % 24;
|
||||||
|
timeInput /= 24; // now it is days
|
||||||
|
tm->Wday = ((timeInput + 4) % 7) + 1; // Sunday is day 1
|
||||||
|
|
||||||
|
year = 0;
|
||||||
|
days = 0;
|
||||||
|
while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= timeInput)
|
||||||
|
{
|
||||||
|
year++;
|
||||||
|
}
|
||||||
|
tm->Year = year; // year is offset from 1970
|
||||||
|
|
||||||
|
days -= LEAP_YEAR(year) ? 366 : 365;
|
||||||
|
timeInput -= days; // now it is days in this year, starting at 0
|
||||||
|
|
||||||
|
days = 0;
|
||||||
|
month = 0;
|
||||||
|
monthLength = 0;
|
||||||
|
for (month = 0; month < 12; month++)
|
||||||
|
{
|
||||||
|
if (month == 1)
|
||||||
|
{ // february
|
||||||
|
if (LEAP_YEAR(year))
|
||||||
|
{
|
||||||
|
monthLength = 29;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
monthLength = 28;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
monthLength = monthDays[month];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeInput >= monthLength)
|
||||||
|
{
|
||||||
|
timeInput -= monthLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tm->Month = month + 1; // jan is month 1
|
||||||
|
tm->Day = timeInput + 1; // day of month
|
||||||
|
|
||||||
|
IsDST(tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t makeTime(ts *tm)
|
||||||
|
{
|
||||||
|
// assemble time elements into time_t
|
||||||
|
// note year argument is offset from 1970 (see macros in time.h to convert to other formats)
|
||||||
|
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
|
||||||
|
|
||||||
|
int i;
|
||||||
|
uint32_t seconds;
|
||||||
|
|
||||||
|
// seconds from 1970 till 1 jan 00:00:00 of the given year
|
||||||
|
seconds = tm->Year*(NUMBEROFSECONDSPERDAY * 365);
|
||||||
|
for (i = 0; i < tm->Year; i++) {
|
||||||
|
if (LEAP_YEAR(i)) {
|
||||||
|
seconds += NUMBEROFSECONDSPERDAY; // add extra days for leap years
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add days for this year, months start from 1
|
||||||
|
for (i = 1; i < tm->Month; i++) {
|
||||||
|
if ( (i == 2) && LEAP_YEAR(tm->Year)) {
|
||||||
|
seconds += NUMBEROFSECONDSPERDAY * 29;
|
||||||
|
} else {
|
||||||
|
seconds += NUMBEROFSECONDSPERDAY * monthDays[i-1]; //monthDay array starts from 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seconds+= (tm->Day-1) * NUMBEROFSECONDSPERDAY;
|
||||||
|
seconds+= tm->Hour * NUMBEROFSECONDSPERHOUR;
|
||||||
|
seconds+= tm->Minute * NUMBEROFSECONDSPERMINUTE;
|
||||||
|
seconds+= tm->Second;
|
||||||
|
|
||||||
|
tm->unixtime = seconds;
|
||||||
|
return seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toTimeZone(ts *utc, ts* local, int8_t timeZone)
|
||||||
|
{
|
||||||
|
// convert UTC time to local time
|
||||||
|
// timeZone is in hours
|
||||||
|
// local is a pointer to a tm structure
|
||||||
|
// this function is not reentrant
|
||||||
|
|
||||||
|
uint32_t localTime = makeTime(utc) + timeZone * NUMBEROFSECONDSPERHOUR;
|
||||||
|
breakTime(localTime, local);
|
||||||
|
}
|
||||||
31
tests/time.hpp
Normal file
31
tests/time.hpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t Second; /* seconds */
|
||||||
|
uint8_t Minute; /* minutes */
|
||||||
|
uint8_t Hour; /* hours */
|
||||||
|
uint8_t Day; /* day of the month */
|
||||||
|
uint8_t Month; /* month */
|
||||||
|
int16_t Year; /* year ofset from 1970*/
|
||||||
|
uint8_t Wday; /* day of the week */
|
||||||
|
uint8_t Yday; /* day in the year */
|
||||||
|
uint8_t IsDST; /* daylight saving time */
|
||||||
|
|
||||||
|
uint32_t unixtime; /* seconds since 01.01.1970 00:00:00 UTC*/
|
||||||
|
} ts;
|
||||||
|
|
||||||
|
enum Wday_e {Sun = 1, Mon, Tue, Wed, Thu, Fri, Sat};
|
||||||
|
|
||||||
|
// leap year calculator expects year argument as years offset from 1970
|
||||||
|
#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) )
|
||||||
|
|
||||||
|
// to transform a number of seconds into a current time you need to do some maths
|
||||||
|
#define NUMBEROFSECONDSPERDAY 86400UL
|
||||||
|
#define NUMBEROFSECONDSPERHOUR 3600UL
|
||||||
|
#define NUMBEROFSECONDSPERMINUTE 60UL
|
||||||
|
|
||||||
|
uint8_t IsDST(ts* tm);
|
||||||
|
void breakTime(uint32_t timeInput, ts *tm);
|
||||||
|
uint32_t makeTime(ts *tm);
|
||||||
|
void toTimeZone(ts *utc, ts* local, int8_t timeZone);
|
||||||
Reference in New Issue
Block a user