From 0d1aad59945b53f19def9893b22dbd3da15dfbc9 Mon Sep 17 00:00:00 2001 From: ahcorde Date: Mon, 11 Oct 2021 16:05:32 +0200 Subject: [PATCH 1/2] Added StopWatch Python Interface Signed-off-by: ahcorde --- src/python/CMakeLists.txt | 1 + src/python/StopWatch.i | 68 +++++++++++++++ src/python/StopWatch_TEST.py | 161 +++++++++++++++++++++++++++++++++++ src/python/python.i | 1 + 4 files changed, 231 insertions(+) create mode 100644 src/python/StopWatch.i create mode 100644 src/python/StopWatch_TEST.py diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 36033b9f8..5340d5e04 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -107,6 +107,7 @@ if (PYTHONLIBS_FOUND) RotationSpline_TEST SemanticVersion_TEST SignalStats_TEST + StopWatch_TEST Spline_TEST Temperature_TEST Triangle_TEST diff --git a/src/python/StopWatch.i b/src/python/StopWatch.i new file mode 100644 index 000000000..161bb6105 --- /dev/null +++ b/src/python/StopWatch.i @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +%module stopwatch +%{ +#include +#include +#include "ignition/math/Stopwatch.hh" +#include +#include +%} + +%include "typemaps.i" +%typemap(out) (std::chrono::steady_clock::time_point) %{ + $result = SWIG_From_long(std::chrono::duration_cast( + (&result)->time_since_epoch()).count()); +%} + +%typemap(out) (std::chrono::steady_clock::duration) %{ + $result = SWIG_From_long((&result)->count()); +%} + +namespace ignition +{ + namespace math + { + class Stopwatch + { + public: Stopwatch(); + + public: virtual ~Stopwatch(); + + public: bool Start(const bool _reset = false); + + public: std::chrono::steady_clock::time_point StartTime() const; + + public: bool Stop(); + + public: std::chrono::steady_clock::time_point StopTime() const; + + public: bool Running() const; + + public: void Reset(); + + public: std::chrono::steady_clock::duration ElapsedRunTime() const; + + public: std::chrono::steady_clock::duration ElapsedStopTime() const; + + public: bool operator==(const Stopwatch &_watch) const; + + public: bool operator!=(const Stopwatch &_watch) const; + }; + } +} diff --git a/src/python/StopWatch_TEST.py b/src/python/StopWatch_TEST.py new file mode 100644 index 000000000..6b0c7e621 --- /dev/null +++ b/src/python/StopWatch_TEST.py @@ -0,0 +1,161 @@ +# Copyright (C) 2021 Open Source Robotics Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License") +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import time +import unittest +from datetime import datetime, timedelta + +from ignition.math import Stopwatch + + +class TestBox(unittest.TestCase): + # Helper function that runs a few tests + def runTimer(self, _time): + handleSteadyClock = 0 + + # Start the timer + self.assertTrue(_time.start()) + # The timer should be running. + self.assertTrue(_time.running()) + # The start time should be greater than the stop time. + self.assertGreater(_time.start_time(), _time.stop_time()) + print(_time.elapsed_stop_time()) + # The elapsed stop time should still be zero. + self.assertEqual(0, _time.elapsed_stop_time()) + + # Wait for some time... + time.sleep(1) + # Now the elapsed time should be greater than or equal to the time slept. + self.assertGreaterEqual(_time.elapsed_run_time() + handleSteadyClock, 100) + + # Stop the timer. + self.assertTrue(_time.stop()) + # The timer should not be running. + self.assertFalse(_time.running()) + # The stop time should be greater than the start time. + self.assertGreater(_time.stop_time(), _time.start_time()) + # The elapsed time should still be greater than the time slept. + self.assertGreaterEqual(_time.elapsed_run_time() + handleSteadyClock, 1000) + + # Save the elapsed time. + elapsedTime = _time.elapsed_run_time() + + # The timer is now stopped, let's sleep some more. + time.sleep(1) + # The elapsed stop time should be greater than or equal to the time + # slept. + self.assertGreaterEqual(_time.elapsed_stop_time() + handleSteadyClock, 100) + # The elapsed time should be the same. + self.assertEqual(elapsedTime, _time.elapsed_run_time()) + + # Start the timer again. + self.assertTrue(_time.start()) + # Store the elapsed stop time. + elapsedStopTime = _time.elapsed_stop_time() + # The timer should be running. + self.assertTrue(_time.running()) + # Sleep for some time. + time.sleep(1) + # The elapsed stop time should remain the same + self.assertEqual(elapsedStopTime, _time.elapsed_stop_time()) + # The elapsed time should be greater than the previous elapsed time. + self.assertGreater(_time.elapsed_run_time(), elapsedTime) + # The elapsed time should be greater than or equal to the the previous + # two sleep times. + self.assertGreaterEqual(_time.elapsed_run_time() + handleSteadyClock, 2000) + + def test_constructor(self): + watch = Stopwatch() + + self.assertFalse(watch.running()) + self.assertEqual(watch.stop_time(), watch.start_time()) + self.assertEqual(0, watch.elapsed_run_time()) + self.assertEqual(0, watch.elapsed_stop_time()) + + self.runTimer(watch) + + watch2 = watch + self.assertEqual(watch, watch2) + + watch3 = watch2 + self.assertEqual(watch, watch3) + + def test_equal_operator(self): + watch = Stopwatch() + watch2 = Stopwatch() + watch3 = Stopwatch() + self.assertEqual(watch, watch2) + self.assertEqual(watch, watch3) + + self.runTimer(watch) + self.runTimer(watch2) + self.runTimer(watch3) + + self.assertNotEqual(watch, watch2) + self.assertNotEqual(watch, watch3) + + watch2 = watch + self.assertEqual(watch, watch2) + + watch3 = watch2 + self.assertEqual(watch, watch3) + + def test_start_stop_reset(self): + watch = Stopwatch() + + self.runTimer(watch) + + watch.reset() + + self.assertFalse(watch.running()) + self.assertEqual(watch.stop_time(), watch.start_time()) + self.assertEqual(0, watch.elapsed_run_time()) + self.assertEqual(0, watch.elapsed_stop_time()) + + self.runTimer(watch) + + self.assertTrue(watch.running()) + + watch.start(True) + self.assertTrue(watch.running()) + self.assertLess(watch.stop_time(), watch.start_time()) + self.assertNotEqual(0, watch.elapsed_run_time()) + self.assertEqual(0, watch.elapsed_stop_time()) + + def test_fail_start_stop(self): + watch = Stopwatch() + + # Can't stop while not running + self.assertFalse(watch.stop()) + self.assertFalse(watch.running()) + + # Can start while not running + self.assertTrue(watch.start()) + self.assertTrue(watch.running()) + + # Can't start while running + self.assertFalse(watch.start()) + self.assertTrue(watch.running()) + + # Can stop while running + self.assertTrue(watch.stop()) + self.assertFalse(watch.running()) + + # Can start while not running + self.assertTrue(watch.start()) + self.assertTrue(watch.running()) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/python/python.i b/src/python/python.i index cea95117b..e478528b8 100644 --- a/src/python/python.i +++ b/src/python/python.i @@ -2,6 +2,7 @@ %include Angle.i %include GaussMarkovProcess.i %include Rand.i +%include StopWatch.i %include Vector2.i %include Vector3.i %include Vector4.i From c1c8e1701ad4f7a05cde08f3b772cd4d9ad1c3af Mon Sep 17 00:00:00 2001 From: ahcorde Date: Thu, 14 Oct 2021 13:20:01 +0200 Subject: [PATCH 2/2] feedback Signed-off-by: ahcorde --- src/python/CMakeLists.txt | 2 +- src/python/StopWatch_TEST.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 5340d5e04..efcd4bc9d 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -107,8 +107,8 @@ if (PYTHONLIBS_FOUND) RotationSpline_TEST SemanticVersion_TEST SignalStats_TEST - StopWatch_TEST Spline_TEST + StopWatch_TEST Temperature_TEST Triangle_TEST Triangle3_TEST diff --git a/src/python/StopWatch_TEST.py b/src/python/StopWatch_TEST.py index 6b0c7e621..b0c777e7b 100644 --- a/src/python/StopWatch_TEST.py +++ b/src/python/StopWatch_TEST.py @@ -30,14 +30,13 @@ def runTimer(self, _time): self.assertTrue(_time.running()) # The start time should be greater than the stop time. self.assertGreater(_time.start_time(), _time.stop_time()) - print(_time.elapsed_stop_time()) # The elapsed stop time should still be zero. self.assertEqual(0, _time.elapsed_stop_time()) # Wait for some time... time.sleep(1) # Now the elapsed time should be greater than or equal to the time slept. - self.assertGreaterEqual(_time.elapsed_run_time() + handleSteadyClock, 100) + self.assertGreaterEqual(_time.elapsed_run_time() + handleSteadyClock, 1000) # Stop the timer. self.assertTrue(_time.stop()) @@ -55,7 +54,7 @@ def runTimer(self, _time): time.sleep(1) # The elapsed stop time should be greater than or equal to the time # slept. - self.assertGreaterEqual(_time.elapsed_stop_time() + handleSteadyClock, 100) + self.assertGreaterEqual(_time.elapsed_stop_time() + handleSteadyClock, 1000) # The elapsed time should be the same. self.assertEqual(elapsedTime, _time.elapsed_run_time())