1import io
2import sys
3import unittest
4
5
6class StdBuffer:
7 def __init__(self):
8 self.buffer = io.StringIO()
9
10 def __enter__(self):
11 self.stds = sys.stdin, sys.stderr, sys.stdout
12 sys.stdin = self.buffer
13 sys.stderr = self.buffer
14 sys.stdout = self.buffer
15
16 def __exit__(self, *args, **kwargs):
17 sys.stdin, sys.stderr, sys.stdout = self.stds
18
19
20class TestSanity(unittest.TestCase):
21 """Check if the test class is present."""
22
23 def setUp(cls):
24 # Importing the test dynamically to prevent including them
25 # in the scoring test suite
26 with StdBuffer():
27 cls.solution = __import__('solution')
28
29 def test_sanity(self):
30 self.assertIn('TestNikuldenValidator', dir(self.solution), 'Убеди се, че класът "TestNikuldenValidator" е наличен с точно това име.')
31 self.assertIn('test_valid_recipe', dir(self.solution.TestNikuldenValidator), 'Убеди се, че методът "test_valid_recipe" е наличен с точно това име.')
32 self.assertIn('test_invalid_recipe', dir(self.solution.TestNikuldenValidator), 'Убеди се, че методът "test_invalid_recipe" е наличен с точно това име.')
33 self.assertIn('test_bad_recipe_file', dir(self.solution.TestNikuldenValidator), 'Убеди се, че методът "test_bad_recipe_file" е наличен с точно това име.')
34
35
36if __name__ == "__main__":
37 suite = unittest.TestSuite()
38 suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestSanity))
39 runner = unittest.TextTestRunner()
40 runner.run(suite)
1import re
2import unittest
3from unittest.mock import patch
4
5import secret
6from secret import FISH_OPTIONS, RuinedNikuldenDinnerError
7
8
9def validate_recipe_no_lower(recipe_file_path):
10 """Implementation missing lower."""
11 try:
12 with open(recipe_file_path) as recipe_file:
13 recipe_text = recipe_file.read()
14 except (IOError, OSError):
15 raise RuinedNikuldenDinnerError
16 return bool(re.search(fr'\b({"|".join(FISH_OPTIONS)})\b', recipe_text))
17
18def validate_recipe_no_error_handling(recipe_file_path):
19 """Implementation missing error handling."""
20 with open(recipe_file_path) as recipe_file:
21 recipe_text = recipe_file.read()
22 return bool(re.search(fr'\b({"|".join(FISH_OPTIONS)})\b', recipe_text, re.I))
23
24def validate_recipe_naive_in(recipe_file_path):
25 """Implementation missing split when reading."""
26 try:
27 with open(recipe_file_path) as recipe_file:
28 recipe_text = recipe_file.read().lower()
29 except (IOError, OSError):
30 raise RuinedNikuldenDinnerError
31 return any(fish in recipe_text for fish in FISH_OPTIONS)
32
33
34class TestTestNikuldenValidator(unittest.TestCase):
35 """Test the tests for validate_recipe."""
36
37 def setUp(cls):
38 # Importing the test dynamically to prevent including them
39 # in the scoring test suite
40 cls.TestNikuldenValidator = __import__('solution').TestNikuldenValidator
41
42 TEST_NAMES = {'test_valid_recipe', 'test_invalid_recipe', 'test_bad_recipe_file'}
43
44 def test_valid_validator(self):
45 """Test with a valid implementation."""
46 for test_name in self.TEST_NAMES:
47 with patch('solution.validate_recipe',
48 side_effect=secret.validate_recipe) as mock_validate_recipe:
49 result = self.TestNikuldenValidator(test_name)()
50 self.assertTrue(result.wasSuccessful(),
51 f"Expecting {test_name} to pass with valid implementation.")
52 mock_validate_recipe.assert_called()
53
54 def test_no_lower_validator(self):
55 """Test with implementation missing lower."""
56 expected_failure = 'test_valid_recipe'
57 for test_name in self.TEST_NAMES:
58 with patch('solution.validate_recipe',
59 side_effect=validate_recipe_no_lower) as mock_validate_recipe:
60 result = self.TestNikuldenValidator(test_name)()
61 if test_name == expected_failure:
62 self.assertFalse(result.wasSuccessful(),
63 f"Expecting {test_name} to fail with an implementation missing lower.")
64 else:
65 self.assertTrue(result.wasSuccessful(),
66 f"Expecting {test_name} to pass with an implementation missing lower.")
67 mock_validate_recipe.assert_called()
68
69 def test_no_error_handling_validator(self):
70 """Test with implementation missing error handling."""
71 expected_failure = 'test_bad_recipe_file'
72 for test_name in self.TEST_NAMES:
73 with patch('solution.validate_recipe',
74 side_effect=validate_recipe_no_error_handling) as mock_validate_recipe:
75 result = self.TestNikuldenValidator(test_name)()
76 if test_name == expected_failure:
77 self.assertFalse(result.wasSuccessful(),
78 f"Expecting {test_name} to fail with an implementation with error handling.")
79 else:
80 self.assertTrue(result.wasSuccessful(),
81 f"Expecting {test_name} to pass with an implementation with error handling.")
82 mock_validate_recipe.assert_called()
83
84 def test_naive_in_validator(self):
85 """Test with implementation missing word splits."""
86 expected_failure = 'test_invalid_recipe'
87 for test_name in self.TEST_NAMES:
88 with patch('solution.validate_recipe',
89 side_effect=validate_recipe_naive_in) as mock_validate_recipe:
90 result = self.TestNikuldenValidator(test_name)()
91 if test_name == expected_failure:
92 self.assertFalse(result.wasSuccessful(),
93 f"Expecting {test_name} to fail with an implementation missing word splits.")
94 else:
95 self.assertTrue(result.wasSuccessful(),
96 f"Expecting {test_name} to pass with an implementation missing word splits.")
97 mock_validate_recipe.assert_called()
98
99
100if __name__ == '__main__':
101 suite = unittest.TestSuite()
102 suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestTestNikuldenValidator))
103 runner = unittest.TextTestRunner()
104 runner.run(suite)
Виктор Бечев
07.12.2024 12:41Генерална бележка за решенията на предизвикателството, цитирано от PEP8:
Surround **top-level** function and class definitions with **two** blank lines.
_Method definitions inside a class_ are surrounded by a _single_ blank line.
Extra blank lines may be used **(sparingly)** to separate groups of related functions. Blank lines may be omitted between a bunch of related one-liners (e.g. a set of dummy implementations).
Use blank lines in functions, **sparingly**, to indicate logical sections.
Най-честите "нарушения" са липсата на два реда за top-level дефиниции (това са импорти, константи, променливи, функции, класове, "хвърчащ" код като `if __name__ == ...`) и вече по-малко - прекалено либерална употреба на нови редове в тялото на функции / методи.
| |
| |
Павел Петков
06.12.2024 14:47рибаааа валидно срещане ли е , защото текста съдържа риба или искаме риба да е отделна дума?
| |
Йоан Байчев
05.12.2024 02:29Нека разлгедаме примерното множеството {тор, Тор, тОр, тоР, ТОр, тОР, ТоР, ТОР}, то трябва ли да бъде асоцирано с думата "тор" спрямо case-insensitive или {тор, Тор} съответно? Относно съдържанието на файла, ние реално се интересуваме от това дали има някоя или няколко от "специалните думи" някъде във файла, тоест при наличие на нелогични думи, числа, специални символи и други, очакваното поведение на функцията би било да върне истина, ако "специална дума" бъде разпозната въпреки това? Примерът с "рибена глава", го разбирам, че функцията трябва да игнорира дума, която в себе си съдържа "специална дума" (префикс, инфикс и суфикс на нея).
Нишка
| |
Виктор Бечев
05.12.2024 01:32Един дисклеймър - досега не сме давали задача свързана с писане на тестове, така че го приемете като нещо експериментално.
Да видим как ще се получи...
|