primeiro commit com exercicios de Exercism realizados até esta data
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"authors": [
|
||||
"J08K"
|
||||
],
|
||||
"contributors": [
|
||||
"BethanyG",
|
||||
"kytrinyx",
|
||||
"meatball133"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"generators.py"
|
||||
],
|
||||
"test": [
|
||||
"generators_test.py"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.py"
|
||||
]
|
||||
},
|
||||
"icon": "new-passport",
|
||||
"blurb": "Learn about generators by assigning seats to passengers on Anaconda Airlines."
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"track":"python","exercise":"plane-tickets","id":"754d7ba9211d45619b389d7835720cbd","url":"https://exercism.org/tracks/python/exercises/plane-tickets","handle":"sanctushck","is_requester":true,"auto_approve":false}
|
||||
@@ -0,0 +1,130 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
We use [pytest][pytest: Getting Started Guide] as our website test runner.
|
||||
You will need to install `pytest` on your development machine if you want to run tests for the Python track locally.
|
||||
You should also install the following `pytest` plugins:
|
||||
|
||||
- [pytest-cache][pytest-cache]
|
||||
- [pytest-subtests][pytest-subtests]
|
||||
|
||||
Extended information can be found in our website [Python testing guide][Python track tests page].
|
||||
|
||||
|
||||
### Running Tests
|
||||
|
||||
To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_).
|
||||
Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded.
|
||||
|
||||
Linux/MacOS
|
||||
```bash
|
||||
$ cd {path/to/exercise-folder-location}
|
||||
```
|
||||
|
||||
Windows
|
||||
```powershell
|
||||
PS C:\Users\foobar> cd {path\to\exercise-folder-location}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file:
|
||||
|
||||
Linux/MacOS
|
||||
```bash
|
||||
$ python3 -m pytest -o markers=task {exercise_test.py}
|
||||
==================== 7 passed in 0.08s ====================
|
||||
```
|
||||
|
||||
Windows
|
||||
```powershell
|
||||
PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py}
|
||||
==================== 7 passed in 0.08s ====================
|
||||
```
|
||||
|
||||
|
||||
### Common options
|
||||
- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_)
|
||||
- `-v` : enable verbose output.
|
||||
- `-x` : stop running tests on first failure.
|
||||
- `--ff` : run failures from previous test before running other test cases.
|
||||
|
||||
For additional options, use `python3 -m pytest -h` or `py -m pytest -h`.
|
||||
|
||||
|
||||
### Fixing warnings
|
||||
|
||||
If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax:
|
||||
|
||||
```bash
|
||||
PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html
|
||||
```
|
||||
|
||||
To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file.
|
||||
We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini].
|
||||
|
||||
You can also create your own `pytest.ini` file with the following content:
|
||||
|
||||
```ini
|
||||
[pytest]
|
||||
markers =
|
||||
task: A concept exercise task.
|
||||
```
|
||||
|
||||
Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings.
|
||||
More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers].
|
||||
|
||||
Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats].
|
||||
|
||||
|
||||
### Extending your IDE or Code Editor
|
||||
|
||||
Many IDEs and code editors have built-in support for using `pytest` and other code quality tools.
|
||||
Some community-sourced options can be found on our [Python track tools page][Python track tools page].
|
||||
|
||||
[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html
|
||||
[Python track tools page]: https://exercism.org/docs/tracks/python/tools
|
||||
[Python track tests page]: https://exercism.org/docs/tracks/python/tests
|
||||
[pytest-cache]:http://pythonhosted.org/pytest-cache/
|
||||
[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests
|
||||
[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini
|
||||
[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats
|
||||
[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks
|
||||
[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit generators.py` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [Python track's documentation](https://exercism.org/docs/tracks/python)
|
||||
- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
Below are some resources for getting help if you run into trouble:
|
||||
|
||||
- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources.
|
||||
- [The Exercism Community on Discord](https://exercism.org/r/discord)
|
||||
- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community.
|
||||
- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners.
|
||||
- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done.
|
||||
- [Python Community Forums](https://discuss.python.org/)
|
||||
- [Free Code Camp Community Forums](https://forum.freecodecamp.org/)
|
||||
- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help)
|
||||
- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually.
|
||||
|
||||
Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already.
|
||||
If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Hints
|
||||
|
||||
## 1. Generate seat letters
|
||||
|
||||
- The returned value should be of _type_ `generator`.
|
||||
- You can have a sequence of letters from `A` to `D` and cycle through them.
|
||||
- Use `yield` to return the next letter.
|
||||
|
||||
## 2. Generate seats
|
||||
|
||||
- The returned value should be of _type_ `generator`.
|
||||
- Row `13` should be skipped, so go from `12` to `14`.
|
||||
- Keep in mind that the returned values should be ordered from low to high. `1A, 1B, 2A, ...`
|
||||
- Here it might be good to reuse or call functions you have already defined.
|
||||
|
||||
## 3. Assign seats to passengers
|
||||
|
||||
- Make sure your seat numbers do not have any spaces in them.
|
||||
- Here it might be good to reuse or call functions you have already defined.
|
||||
|
||||
## 4. Ticket codes
|
||||
|
||||
- You can use `len()` to get the length of a string.
|
||||
- You can use `"<string>" * <int>` to repeat a string.
|
||||
@@ -0,0 +1,265 @@
|
||||
# Plane Tickets
|
||||
|
||||
Welcome to Plane Tickets on Exercism's Python Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||
|
||||
## Introduction
|
||||
|
||||
A `generator` is a function or expression that returns a special type of [iterator][iterator] called [generator iterator][generator-iterator].
|
||||
`Generator-iterators` are [lazy][lazy iterator]: they do not store their `values` in memory, but _generate_ their values when needed.
|
||||
|
||||
A generator function looks like any other function, but contains one or more [yield expressions][yield expression].
|
||||
Each `yield` will suspend code execution, saving the current execution state (_including all local variables and try-statements_).
|
||||
When the generator resumes, it picks up state from the suspension - unlike regular functions which reset with every call.
|
||||
|
||||
|
||||
## Constructing a generator
|
||||
|
||||
Generators are constructed much like other looping or recursive functions, but require a [`yield` expression](#the-yield-expression), which we will explore in depth a bit later.
|
||||
|
||||
An example is a function that returns the _squares_ from a given list of numbers.
|
||||
As currently written, all input must be processed before any values can be returned:
|
||||
|
||||
```python
|
||||
>>> def squares(list_of_numbers):
|
||||
... squares = []
|
||||
... for number in list_of_numbers:
|
||||
... squares.append(number ** 2)
|
||||
... return squares
|
||||
```
|
||||
|
||||
You can convert that function into a generator like this:
|
||||
|
||||
```python
|
||||
>>> def squares_generator(list_of_numbers):
|
||||
... for number in list_of_numbers:
|
||||
... yield number ** 2
|
||||
```
|
||||
|
||||
The rationale behind this is that you use a generator when you do not need to produce all the values _at once_.
|
||||
This saves memory and processing power, since only the value you are _currently working on_ is calculated.
|
||||
|
||||
|
||||
## Using a generator
|
||||
|
||||
Generators may be used in place of most `iterables` in Python.
|
||||
This includes _functions_ or _objects_ that require an `iterable`/`iterator` as an argument.
|
||||
|
||||
To use the `squares_generator()` generator:
|
||||
|
||||
```python
|
||||
>>> squared_numbers = squares_generator([1, 2, 3, 4])
|
||||
|
||||
>>> for square in squared_numbers:
|
||||
... print(square)
|
||||
...
|
||||
1
|
||||
4
|
||||
9
|
||||
16
|
||||
```
|
||||
|
||||
Values within a `generator` can also be produced/accessed via the `next()` function.
|
||||
`next()` calls the `__next__()` method of a generator-iterator object, "advancing" or evaluating the code up to its `yield` expression, which then "yields" or returns a value:
|
||||
|
||||
```python
|
||||
>>> squared_numbers = squares_generator([1, 2])
|
||||
|
||||
>>> next(squared_numbers)
|
||||
1
|
||||
>>> next(squared_numbers)
|
||||
4
|
||||
```
|
||||
|
||||
When a `generator-iterator` is fully consumed and has no more values to return, it throws a `StopIteration` error.
|
||||
|
||||
```python
|
||||
>>> next(squared_numbers)
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
StopIteration
|
||||
```
|
||||
|
||||
|
||||
~~~~exercism/note
|
||||
|
||||
Generator-iterators are a special sub-set of [iterators][iterator].
|
||||
`Iterators` are the mechanism/protocol that enables looping over _iterables_.
|
||||
Generator-iterators and the iterators returned by common Python [`iterables`][iterables] act very similarly, but there are some important differences to note:
|
||||
|
||||
- They are _[lazily evaluated][lazy evaluation]_; iteration is _one-way_ and there is no "backing up" to a previous value.
|
||||
- They are _consumed_ by iterating over the returned values; there is no resetting or saving in memory.
|
||||
- They are not sortable and cannot be reversed.
|
||||
- They are not sequence types, and _do not_ have `indexes`.
|
||||
You cannot reference a previous or future value using addition or subtraction and you cannot use bracket (`[]`) notation or slicing.
|
||||
- They cannot be used with the `len()` function, as they have no length.
|
||||
- They can be _finite_ or _infinite_ - be careful when collecting all values from an _infinite_ `generator-iterator`!
|
||||
|
||||
[iterator]: https://docs.python.org/3.11/glossary.html#term-iterator
|
||||
[iterables]: https://wiki.python.org/moin/Iterator
|
||||
[lazy evaluation]: https://en.wikipedia.org/wiki/Lazy_evaluation
|
||||
~~~~
|
||||
|
||||
|
||||
## The yield expression
|
||||
|
||||
The [yield expression][yield expression] is very similar to the `return` expression.
|
||||
_Unlike_ the `return` expression, `yield` gives up values to the caller at a _specific point_, suspending evaluation/return of any additional values until they are requested.
|
||||
When `yield` is evaluated, it pauses the execution of the enclosing function and returns any values of the function _at that point in time_.
|
||||
The function then _stays in scope_, and when `__next__()` is called, execution resumes until `yield` is encountered again.
|
||||
|
||||
|
||||
~~~~exercism/note
|
||||
Using `yield` expressions is prohibited outside of functions.
|
||||
~~~~
|
||||
|
||||
```python
|
||||
>>> def infinite_sequence():
|
||||
... current_number = 0
|
||||
... while True:
|
||||
... yield current_number
|
||||
... current_number += 1
|
||||
|
||||
>>> lets_try = infinite_sequence()
|
||||
>>> lets_try.__next__()
|
||||
0
|
||||
>>> lets_try.__next__()
|
||||
1
|
||||
```
|
||||
|
||||
|
||||
## Why Create a Generator?
|
||||
|
||||
Generators are useful in a lot of applications.
|
||||
|
||||
When working with a potentially large collection of values, you might not want to put all of them into memory.
|
||||
A generator can be used to work on larger data piece-by-piece, saving memory and improving performance.
|
||||
|
||||
Generators are also very helpful when a process or calculation is _complex_, _expensive_, or _infinite_:
|
||||
|
||||
```python
|
||||
>>> def infinite_sequence():
|
||||
... current_number = 0
|
||||
... while True:
|
||||
... yield current_number
|
||||
... current_number += 1
|
||||
```
|
||||
|
||||
Now whenever `__next__()` is called on the `infinite_sequence` object, it will return the _previous number_ + 1.
|
||||
|
||||
|
||||
[generator-iterator]: https://docs.python.org/3.11/glossary.html#term-generator-iterator
|
||||
[iterables]: https://wiki.python.org/moin/Iterator
|
||||
[iterator]: https://docs.python.org/3.11/glossary.html#term-iterator
|
||||
[lazy evaluation]: https://en.wikipedia.org/wiki/Lazy_evaluation
|
||||
[lazy iterator]: https://en.wikipedia.org/wiki/Lazy_evaluation
|
||||
[yield expression]: https://docs.python.org/3.11/reference/expressions.html#yield-expressions
|
||||
|
||||
## Instructions
|
||||
|
||||
Conda Airlines is the programming-world's biggest airline, with over 10,000 flights a day!
|
||||
|
||||
They are currently assigning all seats to passengers by hand; this will need to be automated.
|
||||
|
||||
They have asked _you_ to create software to automate passenger seat assignments.
|
||||
They require your software to be memory efficient and performant.
|
||||
|
||||
## 1. Generate seat letters
|
||||
|
||||
Conda wants to generate seat letters for their airplanes.
|
||||
An airplane is made of rows of seats.
|
||||
Each row has _4 seats_.
|
||||
The seats in each row are always named `A`, `B`, `C`, and `D`.
|
||||
The first seat in the row is `A`, the second seat in the row is `B`, and so on.
|
||||
After reaching `D`, it should start again with `A`.
|
||||
|
||||
Implement a function `generate_seat_letters(<number>)` that accepts an `int` that holds how many seat letters to be generated.
|
||||
The function should then return an _iterable_ of seat letters.
|
||||
|
||||
```python
|
||||
>>> letters = generate_seat_letters(4)
|
||||
>>> next(letters)
|
||||
"A"
|
||||
>>> next(letters)
|
||||
"B"
|
||||
```
|
||||
|
||||
## 2. Generate seats
|
||||
|
||||
Conda wants a system that can generate a given number of seats for their airplanes.
|
||||
Each airplane has _4 seats_ in each row.
|
||||
The rows are defined using numbers, starting from `1` and going up.
|
||||
The seats should be ordered, like: `1A`, `1B`, `1C`, `1D`, `2A`, `2B`, `2C`, `2D`, `3A`, `3B`, `3C`, `3D`, ...
|
||||
|
||||
Here is an example:
|
||||
|
||||
| x | 1 | 2 |
|
||||
| :---------: | :-: | :-: |
|
||||
| Row | 5 | 21 |
|
||||
| Seat letter | A | D |
|
||||
| Result | 5A | 21D |
|
||||
|
||||
Many airlines do not have _row_ number 13 on their flights, due to superstition amongst passengers.
|
||||
Conda Airlines also follows this convention, so make sure you _don't_ generate seats for _row_ number 13.
|
||||
|
||||
Implement a function `generate_seats(<number>)` that accepts an `int` that holds how many seats to be generated.
|
||||
The function should then return an _iterable_ of seats given.
|
||||
|
||||
```python
|
||||
>>> seats = generate_seats(10)
|
||||
>>> next(seats)
|
||||
"1A"
|
||||
>>> next(seats)
|
||||
"1B"
|
||||
```
|
||||
|
||||
## 3. Assign seats to passengers
|
||||
|
||||
Now that you have a function that generates seats, you can use it to assign seats to passengers.
|
||||
|
||||
Implement a function `assign_seats(<passengers>)` that accepts a `list` of passenger names.
|
||||
The function should then return a _dictionary_ of `passenger` as _key_, and `seat_number` as _value_.
|
||||
|
||||
```python
|
||||
>>> passengers = ['Jerimiah', 'Eric', 'Bethany', 'Byte', 'SqueekyBoots', 'Bob']
|
||||
|
||||
>>> assign_seats(passengers)
|
||||
{'Jerimiah': '1A', 'Eric': '1B', 'Bethany': '1C', 'Byte': '1D', 'SqueekyBoots': '2A', 'Bob': '2B'}
|
||||
```
|
||||
|
||||
## 4. Ticket codes
|
||||
|
||||
Conda Airlines would like to have a unique code for each ticket.
|
||||
Since they are a big airline, they have a lot of flights.
|
||||
This means that there are multiple flights with the same seat number.
|
||||
They want you to create a system that creates a unique ticket that is _12_ characters long string code for identification.
|
||||
|
||||
This code begins with the `assigned_seat` followed by the `flight_id`.
|
||||
The rest of the code is appended by `0s`.
|
||||
|
||||
Implement a function `generate_codes(<seat_numbers>, <flight_id>)` that accepts a `list` of `seat_numbers` and a `string` with the flight number.
|
||||
The function should then return a `generator` that yields a `ticket_number`.
|
||||
|
||||
```python
|
||||
>>> seat_numbers = ['1A', '17D']
|
||||
>>> flight_id = 'CO1234'
|
||||
>>> ticket_ids = generate_codes(seat_numbers, flight_id)
|
||||
|
||||
>>> next(ticket_ids)
|
||||
'1ACO12340000'
|
||||
>>> next(ticket_ids)
|
||||
'17DCO1234000'
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @J08K
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @BethanyG
|
||||
- @kytrinyx
|
||||
- @meatball133
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,72 @@
|
||||
"""Functions to automate Conda airlines ticketing system."""
|
||||
|
||||
|
||||
def generate_seat_letters(number):
|
||||
"""Generate a series of letters for airline seats.
|
||||
|
||||
:param number: int - total number of seat letters to be generated.
|
||||
:return: generator - generator that yields seat letters.
|
||||
|
||||
Seat letters are generated from A to D.
|
||||
After D it should start again with A.
|
||||
|
||||
Example: A, B, C, D
|
||||
|
||||
"""
|
||||
seat_letters: list = ["A", "B", "C", "D"]
|
||||
for seat_number in range(number):
|
||||
yield seat_letters[seat_number % len(seat_letters)]
|
||||
|
||||
|
||||
def generate_seats(number):
|
||||
"""Generate a series of identifiers for airline seats.
|
||||
|
||||
:param number: int - total number of seats to be generated.
|
||||
:return: generator - generator that yields seat numbers.
|
||||
|
||||
A seat number consists of the row number and the seat letter.
|
||||
|
||||
There is no row 13.
|
||||
Each row has 4 seats.
|
||||
|
||||
Seats should be sorted from low to high.
|
||||
|
||||
Example: 3C, 3D, 4A, 4B
|
||||
|
||||
"""
|
||||
seat_letters = generate_seat_letters(number)
|
||||
row_number = 1
|
||||
for seat_number in range(number):
|
||||
if not seat_number % 4 and seat_number > 0:
|
||||
row_number += 1
|
||||
if row_number == 13:
|
||||
row_number += 1
|
||||
yield f"{row_number}{next(seat_letters)}"
|
||||
|
||||
|
||||
def assign_seats(passengers):
|
||||
"""Assign seats to passengers.
|
||||
|
||||
:param passengers: list[str] - a list of strings containing names of passengers.
|
||||
:return: dict - with the names of the passengers as keys and seat numbers as values.
|
||||
|
||||
Example output: {"Adele": "1A", "Björk": "1B"}
|
||||
|
||||
"""
|
||||
seats = generate_seats(len(passengers))
|
||||
assign_seats_dict: dict = {}
|
||||
for passenger in passengers:
|
||||
assign_seats_dict[passenger] = next(seats)
|
||||
return assign_seats_dict
|
||||
|
||||
|
||||
def generate_codes(seat_numbers, flight_id):
|
||||
"""Generate codes for a ticket.
|
||||
|
||||
:param seat_numbers: list[str] - list of seat numbers.
|
||||
:param flight_id: str - string containing the flight identifier.
|
||||
:return: generator - generator that yields 12 character long ticket codes.
|
||||
|
||||
"""
|
||||
for seat in seat_numbers:
|
||||
yield f"{seat}{flight_id}".ljust(12, "0")
|
||||
@@ -0,0 +1,140 @@
|
||||
import inspect
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from generators import (
|
||||
generate_seat_letters,
|
||||
generate_seats,
|
||||
assign_seats,
|
||||
generate_codes
|
||||
)
|
||||
|
||||
class PlaneTicketsTest(unittest.TestCase):
|
||||
@pytest.mark.task(taskno=1)
|
||||
def test_task1_returns_generator(self):
|
||||
"""Test if generate_seat_letters() returns a generator type."""
|
||||
|
||||
number = 5
|
||||
error_message = (f'Called generate_seat_letters({number}). '
|
||||
f'The function returned a {type(generate_seat_letters(number))} type, '
|
||||
f"but the tests expected the function to return a <class 'generator'> type.")
|
||||
|
||||
self.assertTrue(inspect.isgenerator(generate_seat_letters(number)), msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=1)
|
||||
def test_generate_seat_letters(self):
|
||||
test_data = [1, 2, 3, 4, 5]
|
||||
result_data = [["A"],
|
||||
["A", "B"],
|
||||
["A", "B", "C"],
|
||||
["A", "B", "C", "D"],
|
||||
["A", "B", "C", "D", "A"]]
|
||||
|
||||
for variant, (number, expected) in enumerate(zip(test_data, result_data), start=1):
|
||||
with self.subTest(f"variation #{variant}", number=number, expected=expected):
|
||||
actual_result = list(generate_seat_letters(number))
|
||||
error_message = (f'Called generate_seat_letters({number}). '
|
||||
f'The function returned {actual_result}, but the tests '
|
||||
f'expected {expected} when generating {number} seat(s).')
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=2)
|
||||
def test_task2_returns_generator(self):
|
||||
"""Test if generate_seats() returns a generator type."""
|
||||
|
||||
number = 7
|
||||
error_message = (f'Called generate_seats({number}). '
|
||||
f'The function returned a {type(generate_seats(number))} type, '
|
||||
f"but the tests expected the function to return a <class 'generator'> type.")
|
||||
|
||||
self.assertTrue(inspect.isgenerator(generate_seats(number)), msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=2)
|
||||
def test_generate_seats(self):
|
||||
test_data = [1, 2, 3, 4, 5]
|
||||
result_data = [["1A"],
|
||||
["1A", "1B"],
|
||||
["1A", "1B", "1C"],
|
||||
["1A", "1B", "1C", "1D"],
|
||||
["1A", "1B", "1C", "1D", "2A"]]
|
||||
|
||||
for variant, (number, expected) in enumerate(zip(test_data, result_data), start=1):
|
||||
with self.subTest(f"variation #{variant}", number=number, expected=expected):
|
||||
actual_result = list(generate_seats(number))
|
||||
error_message = (f'Called generate_seats({number}). '
|
||||
f'The function returned {actual_result}, but the tests '
|
||||
f'expected {expected} when generating {number} seat(s).')
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=2)
|
||||
def test_generate_seats_skips_row_13(self):
|
||||
test_data = [14 * 4]
|
||||
result_data = [["1A", "1B", "1C", "1D", "2A", "2B", "2C", "2D",
|
||||
"3A", "3B", "3C", "3D", "4A", "4B", "4C", "4D",
|
||||
"5A", "5B", "5C", "5D", "6A", "6B", "6C", "6D",
|
||||
"7A", "7B", "7C", "7D", "8A", "8B", "8C", "8D",
|
||||
"9A", "9B", "9C", "9D", "10A", "10B", "10C", "10D",
|
||||
"11A", "11B", "11C", "11D", "12A", "12B", "12C", "12D",
|
||||
"14A", "14B", "14C", "14D", "15A", "15B", "15C", "15D"]]
|
||||
|
||||
for variant, (number, expected) in enumerate(zip(test_data, result_data), start=1):
|
||||
with self.subTest(f"variation #{variant}", number=number, expected=expected):
|
||||
actual_result = list(generate_seats(number))
|
||||
error_message = (f'Called generate_seats({number}). '
|
||||
f'The function returned {actual_result}, but the tests '
|
||||
f'expected: {expected}, when generating {number} seat(s).')
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=3)
|
||||
def test_assign_seats(self):
|
||||
test_data = [["Passenger1", "Passenger2", "Passenger3", "Passenger4", "Passenger5"],
|
||||
["TicketNo=5644", "TicketNo=2273", "TicketNo=493", "TicketNo=5411", "TicketNo=824"]]
|
||||
result_data = [{"Passenger1": "1A", "Passenger2": "1B",
|
||||
"Passenger3": "1C", "Passenger4": "1D", "Passenger5": "2A"},
|
||||
{"TicketNo=5644": "1A", "TicketNo=2273": "1B",
|
||||
"TicketNo=493": "1C", "TicketNo=5411": "1D", "TicketNo=824": "2A"}]
|
||||
|
||||
for variant, (passengers, expected) in enumerate(zip(test_data, result_data), start=1):
|
||||
with self.subTest(f"variation #{variant}", passengers=passengers, expected=expected):
|
||||
actual_result = assign_seats(passengers)
|
||||
error_message = (f'Called assign_seats({passengers}). '
|
||||
f'The function returned {actual_result}, but the tests '
|
||||
f'expected {expected}, when assigning seats.')
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=4)
|
||||
def test_task4_returns_generator(self):
|
||||
"""Test if generate_codes() returns a generator type."""
|
||||
|
||||
seat_numbers, flight_id = "11B", "HA80085"
|
||||
error_message = (f'Called generate_codes({seat_numbers}, {flight_id}). '
|
||||
f'The function returned a {type(generate_codes(seat_numbers, flight_id))} type, '
|
||||
f"but the tests expected the function to return a <class 'generator'> type.")
|
||||
|
||||
self.assertTrue(inspect.isgenerator(generate_codes(seat_numbers, flight_id)), msg=error_message)
|
||||
|
||||
|
||||
@pytest.mark.task(taskno=4)
|
||||
def test_generate_codes(self):
|
||||
test_data = [(["12A", "38B", "69C", "102B"],"KL1022"),
|
||||
(["22C", "88B", "33A", "44B"], "DL1002")]
|
||||
result_data = [['12AKL1022000', '38BKL1022000', '69CKL1022000', '102BKL102200'],
|
||||
['22CDL1002000', '88BDL1002000', '33ADL1002000', '44BDL1002000']]
|
||||
|
||||
for variant, ((seat_numbers, flight_id), expected) in enumerate(zip(test_data, result_data), start=1):
|
||||
with self.subTest(f"variation #{variant}", seat_numbbers=seat_numbers,
|
||||
flight_id=flight_id, expected=expected):
|
||||
|
||||
actual_result = list(generate_codes(seat_numbers, flight_id))
|
||||
error_message = (f'Called generate_codes({seat_numbers}, {flight_id}). '
|
||||
f'The function returned {actual_result}, but the tests '
|
||||
f'expected {expected} when generating ticket numbers.')
|
||||
|
||||
# Note: DO NOT call the function here again, in case the student is using list.pop()
|
||||
# to process the input. If another call is done with that condition,
|
||||
# the test will fail with a terrible error message.
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
Reference in New Issue
Block a user