blob: 93acc3f25e449888f23c37bf1b6a170dfda6f35b [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <librtc.h>
#include <stdint.h>
#include <string.h>
#include <zxtest/zxtest.h>
#include "fuchsia/hardware/rtc/c/fidl.h"
#include "zircon/errors.h"
static fuchsia_hardware_rtc_Time make_rtc(uint16_t year, uint8_t month, uint8_t day, uint8_t hours,
uint8_t minutes, uint8_t seconds) {
return fuchsia_hardware_rtc_Time{seconds, minutes, hours, day, month, year};
}
enum months {
JANUARY = 1,
FEBRUARY = 2,
MARCH = 3,
APRIL = 4,
MAY = 5,
JUNE = 6,
JULY = 7,
AUGUST = 8,
SEPTEMBER = 9,
OCTOBER = 10,
NOVEMBER = 11,
DECEMBER = 12
};
TEST(RTCLibTest, BCD) {
EXPECT_EQ(0x00, to_bcd(0));
EXPECT_EQ(0x16, to_bcd(16));
EXPECT_EQ(0x99, to_bcd(99));
EXPECT_EQ(0, from_bcd(0x00));
EXPECT_EQ(16, from_bcd(0x16));
EXPECT_EQ(99, from_bcd(0x99));
}
TEST(RTCLibTest, RTCYearsValid) {
auto t0 = make_rtc(1999, 1, 1, 0, 0, 0);
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.year = 2000;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.year = 2100;
EXPECT_TRUE(rtc_is_invalid(&t0));
}
TEST(RTCLibTest, RTCMonthsValid) {
auto t0 = make_rtc(2001, 7, 1, 0, 0, 0);
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.month = 13;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = 0;
EXPECT_TRUE(rtc_is_invalid(&t0));
}
TEST(RTCLibTest, RTCDaysValid) {
auto t0 = make_rtc(2001, 1, 1, 0, 0, 0);
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.month = JANUARY;
t0.day = 0;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.day = 31;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 32;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = FEBRUARY;
t0.day = 28; // not a leap year
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 29; // not a leap year
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = MARCH;
t0.day = 31;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.month = MARCH;
t0.day = 32;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = APRIL;
t0.day = 30;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 31;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = MAY;
t0.day = 31;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 32;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = JUNE;
t0.day = 30;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 31;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = JULY;
t0.day = 31;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 32;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = AUGUST;
t0.day = 31;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 32;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = SEPTEMBER;
t0.day = 30;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 31;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = OCTOBER;
t0.day = 31;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 32;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = NOVEMBER;
t0.day = 30;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 31;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.month = DECEMBER;
t0.day = 31;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 32;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.day = 99;
EXPECT_TRUE(rtc_is_invalid(&t0));
}
TEST(RTCLibTest, HoursMinutesSecondsValid) {
auto t0 = make_rtc(2001, 1, 1, 0, 0, 0);
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 1;
t0.hours = 0;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.hours = 23;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.hours = 24;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.hours = 25;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.hours = 1;
t0.minutes = 0;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.minutes = 59;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.minutes = 60;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.minutes = 61;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.minutes = 1;
t0.seconds = 0;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.seconds = 59;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.seconds = 60;
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.seconds = 61;
EXPECT_TRUE(rtc_is_invalid(&t0));
}
TEST(RTCLibTest, LeapYears) {
auto t0 = make_rtc(2000, 2, 28, 0, 0, 0); // Is a leap year
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.day = 29;
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.year = 2001; // NOT a leap year
EXPECT_TRUE(rtc_is_invalid(&t0));
t0.year = 2004; // A leap year
EXPECT_FALSE(rtc_is_invalid(&t0));
t0.year = 2020; // A leap year
EXPECT_FALSE(rtc_is_invalid(&t0));
// Sadly 2100 is out of range to test as a non-leap year
}
TEST(RTCLibTest, SecondsSinceEpoch) {
auto t0 = make_rtc(2018, 8, 4, 1, 19, 1);
EXPECT_EQ(1533345541, seconds_since_epoch(&t0));
auto t1 = make_rtc(2000, 1, 1, 0, 0, 0);
EXPECT_EQ(946684800, seconds_since_epoch(&t1));
}
static fuchsia_hardware_rtc_Time default_rtc;
static bool rtc_equal(fuchsia_hardware_rtc_Time* t0, fuchsia_hardware_rtc_Time* t1) {
return (t0->year == t1->year && t0->month == t1->month && t0->day == t1->day &&
t0->hours == t1->hours && t0->minutes == t1->minutes && t0->seconds == t1->seconds);
}
static void rtc_clear() { memset((void*)&default_rtc, 0, sizeof(default_rtc)); }
static zx_status_t rtc_get(void* ctx, fuchsia_hardware_rtc_Time* rtc) {
memcpy((void*)rtc, (void*)&default_rtc, sizeof(*rtc));
return ZX_OK;
}
static zx_status_t rtc_set(void*, const fuchsia_hardware_rtc_Time* rtc) {
memcpy((void*)&default_rtc, (void*)rtc, sizeof(*rtc));
return ZX_OK;
}
static zx_status_t rtc_bad_get(void* ctx, fuchsia_hardware_rtc_Time* rtc) {
return ZX_ERR_ACCESS_DENIED;
}
static zx_status_t rtc_bad_set(void*, const fuchsia_hardware_rtc_Time* rtc) {
return ZX_ERR_ACCESS_DENIED;
}
static void backstop_clear() { unsetenv("clock.backstop"); }
TEST(RTCLibTest, rtc_backstop_seconds) {
backstop_clear();
EXPECT_EQ(0, rtc_backstop_seconds());
setenv("clock.backstop", "invalid", 1);
EXPECT_EQ(0, rtc_backstop_seconds());
setenv("clock.backstop", "1563584646", 1);
EXPECT_EQ(1563584646, rtc_backstop_seconds());
}
TEST(RTCLibTest, SanitizeRTCPreservesGoodValue) {
backstop_clear();
auto t0 = make_rtc(2018, 8, 4, 1, 19, 1); // good value
EXPECT_FALSE(rtc_is_invalid(&t0));
rtc_clear();
sanitize_rtc(NULL, &t0, rtc_get, rtc_set);
EXPECT_TRUE(rtc_equal(&t0, &default_rtc));
}
TEST(RTCLibTest, SanitizeRTCCorrectsBadValue) {
backstop_clear();
auto t0 = make_rtc(2018, 8, 4, 99, 19, 1); // bad value
EXPECT_TRUE(rtc_is_invalid(&t0));
rtc_clear();
sanitize_rtc(NULL, &t0, rtc_get, rtc_set);
// don't actually care what value it's set to
EXPECT_FALSE(rtc_is_invalid(&t0));
EXPECT_FALSE(rtc_is_invalid(&default_rtc));
}
TEST(RTCLibTest, SanitizeRTCCheecksGetError) {
auto t0 = make_rtc(2018, 8, 4, 99, 19, 1);
EXPECT_TRUE(rtc_is_invalid(&t0));
rtc_clear();
sanitize_rtc(NULL, &t0, rtc_bad_get, rtc_set);
EXPECT_TRUE(rtc_is_invalid(&default_rtc));
EXPECT_TRUE(rtc_is_invalid(&t0));
}
TEST(RTCLibTest, SanitizeRTCCheecksSetError) {
backstop_clear();
auto t0 = make_rtc(2018, 8, 4, 99, 19, 1);
EXPECT_TRUE(rtc_is_invalid(&t0));
rtc_clear();
sanitize_rtc(NULL, &t0, rtc_get, rtc_bad_set);
EXPECT_TRUE(rtc_is_invalid(&default_rtc));
EXPECT_TRUE(rtc_is_invalid(&t0));
}
TEST(RTCLibTest, SanitizeRTCSetsBackstop) {
backstop_clear();
// There's no backstop value, but we're ahead of the hardcoded backstop.
auto before_backstop = make_rtc(2019, 2, 2, 0, 0, 0);
sanitize_rtc(nullptr, &before_backstop, &rtc_get, &rtc_set);
EXPECT_TRUE(rtc_equal(&before_backstop, &default_rtc));
// There's no backstop, and the clock is behind the hardcoded backstop.
auto before_default = make_rtc(2018, 1, 1, 0, 0, 0);
sanitize_rtc(nullptr, &before_default, &rtc_get, &rtc_set);
auto constant_rtc = make_rtc(2019, 1, 1, 0, 0, 0);
EXPECT_TRUE(rtc_equal(&constant_rtc, &default_rtc));
// There's a backstop, so any date prior will be moved to the backstop.
auto backstop = make_rtc(2019, 7, 20, 1, 4, 6);
setenv("clock.backstop", "1563584646", 1);
sanitize_rtc(nullptr, &before_backstop, &rtc_get, &rtc_set);
EXPECT_TRUE(rtc_equal(&backstop, &default_rtc));
}