class TestCase::Sys::Time {
use Sys::Time;
use Sys::Time::Timeval;
use Sys::Time::Timezone;
use Sys::Time::Timespec;
use Sys::Time::Constant as TIME;
use Sys::Time::Itimerval;
use Sys::Time::Utimbuf;
static method new_tm : int () {
my $tm = Sys::Time::Tm->new;
unless ($tm isa Sys::Time::Tm) {
return 0;
}
return 1;
}
static method time : long () {
my $time = Sys::Time->time;
return $time;
}
static method localtime : int () {
{
my $tm = Sys->localtime(0);
unless ($tm->tm_year + 1900 == 1970) {
return 0;
}
}
{
my $tm = Sys->localtime;
unless ($tm->tm_year + 1900 > 1970) {
return 0;
}
}
unless (Sys::OS->is_windows) {
my $tm = Sys->localtime(-(86_400 * 2));
unless ($tm->tm_year + 1900 == 1969) {
return 0;
}
}
# with TZ
{
# Get the current epoch time and fix it to avoid a 1-second deviation
my $now = Sys->time;
# 1. Test for JST (Japan Standard Time: UTC+9)
{
# Set C<TZ> environment variable to JST-9
Sys->set_env("TZ", "JST-9");
# Get localtime (JST) and gmtime (UTC) using the same epoch time
my $lt_jst = Sys->localtime($now);
my $gt = Sys->gmtime($now);
# Calculate the difference in seconds within a day
my $jst_seconds = $lt_jst->tm_hour * 3600 + $lt_jst->tm_min * 60 + $lt_jst->tm_sec;
my $gm_seconds = $gt->tm_hour * 3600 + $gt->tm_min * 60 + $gt->tm_sec;
my $diff = $jst_seconds - $gm_seconds;
# Adjust for cases where the date changes
if ($diff < 0) {
$diff += 86400;
}
# Check if the difference is exactly 9 hours (32400 seconds)
unless ($diff == 32400) {
return 0;
}
}
# 2. Test for UTC (UTC+0)
{
# Set C<TZ> environment variable to UTC0
Sys->set_env("TZ", "UTC0");
my $lt_utc = Sys->localtime($now);
my $gt = Sys->gmtime($now);
# Check if localtime matches gmtime under UTC0
unless ($lt_utc->tm_hour == $gt->tm_hour && $lt_utc->tm_min == $gt->tm_min && $lt_utc->tm_sec == $gt->tm_sec) {
return 0;
}
}
}
return 1;
}
static method localtime_value : Sys::Time::Tm ($time : long) {
my $time_info = Sys::Time->localtime(\$time);
return $time_info;
}
static method gmtime : int () {
{
my $tm = Sys->gmtime(0);
unless ($tm->tm_year + 1900 == 1970) {
return 0;
}
}
{
my $tm = Sys->gmtime;
unless ($tm->tm_year + 1900 > 1970) {
return 0;
}
}
unless (Sys::OS->is_windows) {
my $tm = Sys->gmtime(-(86_400 * 2));
unless ($tm->tm_year + 1900 == 1969) {
return 0;
}
}
return 1;
}
static method gmtime_value : Sys::Time::Tm ($time : long) {
my $time_info = Sys::Time->gmtime(\$time);
return $time_info;
}
static method gettimeofday : int () {
my $tv = Sys::Time::Timeval->new;
my $tz = Sys::Time::Timezone->new;
my $status = Sys::Time->gettimeofday($tv, $tz);
unless ($status == 0) {
return 0;
}
unless ($tv->tv_sec > 0) {
return 0;
}
return 1;
}
static method clock : int () {
my $tv = Sys::Time::Timeval->new;
my $tz = Sys::Time::Timezone->new;
my $cpu_time = Sys::Time->clock;
unless ($cpu_time >= 0) {
return 0;
}
return 1;
}
static method clock_gettime : int () {
my $tp = Sys::Time::Timespec->new;
my $status = Sys::Time->clock_gettime(TIME->CLOCK_REALTIME, $tp);
unless ($status >= 0) {
return 0;
}
unless ($tp->tv_sec >= 0) {
return 0;
}
return 1;
}
static method clock_getres : int () {
my $tp = Sys::Time::Timespec->new;
my $status = Sys::Time->clock_getres(TIME->CLOCK_REALTIME, $tp);
unless ($status >= 0) {
return 0;
}
unless ($tp->tv_sec >= 0) {
return 0;
}
return 1;
}
static method setitimer : int () {
my $new_tv = Sys::Time::Timeval->new(1, 1);
my $new_value = Sys::Time::Itimerval->new;
$new_value->set_it_interval($new_tv);
my $old_value = Sys::Time::Itimerval->new;
my $status = Sys::Time->setitimer(TIME->ITIMER_REAL, $new_value, $old_value);
unless ($status == 0) {
return 0;
}
return 1;
}
static method getitimer : int () {
my $curr_value = Sys::Time::Itimerval->new;
my $status = Sys::Time->getitimer(TIME->ITIMER_REAL, $curr_value);
unless ($status == 0) {
return 0;
}
return 1;
}
static method times : int () {
my $buffer = Sys::Time::Tms->new;
my $tick = Sys::Time->times($buffer);
warn $tick;
unless ($tick >= 0) {
return 0;
}
warn $buffer->tms_utime;
unless ($buffer->tms_utime > 0) {
return 0;
}
warn $buffer->tms_stime;
unless ($buffer->tms_stime >= 0) {
return 0;
}
warn $buffer->tms_cutime;
unless ($buffer->tms_cutime >= 0) {
return 0;
}
warn $buffer->tms_cstime;
unless ($buffer->tms_cstime >= 0) {
return 0;
}
# The fields of the Sys::Time::Tms class
{
$buffer->set_tms_utime(0);
$buffer->set_tms_stime(0);
$buffer->set_tms_cutime(0);
$buffer->set_tms_cstime(0);
}
return 1;
}
static method clock_nanosleep : int () {
my $start = Sys::Time->time;
my $request = Sys::Time::Timespec->new;
$request->set_tv_sec(1);
$request->set_tv_nsec(100_000_000);
my $remain = Sys::Time::Timespec->new;
my $status = Sys::Time->clock_nanosleep(TIME->CLOCK_REALTIME, 0, $request, $remain);
unless ($status == 0) {
return 0;
}
unless (Sys::Time->time - $start >= 1) {
return 0;
}
return 1;
}
static method nanosleep : int () {
my $start = Sys::Time->time;
my $ts = Sys::Time::Timespec->new(1, 100_000_000);
my $status = Sys::Time->nanosleep($ts, undef);
unless ($status == 0) {
return 0;
}
unless (Sys::Time->time - $start >= 1) {
return 0;
}
return 1;
}
static method utime : int ($test_dir : string) {
my $file = "$test_dir/ftest/utime.txt";
my $utimbuf = Sys::Time::Utimbuf->new;
my $time = Sys::Time->time;
my $actime = $utimbuf->set_actime($time);
my $modtime = $utimbuf->set_modtime($time);
my $status = Sys::Time->utime($file, $utimbuf);
unless ($status == 0) {
return 0;
}
return 1;
}
static method utimes : int ($test_dir : string) {
if (Sys::OS->is_windows) {
eval { Sys::Time->utimes(undef, undef); }
unless ($@ && eval_error_id is_error Error::NotSupported) {
return 0;
}
}
else {
my $file = "$test_dir/ftest/utime.txt";
my $times0 = Sys::Time::Timeval->new;
Sys::Time->gettimeofday($times0, undef);
my $times1 = Sys::Time::Timeval->new;
Sys::Time->gettimeofday($times1, undef);
my $times = [$times0, $times1];
my $status = Sys::Time->utimes($file, $times);
unless ($status == 0) {
return 0;
}
}
return 1;
}
static method timespec : int () {
# new
{
# check
{
# Valid values
eval { Sys::Time::Timespec->new(100L, 500L); };
if ($@) { return 0; }
# Invalid tv_nsec (too small)
eval { Sys::Time::Timespec->new(100L, -1L); };
unless ($@) { return 0; }
# Invalid tv_nsec (too large)
eval { Sys::Time::Timespec->new(100L, 1_000_000_000L); };
unless ($@) { return 0; }
}
}
# clone
{
# 1. Basic clone test
{
my $ts = Sys::Time::Timespec->new;
$ts->set_tv_sec(123456789L);
$ts->set_tv_nsec(987654321L);
# Perform clone
my $ts_clone = $ts->clone;
# Check if field values are identical
unless ($ts_clone->tv_sec == $ts->tv_sec) {
return 0;
}
unless ($ts_clone->tv_nsec == $ts->tv_nsec) {
return 0;
}
# Check if it's a different object (not the same memory address)
# In SPVM, comparing objects with == checks identity
if ($ts_clone == $ts) {
return 0;
}
}
# 2. Independence test (Modifying original should not affect clone)
{
my $ts = Sys::Time::Timespec->new;
$ts->set_tv_sec(100L);
my $ts_clone = $ts->clone;
# Modify original
$ts->set_tv_sec(200L);
# The clone's value must remain unchanged
unless ($ts_clone->tv_sec == 100L) {
return 0;
}
}
}
# check
{
# Valid values
eval { Sys::Time::Timespec->check(100L, 500L); };
if ($@) { return 0; }
# Invalid tv_nsec (too small)
eval { Sys::Time::Timespec->check(100L, -1L); };
unless ($@) { return 0; }
# Invalid tv_nsec (too large)
eval { Sys::Time::Timespec->check(100L, 1_000_000_000L); };
unless ($@) { return 0; }
}
return 1;
}
static method timeval : int () {
# new
{
# Valid object creation
{
my $tv = Sys::Time::Timeval->new(123456789L, 999999L);
unless ($tv->tv_sec == 123456789L) { return 0; }
unless ($tv->tv_usec == 999999L) { return 0; }
}
# Exception on invalid arguments (verify it calls check internally)
{
eval { Sys::Time::Timeval->new(0L, -1L); };
unless ($@) { return 0; }
eval { Sys::Time::Timeval->new(0L, 1_000_000L); };
unless ($@) { return 0; }
}
# Default values
{
my $tv = Sys::Time::Timeval->new;
unless ($tv->tv_sec == 0L && $tv->tv_usec == 0L) { return 0; }
}
}
# clone
{
# 1. Basic clone test
{
my $tv = Sys::Time::Timeval->new;
$tv->set_tv_sec(123456789L);
$tv->set_tv_usec(987654L); # Microseconds
# Perform clone
my $tv_clone = $tv->clone;
# Check if field values are identical
unless ($tv_clone->tv_sec == $tv->tv_sec) {
return 0;
}
unless ($tv_clone->tv_usec == $tv->tv_usec) {
return 0;
}
# Check if it's a different object (not the same memory address)
if ($tv_clone == $tv) {
return 0;
}
}
# 2. Independence test (Modifying original should not affect clone)
{
my $tv = Sys::Time::Timeval->new;
$tv->set_tv_sec(100L);
my $tv_clone = $tv->clone;
# Modify original
$tv->set_tv_sec(200L);
# The clone's value must remain unchanged
unless ($tv_clone->tv_sec == 100L) {
return 0;
}
}
}
# check
{
# Valid values
{
eval { Sys::Time::Timeval->check(100L, 500L); };
if ($@) { return 0; }
}
# Invalid tv_usec (too small)
{
eval { Sys::Time::Timeval->check(100L, -1L); };
unless ($@) { return 0; }
}
# Invalid tv_usec (too large)
{
eval { Sys::Time::Timeval->check(100L, 1_000_000L); };
unless ($@) { return 0; }
}
}
return 1;
}
static method tzset : int () {
{
Sys::Time->tzset;
}
return 1;
}
}