Ще започнем с един любопитен факт. Освен [песента на Skrillex](https://www.youtube.com/watch?v=YJVmu6yttiw), Bangarang се споменава за първи път в поп културата още през 1991 във филма [Hook](https://www.youtube.com/watch?v=G87uIh9ISWU). 25 години по-късно му добавяме едно "a" и получаваме [Bangaranga](https://i.redd.it/jp7b25ekmbmg1.jpeg)!
За да не останем назад със събитията, решихме да нахвърляме едно последно домашно за вас, да не ви е скучно покрай празника. И ако някой се е чудил къде е Коцето...

#### Задачата
За да не ви е за сефте на проектите, ще искаме от вас да напишете малко тестове. Ние пишем функционалността, вие пишете тестове, използвайки преподадения до момента материал _(testing framework)_.
Ние ще подготвим функцията `does_the_banga_rang`, за която имаме следните изисквания:
- Приема име на файл.
- Чете файла.
- Проверява дали в него се съдържат цели "думи", които да могат да сформират _(сформират ще рече - конкатенират изцяло)_ низа `"bangaranga"`. Т.е. ако в съдържанието на файла имаме `"The banga is doing some ranga!"` - това съдържа `"banga" + "ranga" = "bangaranga"`. Ако имаме `"Does the banga rang?"` - нямаме такива думи.
- "Думи" в този контекст са низове от латински букви, които са оградени от `r"\b"`, както в регулярните изрази, т.е. `r"\b[a-z]+\b"`. Алгоритъмът е case-insensitive.
- Думите трябва да са в точната последователност из съдържанието на файла. Т.е. `"banga is ranga"` е валидно, но `"ranga is banga"` - не.
- Функцията връща число, равно на **минималния** брой отделни думи, които сформират `"bangaranga"`. Например:
```
# 2.txt
banga the ranga
```
```
# 3.txt
bang a small ranga
```
```
# multiple.txt
bang a banga ranga bangaranga
```
```
# питонски файл или REPL
print(does_the_banga_rang("2.txt")) # 2
print(does_the_banga_rang("3.txt")) # 3
print(does_the_banga_rang("multiple.txt")) # 1 - bangaranga
```
- Ако файлът не съдържа думи, които да удовлетворяват изискването за `"bangaranga"` - функцията връща `0` - `does_the_banga_rang("some_file_without_bangaranga.txt") # 0`.
- Ако има проблем с четенето от файла - `OSError` или `IOError` - искаме да се хвърли грешката `TheBangaDoesNotRangError`, дефинирана в същия файл, както функцията.
И отново - **вие няма да пишете `does_the_banga_rang`, това ще го напишем ние. Вашата задача е, да напишете тестове за въпросната функция**.
#### Тестовете
Очевидно не знаете каква ще е имплементацията на функцията `does_the_banga_rang`, така че тестовете ви ще трябва да са black-box (както е редно за unit тестове). В тестовете си импортирайте така:
```
from bangaranga import does_the_banga_rang, TheBangaDoesNotRangError
```
##### Какво се очаква от вашите тестове?
- Вашите тестове трябва да проверяват публичното поведение на функцията според описаните по-горе изисквания.
- За да бъде един test suite надежден, той трябва да минава успешно срещу коректната имплементация.
- И също така да се проваля срещу некоректни имплементации, когато те нарушават изискванията.
- Не пишете повече от 12 теста. Дори и по-малко биха покрили целия набор от изисквания, който сме дефинирали по-горе
- Очакваме не просто тестовете ви да минат (или фейлнат, в зависимост от обстоятелствата), а да спазите добрите практики и насоки, които сме обяснили в лекциите за тестване и проведените live coding workshop-и - атомарност и автономност на тестовете, липса на странични ефекти и т.н. Тази точка ще оценяваме ръчно с допълнителни или наказателни точки, отвъд резултата от автоматизираните тестове.
Помислете какви входове биха доказали, че функцията спазва описаните изисквания.
Добрият test suite обикновено проверява:
- нормални случаи;
- гранични случаи;
- случаи, в които няма валидно решение;
- случаи, в които очакваме грешка.
С други думи - не е достатъчно да тествате само примерите от условието.