mirror of
https://github.com/Xevion/exercism.git
synced 2025-12-06 13:15:00 -06:00
clock exercise
This commit is contained in:
1
python/clock/.exercism/metadata.json
Normal file
1
python/clock/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"track":"python","exercise":"clock","id":"5ea6c6c4c840489da2850d5d3dacd63f","url":"https://exercism.io/my/solutions/5ea6c6c4c840489da2850d5d3dacd63f","handle":"Xevion","is_requester":true,"auto_approve":false}
|
||||||
56
python/clock/README.md
Normal file
56
python/clock/README.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Clock
|
||||||
|
|
||||||
|
Implement a clock that handles times without dates.
|
||||||
|
|
||||||
|
You should be able to add and subtract minutes to it.
|
||||||
|
|
||||||
|
Two clocks that represent the same time should be equal to each other.
|
||||||
|
|
||||||
|
## Exception messages
|
||||||
|
|
||||||
|
Sometimes it is necessary to raise an exception. When you do this, you should include a meaningful error message to
|
||||||
|
indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. Not
|
||||||
|
every exercise will require you to raise an exception, but for those that do, the tests will only pass if you include
|
||||||
|
a message.
|
||||||
|
|
||||||
|
To raise a message with an exception, just write it as an argument to the exception type. For example, instead of
|
||||||
|
`raise Exception`, you should write:
|
||||||
|
|
||||||
|
```python
|
||||||
|
raise Exception("Meaningful message indicating the source of the error")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
To run the tests, run the appropriate command below ([why they are different](https://github.com/pytest-dev/pytest/issues/1629#issue-161422224)):
|
||||||
|
|
||||||
|
- Python 2.7: `py.test clock_test.py`
|
||||||
|
- Python 3.4+: `pytest clock_test.py`
|
||||||
|
|
||||||
|
Alternatively, you can tell Python to run the pytest module (allowing the same command to be used regardless of Python version):
|
||||||
|
`python -m pytest clock_test.py`
|
||||||
|
|
||||||
|
### Common `pytest` options
|
||||||
|
|
||||||
|
- `-v` : enable verbose output
|
||||||
|
- `-x` : stop running tests on first failure
|
||||||
|
- `--ff` : run failures from previous test before running other test cases
|
||||||
|
|
||||||
|
For other options, see `python -m pytest -h`
|
||||||
|
|
||||||
|
## Submitting Exercises
|
||||||
|
|
||||||
|
Note that, when trying to submit an exercise, make sure the solution is in the `$EXERCISM_WORKSPACE/python/clock` directory.
|
||||||
|
|
||||||
|
You can find your Exercism workspace by running `exercism debug` and looking for the line that starts with `Workspace`.
|
||||||
|
|
||||||
|
For more detailed information about running tests, code style and linting,
|
||||||
|
please see [Running the Tests](http://exercism.io/tracks/python/tests).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
Pairing session with Erin Drummond [https://twitter.com/ebdrummond](https://twitter.com/ebdrummond)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
26
python/clock/clock.py
Normal file
26
python/clock/clock.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
class Clock(object):
|
||||||
|
def __init__(self, hour, minute):
|
||||||
|
self.hour, self.minute = hour, minute
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Clock {}:{}>'.format(str(self.hour).zfill(2), str(self.minute).zfill(2))
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.hour == other.hour and self.minute == other.minute
|
||||||
|
|
||||||
|
def change(self, minutes):
|
||||||
|
self.minute += minutes
|
||||||
|
while self.minute >= 60 or self.minute < 0:
|
||||||
|
if self.minute >= 60:
|
||||||
|
self.hour += 1
|
||||||
|
self.minute -= 60
|
||||||
|
elif self.minute < 0:
|
||||||
|
self.hour -= 1
|
||||||
|
self.minute += 60
|
||||||
|
self.hour = self.hour % 24
|
||||||
|
|
||||||
|
def __add__(self, minutes):
|
||||||
|
return self.change(minutes)
|
||||||
|
|
||||||
|
def __sub__(self, minutes):
|
||||||
|
return self.change(-minutes)
|
||||||
170
python/clock/clock_test.py
Normal file
170
python/clock/clock_test.py
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from clock import Clock
|
||||||
|
|
||||||
|
|
||||||
|
# Tests adapted from `problem-specifications//canonical-data.json` @ v2.4.0
|
||||||
|
|
||||||
|
class ClockTest(unittest.TestCase):
|
||||||
|
# Test creating a new clock with an initial time.
|
||||||
|
def test_on_the_hour(self):
|
||||||
|
self.assertEqual(str(Clock(8, 0)), '08:00')
|
||||||
|
|
||||||
|
def test_past_the_hour(self):
|
||||||
|
self.assertEqual(str(Clock(11, 9)), '11:09')
|
||||||
|
|
||||||
|
def test_midnight_is_zero_hours(self):
|
||||||
|
self.assertEqual(str(Clock(24, 0)), '00:00')
|
||||||
|
|
||||||
|
def test_hour_rolls_over(self):
|
||||||
|
self.assertEqual(str(Clock(25, 0)), '01:00')
|
||||||
|
|
||||||
|
def test_hour_rolls_over_continuously(self):
|
||||||
|
self.assertEqual(str(Clock(100, 0)), '04:00')
|
||||||
|
|
||||||
|
def test_sixty_minutes_is_next_hour(self):
|
||||||
|
self.assertEqual(str(Clock(1, 60)), '02:00')
|
||||||
|
|
||||||
|
def test_minutes_roll_over(self):
|
||||||
|
self.assertEqual(str(Clock(0, 160)), '02:40')
|
||||||
|
|
||||||
|
def test_minutes_roll_over_continuously(self):
|
||||||
|
self.assertEqual(str(Clock(0, 1723)), '04:43')
|
||||||
|
|
||||||
|
def test_hour_and_minutes_roll_over(self):
|
||||||
|
self.assertEqual(str(Clock(25, 160)), '03:40')
|
||||||
|
|
||||||
|
def test_hour_and_minutes_roll_over_continuously(self):
|
||||||
|
self.assertEqual(str(Clock(201, 3001)), '11:01')
|
||||||
|
|
||||||
|
def test_hour_and_minutes_roll_over_to_exactly_midnight(self):
|
||||||
|
self.assertEqual(str(Clock(72, 8640)), '00:00')
|
||||||
|
|
||||||
|
def test_negative_hour(self):
|
||||||
|
self.assertEqual(str(Clock(-1, 15)), '23:15')
|
||||||
|
|
||||||
|
def test_negative_hour_rolls_over(self):
|
||||||
|
self.assertEqual(str(Clock(-25, 0)), '23:00')
|
||||||
|
|
||||||
|
def test_negative_hour_rolls_over_continuously(self):
|
||||||
|
self.assertEqual(str(Clock(-91, 0)), '05:00')
|
||||||
|
|
||||||
|
def test_negative_minutes(self):
|
||||||
|
self.assertEqual(str(Clock(1, -40)), '00:20')
|
||||||
|
|
||||||
|
def test_negative_minutes_roll_over(self):
|
||||||
|
self.assertEqual(str(Clock(1, -160)), '22:20')
|
||||||
|
|
||||||
|
def test_negative_minutes_roll_over_continuously(self):
|
||||||
|
self.assertEqual(str(Clock(1, -4820)), '16:40')
|
||||||
|
|
||||||
|
def test_negative_sixty_minutes_is_previous_hour(self):
|
||||||
|
self.assertEqual(str(Clock(2, -60)), '01:00')
|
||||||
|
|
||||||
|
def test_negative_hour_and_minutes_both_roll_over(self):
|
||||||
|
self.assertEqual(str(Clock(-25, -160)), '20:20')
|
||||||
|
|
||||||
|
def test_negative_hour_and_minutes_both_roll_over_continuously(self):
|
||||||
|
self.assertEqual(str(Clock(-121, -5810)), '22:10')
|
||||||
|
|
||||||
|
# Test adding and subtracting minutes.
|
||||||
|
def test_add_minutes(self):
|
||||||
|
self.assertEqual(str(Clock(10, 0) + 3), '10:03')
|
||||||
|
|
||||||
|
def test_add_no_minutes(self):
|
||||||
|
self.assertEqual(str(Clock(6, 41) + 0), '06:41')
|
||||||
|
|
||||||
|
def test_add_to_next_hour(self):
|
||||||
|
self.assertEqual(str(Clock(0, 45) + 40), '01:25')
|
||||||
|
|
||||||
|
def test_add_more_than_one_hour(self):
|
||||||
|
self.assertEqual(str(Clock(10, 0) + 61), '11:01')
|
||||||
|
|
||||||
|
def test_add_more_than_two_hours_with_carry(self):
|
||||||
|
self.assertEqual(str(Clock(0, 45) + 160), '03:25')
|
||||||
|
|
||||||
|
def test_add_across_midnight(self):
|
||||||
|
self.assertEqual(str(Clock(23, 59) + 2), '00:01')
|
||||||
|
|
||||||
|
def test_add_more_than_one_day(self):
|
||||||
|
self.assertEqual(str(Clock(5, 32) + 1500), '06:32')
|
||||||
|
|
||||||
|
def test_add_more_than_two_days(self):
|
||||||
|
self.assertEqual(str(Clock(1, 1) + 3500), '11:21')
|
||||||
|
|
||||||
|
def test_subtract_minutes(self):
|
||||||
|
self.assertEqual(str(Clock(10, 3) - 3), '10:00')
|
||||||
|
|
||||||
|
def test_subtract_to_previous_hour(self):
|
||||||
|
self.assertEqual(str(Clock(10, 3) - 30), '09:33')
|
||||||
|
|
||||||
|
def test_subtract_more_than_an_hour(self):
|
||||||
|
self.assertEqual(str(Clock(10, 3) - 70), '08:53')
|
||||||
|
|
||||||
|
def test_subtract_across_midnight(self):
|
||||||
|
self.assertEqual(str(Clock(0, 3) - 4), '23:59')
|
||||||
|
|
||||||
|
def test_subtract_more_than_two_hours(self):
|
||||||
|
self.assertEqual(str(Clock(0, 0) - 160), '21:20')
|
||||||
|
|
||||||
|
def test_subtract_more_than_two_hours_with_borrow(self):
|
||||||
|
self.assertEqual(str(Clock(6, 15) - 160), '03:35')
|
||||||
|
|
||||||
|
def test_subtract_more_than_one_day(self):
|
||||||
|
self.assertEqual(str(Clock(5, 32) - 1500), '04:32')
|
||||||
|
|
||||||
|
def test_subtract_more_than_two_days(self):
|
||||||
|
self.assertEqual(str(Clock(2, 20) - 3000), '00:20')
|
||||||
|
|
||||||
|
# Construct two separate clocks, set times, test if they are equal.
|
||||||
|
def test_clocks_with_same_time(self):
|
||||||
|
self.assertEqual(Clock(15, 37), Clock(15, 37))
|
||||||
|
|
||||||
|
def test_clocks_a_minute_apart(self):
|
||||||
|
self.assertNotEqual(Clock(15, 36), Clock(15, 37))
|
||||||
|
|
||||||
|
def test_clocks_an_hour_apart(self):
|
||||||
|
self.assertNotEqual(Clock(14, 37), Clock(15, 37))
|
||||||
|
|
||||||
|
def test_clocks_with_hour_overflow(self):
|
||||||
|
self.assertEqual(Clock(10, 37), Clock(34, 37))
|
||||||
|
|
||||||
|
def test_clocks_with_hour_overflow_by_several_days(self):
|
||||||
|
self.assertEqual(Clock(3, 11), Clock(99, 11))
|
||||||
|
|
||||||
|
def test_clocks_with_negative_hour(self):
|
||||||
|
self.assertEqual(Clock(22, 40), Clock(-2, 40))
|
||||||
|
|
||||||
|
def test_clocks_with_negative_hour_that_wraps(self):
|
||||||
|
self.assertEqual(Clock(17, 3), Clock(-31, 3))
|
||||||
|
|
||||||
|
def test_clocks_with_negative_hour_that_wraps_multiple_times(self):
|
||||||
|
self.assertEqual(Clock(13, 49), Clock(-83, 49))
|
||||||
|
|
||||||
|
def test_clocks_with_minute_overflow(self):
|
||||||
|
self.assertEqual(Clock(0, 1), Clock(0, 1441))
|
||||||
|
|
||||||
|
def test_clocks_with_minute_overflow_by_several_days(self):
|
||||||
|
self.assertEqual(Clock(2, 2), Clock(2, 4322))
|
||||||
|
|
||||||
|
def test_clocks_with_negative_minute(self):
|
||||||
|
self.assertEqual(Clock(2, 40), Clock(3, -20))
|
||||||
|
|
||||||
|
def test_clocks_with_negative_minute_that_wraps(self):
|
||||||
|
self.assertEqual(Clock(4, 10), Clock(5, -1490))
|
||||||
|
|
||||||
|
def test_clocks_with_negative_minute_that_wraps_multiple_times(self):
|
||||||
|
self.assertEqual(Clock(6, 15), Clock(6, -4305))
|
||||||
|
|
||||||
|
def test_clocks_with_negative_hours_and_minutes(self):
|
||||||
|
self.assertEqual(Clock(7, 32), Clock(-12, -268))
|
||||||
|
|
||||||
|
def test_clocks_with_negative_hours_and_minutes_that_wrap(self):
|
||||||
|
self.assertEqual(Clock(18, 7), Clock(-54, -11513))
|
||||||
|
|
||||||
|
def test_full_clock_and_zeroed_clock(self):
|
||||||
|
self.assertEqual(Clock(24, 0), Clock(0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user