// main.cpp
// Copyright (C) MicroNeil Research Corporation
//
// This is the certification test for the timing module.
// Most of these tests are about basic sanity.
// If something doesn't look sane then the program returns the line number
// starting the tests that failed. Otherwise the program returns zero.
//
// 20060404 _M Added testing for Timer::start(msclock startt);
//
// 20060403 _M Polished this off and successfully tested on RHES3 (g++)
// and on WINXP (mingw) with comparable results. This is ready for production.
// The thing I wish is that on win32 platforms the timing functions were more
// robuts and reliable -- but they're not. No matter what way you slice it,
// any kind of real-time functionality on the Windows platform is going to be
// problematic and application specific. That said, this new timing module does
// provide reasonably accurate functions for most applications that don't need
// to interact in real-time.
#include <iostream>
#include <cmath>
#include "timing.hpp"
using namespace std;
char* TestName = "none";
int TestLine = 0;
#define NowTesting(x) _NowTesting(__LINE__,x);
class FoundABugException {};
void _NowTesting(int l, char* x) {
TestName = x;
TestLine = l;
cout << endl << "Testing " << TestLine << ": " << x << endl;
}
static const int X30SECS = 30000; // 30 second timeout value.
class ThirtySecondTimeout: public Timeout { // Make a 30 second timeout extended class.
public:
ThirtySecondTimeout():Timeout(X30SECS) {}
};
int main() {
try {
NowTesting("Timing Module Certification.");
// Keep track of the running time with timerx as part of the cert.
NowTesting("Timer timerx;");
Timer timerx;
// Certify Sleeper.
// Sleeper()
// Sleeper(int x)
// setMillisecondsToSleep()
// getMillisecondsToSleep()
// sleep();
// sleep(int x);
NowTesting("Sleeper Certifications...");
NowTesting("BadSleeperValue exceptions");
static const int BadMinSleeperTime = MinimumSleeperTime - 1;
static const int BadMaxSleeperTime = MaximumSleeperTime + 1;
static const int NominalSleeperTime = 10;
bool ExceptionsHappen = false; // Create a reset test flag.
try {
Sleeper T(BadMinSleeperTime); // Test for a bad low sleeper time.
} catch (Sleeper::BadSleeperValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "BadMinSleeperTime exception works." << endl;
} else {
cout << "BadMinSleeperTime execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
Sleeper T(BadMaxSleeperTime); // Test for a bad high sleeper time.
} catch (Sleeper::BadSleeperValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "BadMaxSleeperTime exception works." << endl;
} else {
cout << "BadMaxSleeperTime execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
Sleeper T; // Test for an unset sleeper time.
T.sleep(); // Try to sleep with that!
} catch (Sleeper::BadSleeperValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Unset Sleep Time exception works." << endl;
} else {
cout << "Unset Sleep Time execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
Sleeper T;
T.setMillisecondsToSleep(BadMinSleeperTime); // Test setting bad low after construction.
} catch (Sleeper::BadSleeperValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad low after construction exception works." << endl;
} else {
cout << "Bad low after construction execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
Sleeper T;
T.setMillisecondsToSleep(BadMaxSleeperTime); // Test setting bad high after construction.
} catch (Sleeper::BadSleeperValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad high after construction exception works." << endl;
} else {
cout << "Bad high after construction execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
Sleeper T;
T.sleep(BadMinSleeperTime); // Test setting bad low sleep(x)
} catch (Sleeper::BadSleeperValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad low on sleep(x) exception works." << endl;
} else {
cout << "Bad low on sleep(x) execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
Sleeper T;
T.sleep(BadMaxSleeperTime); // Test setting bad high sleep(x)
} catch (Sleeper::BadSleeperValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad high on sleep(x) exception works." << endl;
} else {
cout << "Bad high on sleep(x) execption failed!" << endl;
throw FoundABugException();
}
NowTesting("Sleeper Sleeper1;");
Sleeper Sleeper1;
NowTesting("Sleeper Sleeper200(200);");
Sleeper Sleeper200(200);
NowTesting("Sleeper200.getMillisecondsToSleep();");
if(200==Sleeper200.getMillisecondsToSleep()) {
cout << "Sleeper200.getMilliscondsToSleep() OK!" << endl;
}
// SWIGGLE is 15ms because the actual sleep time can be effected by
// operating system and operating conditions. Also, on WIN32 systems the
// measured time in a timer can be off by as much as 15ms because the
// time values are only set (all be it accurately) 64 times per second
// or so on XP. A higher resolution timer could be created, but it would
// be overkill for most of the applications this code is intended to
// support.
static const int SWIGGLE = 15; // Wiggle room for sleep times.
static const int FIRST_SLEEPER1_TIME = 92; // Time for first spleeper experiment.
NowTesting("Sleeper1.setMillisecondsToSleep(FIRST_LEEPER1_TIME)");
Sleeper1.setMillisecondsToSleep(FIRST_SLEEPER1_TIME);
NowTesting("Sleeper1.getMillisecondsToSleep()");
if(FIRST_SLEEPER1_TIME != Sleeper1.getMillisecondsToSleep()) {
cout << "getMillisecondsToSleep() did not match setMillisecondsToSleep()!" << endl;
throw FoundABugException();
}
NowTesting("First Elapsed Time from timerx & Build T1 to test Sleeper1.");
cout << "Time elapsed: " << timerx.getElapsedSeconds() << endl;
Timer T1;
NowTesting("Sleeper1.sleep();");
Sleeper1.sleep();
T1.stop();
cout << "Time elapsed: " << timerx.getElapsedSeconds() << endl;
cout << "T1 time slept: " << T1.getElapsedTime() << endl;
int delta;
if(SWIGGLE > (delta = abs((long long int) T1.getElapsedTime() - Sleeper1.getMillisecondsToSleep()))) {
cout << "T1.getElapsedTime - Sleeper1.getMillisecondsToSleep() within "
<< SWIGGLE << "ms - OK! (" << delta << "ms)" << endl;
} else {
cout << "T1.getElapsedTime - Sleeper1.getMillisecondsToSleep() is not in range! (" << delta << "ms)" << endl;
throw FoundABugException();
}
int SECOND_SLEEPER1_TIME = 532; // Time for second sleeper experiment.
NowTesting("T1.restart & Sleeper.sleep(x)");
NowTesting("Sleeper1.sleep(SECOND_SLEEPER1_TIME);");
T1.start();
Sleeper1.sleep(SECOND_SLEEPER1_TIME);
T1.stop();
cout << "Time elapsed: " << timerx.getElapsedSeconds() << endl;
cout << "T1 time slept: " << T1.getElapsedTime() << endl;
cout << "Sleeper1.getMillisecondsToSleep(): " << Sleeper1.getMillisecondsToSleep() << endl;
delta = abs((long long int) T1.getElapsedTime() - Sleeper1.getMillisecondsToSleep());
if(SWIGGLE > delta) {
cout << "T1.getElapsedTime - Sleeper1.getMillisecondsToSleep() within 15 ms - OK! (" << delta << "ms)" << endl;
} else {
cout << "T1.getElapsedTime - Sleeper1.getMillisecondsToSleep() is not in range! (" << delta << "ms)" << endl;
throw FoundABugException();
}
// Certify PollTimer
// PollTimer(int Nom, int Max)
// setNominalPollTime(int Nom)
// setMaximumPollTime(int Max)
// reset()
// pause()
NowTesting("PollTimer exceptions...");
ExceptionsHappen = false; // Reset the test flag.
try {
PollTimer T(BadMinSleeperTime,NominalSleeperTime); // Test bad low nom exception.
} catch (PollTimer::BadPollTimerValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad low nominal construction exception works." << endl;
} else {
cout << "Bad low nominal construction execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
PollTimer T(BadMaxSleeperTime,NominalSleeperTime); // Test bad high nom exception.
} catch (PollTimer::BadPollTimerValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad high nominal construction exception works." << endl;
} else {
cout << "Bad high nominal construction execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
PollTimer T(NominalSleeperTime,BadMinSleeperTime); // Test bad low max exception.
} catch (PollTimer::BadPollTimerValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad low max construction exception works." << endl;
} else {
cout << "Bad low max construction execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
PollTimer T(NominalSleeperTime,BadMaxSleeperTime); // Test bad high max exception.
} catch (PollTimer::BadPollTimerValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad high max construction exception works." << endl;
} else {
cout << "Bad high max construction execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
PollTimer T(NominalSleeperTime,NominalSleeperTime);
T.setNominalPollTime(BadMinSleeperTime); // Test bad nom change exception.
} catch (PollTimer::BadPollTimerValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad low nom change exception works." << endl;
} else {
cout << "Bad low nom change execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
PollTimer T(NominalSleeperTime,NominalSleeperTime);
T.setNominalPollTime(BadMaxSleeperTime); // Test high nom change exception.
} catch (PollTimer::BadPollTimerValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad high nom change exception works." << endl;
} else {
cout << "Bad high nom change execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
PollTimer T(NominalSleeperTime,NominalSleeperTime);
T.setMaximumPollTime(BadMinSleeperTime); // Test low max change exception.
} catch (PollTimer::BadPollTimerValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad low max change exception works." << endl;
} else {
cout << "Bad low max change execption failed!" << endl;
throw FoundABugException();
}
ExceptionsHappen = false; // Reset the test flag.
try {
PollTimer T(NominalSleeperTime,NominalSleeperTime);
T.setMaximumPollTime(BadMaxSleeperTime); // Test high max change exception.
} catch (PollTimer::BadPollTimerValue) {
ExceptionsHappen = true;
}
if(true == ExceptionsHappen) {
cout << "Bad high max change exception works." << endl;
} else {
cout << "Bad high max change execption failed!" << endl;
throw FoundABugException();
}
NowTesting("PollTimer PT1(PTNOMINAL, PTMAXIMUM);");
static const int PTNOMINAL = 10;
static const int PTMAXIMUM = 1000;
static const int MAX_POLLTIMER_LOOP_COUNT = 100;
PollTimer PT1(PTNOMINAL, PTMAXIMUM);
NowTesting("First pause time = Min");
int LastPollTime = 0;
T1.start();
LastPollTime = PT1.pause();
T1.stop();
if(PTNOMINAL == LastPollTime) {
cout << "PT1 Min Poll Time indicated on first pass OK!" << endl;
} else {
cout << "PT1 Min Poll Time NOT INDICATED ON FIRST PASS!" << endl;
throw FoundABugException();
}
delta = abs((long long int) T1.getElapsedTime() - PTNOMINAL);
cout << "Elapsed on first poll was: " << T1.getElapsedTime() << endl;
if(SWIGGLE > delta) {
cout << "PT1 Min Poll Time .wiggle on first poll was OK! ("
<< delta << ")" << endl;
} else {
cout << "PT1 Min Poll Time wiggle on firlst poll was BAD! ("
<< delta << ")" << endl;
throw FoundABugException();
}
NowTesting("PT1.pause() in a loop to Max poll time.");
int LoopCount = 0;
while( // Loop while...
LastPollTime < PTMAXIMUM && // We've not reached our maximum pause time and
MAX_POLLTIMER_LOOP_COUNT > LoopCount) { // We've not exceeded our loop count.
LoopCount++; // Count the loops.
T1.start(); // Start the clock to measure the event.
LastPollTime = PT1.pause(); // Pause per loop.
T1.stop(); // Stop the clock measuring the event.
cout << "Loop[" << LoopCount // Report per loop.
<< "] Last Poll Time: " << LastPollTime << endl;
cout << " Measured: " << T1.getElapsedTime() << endl; // Report the measured time.
delta = abs((long long int) T1.getElapsedTime() - LastPollTime);
if(SWIGGLE < delta) { // Check for too much wiggle.
cout << "SWIGGLE EXCEEDED!" << endl; // Report and throw if we find it.
throw FoundABugException();
}
}
NowTesting("Max pause time reached and correct?");
if(PTMAXIMUM == LastPollTime) {
cout << "Indicated Poll Time is correct. SWIGGLE passed!" << endl;
} else {
cout << "Indicated Poll Time NOT MAX!" << endl;
throw FoundABugException();
}
NowTesting("PT1.reset();");
PT1.reset();
// Certify Timer
// Timer()
// Timer(msclock startt)
// start()
// start(msclock startt)
// stop()
// getStartClock()
// getElapsedTime()
// getStopClock()
// isRunning()
// getElapsedSeconds()
// isUnixBased()
// toWindowsEpoch(msclock unixt)
// toUnixEpoch(msclock win32t)
NowTesting("TX, TY, TZ chaining & basic functions.");
Timer TX; // Create TX Timer.
Sleeper200.sleep(); // Sleep a bit.
Timer TY(TX.stop()); // Create TY Timer chained from TX.
Sleeper200.sleep(); // Sleep a bit.
if(true == TY.isRunning()) { // Test the isRunning() method when running.
cout << "TY.isRunning() seems correct." << endl;
} else {
cout << "TY.isRunning() IS NOT CORRECT!" << endl;
throw FoundABugException();
}
if(false == TX.isRunning()) { // Test the isRunning() method when not running.
cout << "TX.isRunning() seems correct." << endl;
} else {
cout << "TX.isRunning() IS NOT CORRECT!" << endl;
throw FoundABugException();
}
Sleeper200.sleep(); // Sleep again for fun.
Timer TZ(TY.stop()); // Create TZ timer chained from TY.
Sleeper200.sleep(); // Sleep 1
Sleeper200.sleep(); // 2...
Sleeper200.sleep(); // 3 times the charm.
timerx.start(TZ.stop()); // Stop TZ and restart timerx.
if(timerx.getStartClock() == TZ.getStopClock()) {
cout << "timerx.start(TZ.stop()) worked as expected." << endl;
} else {
cout << "timerx.start(TZ.stop()) is broken!" << endl;
throw FoundABugException();
}
NowTesting("getStartClock, getStopClock, and getElapsedTime");
cout << "TX start clock: " << TX.getStartClock() << endl;
cout << "TX stop clock: " << TX.getStopClock() << endl;
long long int MeasureElapsed = TX.getStopClock() - TX.getStartClock();
cout << "TX external calc of elapsed ms = " << MeasureElapsed << endl;
cout << "TX getElapsedTime() returns: " << TX.getElapsedTime() << endl;
if(TX.getElapsedTime() == MeasureElapsed) {
cout << "TX getElapsedTime() and MeasureElapsed match ok!" << endl;
} else {
cout << "TX.getElapsedTime() and MeasureElapsed DO NOT MATCH!" << endl;
throw FoundABugException();
}
NowTesting("getElapsedSeconds() math");
double ElapsedShouldBe = (3 * 200) / 1000; // We waited 3 & 200 milliseconds.
cout << "TZ.getElapsedSeconds() returns: "
<< TZ.getElapsedSeconds() << endl;
static const double SecondsWiggle = SWIGGLE / 1000; // Calculate wiggle as seconds.
double SecondsDelta = abs(ElapsedShouldBe-TZ.getElapsedSeconds()); // Calculate the delta.
cout << "SecondsDelta is: " << SecondsDelta << endl;
if(SecondsWiggle < SecondsDelta) {
cout << "Seconds Look Good from getElapsedSeconds()." << endl;
} else {
cout << "Seconds DONT MATCH from getElapsedSeconds()!" << endl;
throw FoundABugException();
}
NowTesting("Does the TX, TY, TZ chain match?");
if( // Start and end clocks on the chain should match.
TX.getStopClock() == TY.getStartClock() &&
TY.getStopClock() == TZ.getStartClock()
) {
cout << "Chained timers work ok." << endl;
} else {
cout << "Cained timers broken!" << endl;
throw FoundABugException();
}
NowTesting("isUnixBased() Correct?");
#ifdef WIN32
if(false == TZ.isUnixBased()) { // On a WIN32 system this should be false.
cout << "isUnixBased() appears correct." << endl;
} else {
cout << "isUnixBased() appears broken!" << endl;
throw FoundABugException();
}
#else
if(true == TZ.isUnixBased()) { // On a non WIN32 system this should be true.
cout << "isUnixBased() appears correct." << endl;
} else {
cout << "isUnixBased() appears broken!" << endl;
throw FoundABugException();
}
#endif
NowTesting("toWindowsEpoch() and toUnixEpoch()");
if( // Epoch conversion should be symmetcal.
TZ.toWindowsEpoch(TZ.getStopClock()) != TZ.getStopClock() &&
TZ.getStopClock() == TZ.toUnixEpoch(TZ.toWindowsEpoch(TZ.getStopClock()))
) {
cout << "Epoch Conversions seem correct." << endl;
} else {
cout << "Epoch Conversions are not symmetrical!" << endl;
throw FoundABugException();
}
// Certify Timeout
// Timeout(msclock duration)
// setDuration(msclock duration)
// restart()
// getElapsedTime()
// getRemainingTime()
// isExpired()
NowTesting("ThirtySecondTimeout X30");
ThirtySecondTimeout X30; // Create a 30 second timout by extension.
if(X30SECS == X30.getDuration()) { // Test getDuration();
cout << "getDuration() seems sane." << endl;
} else {
cout << "getDuration() is broken!" << endl;
throw FoundABugException();
}
NowTesting("Timeout.getElapsedTime & .getRemainingTime()");
msclock PreElapsed = X30.getElapsedTime();
msclock PreRemaining = X30.getRemainingTime();
T1.start();
Sleeper200.sleep();
msclock PostElapsed = X30.getElapsedTime();
msclock PostRemaining = X30.getRemainingTime();
T1.stop();
long long int ElapsedCalc = PostElapsed - PreElapsed;
long long int RemainingCalc = PreRemaining - PostRemaining;
delta = abs((long long int) T1.getElapsedTime() - ElapsedCalc);
if(SWIGGLE > delta) {
cout << "getElapsedTime() seems sane." << endl;
} else {
cout << "getElapsedTime() is broken!" << endl;
throw FoundABugException();
}
delta = abs((long long int) T1.getElapsedTime() - RemainingCalc);
if(SWIGGLE > delta) {
cout << "getRemainingTime() seems sane." << endl;
} else {
cout << "getRemainingTime() is broken!" << endl;
throw FoundABugException();
}
NowTesting("X30 count down...");
static const int ONESEC = 1000;
PollTimer XX(ONESEC,ONESEC); // Count down every second...
while(false == X30.isExpired()) {
cout << "X30.getElapsedTime() = " << X30.getElapsedTime() << endl;
cout << "X30.getRemainingTime() = " << X30.getRemainingTime() << endl;
XX.pause();
}
NowTesting("X30 Remaining value after expiration.");
Sleeper200.sleep(); // After we've expired wait a bit...
if(0 == X30.getRemainingTime()) {
cout << "X30 zero remaining after timeout ok." << endl;
} else {
cout << "X30 NOT ZERO AFTER TIMEOUT!" << endl;
throw FoundABugException();
}
NowTesting("X30 Restart function");
X30.restart(); // After a restart we should have 30 secs.
msclock X30NewRemaining = X30.getRemainingTime();
delta = abs((long long int) X30NewRemaining - X30SECS);
if(SWIGGLE > delta && false == X30.isExpired()) {
cout << "X30 Restart to 30 secs OK." << endl;
} else {
cout << "X30 Restart BROKEN!" << endl;
cout << "X30 reports time left is: " << X30NewRemaining << endl;
throw FoundABugException();
}
}
catch(...) {
cout << "Unexpected Error In Test " << TestName << endl;
return (TestLine);
}
cout << endl << "All OK!" << endl;
return (0);
}