1import unittest
2
3import solution
4
5
6class TestSanity(unittest.TestCase):
7 """Check if the function is present."""
8
9 def test_interfaces(self):
10 self.assertIn('type_check', dir(solution), 'Убеди се, че функцията "type_check" е налична с точно това име.')
11 self.assertTrue(callable(solution.type_check), 'Убеди се, че "type_check" е функция.')
12
13
14if __name__ == '__main__':
15 unittest.main()
1import itertools
2import unittest
3from unittest.mock import call, patch
4
5from solution import type_check
6
7
8def join_collections(*collections):
9 result = []
10 for collection in collections:
11 result.extend(collection)
12 return result
13
14def nothing():
15 pass
16
17def lonely_island(main_character, supporting_character, **kwargs):
18 return f"This is the tale of {main_character} and {supporting_character}!"
19
20def divide_by_zero(numbers):
21 return [number / 0 for number in numbers]
22
23
24class TestTypeCheck(unittest.TestCase):
25 """Test the function of the decorator."""
26
27 BASE_STRING_IN = "Invalid input arguments, expected {}!"
28 BASE_STRING_OUT = "Invalid output value, expected {}!"
29
30 def assert_in_permutations(self, call, types, inout_string):
31 """Check if call is in a list of all permutations of the types."""
32 types_permutations = itertools.permutations(types)
33 types_strings = [", ".join(str(_type) for _type in perm) for perm in types_permutations]
34 call_permutations = [call(inout_string.format(types_string)) for types_string in types_strings]
35 self.assertIn(call, call_permutations)
36
37 @patch("builtins.print")
38 def test_check_in(self, mock_print):
39 """The decorator should report invalid "in" arguments."""
40 # Single type
41 decorated = type_check("in")(list)(join_collections)
42 result = decorated('asdf', 'movie')
43 self.assertEqual(mock_print.call_count, 1)
44 mock_print.assert_has_calls(
45 [call(self.BASE_STRING_IN.format(str(list)))])
46 self.assertEqual(result, ['a', 's', 'd', 'f', 'm', 'o', 'v', 'i', 'e'])
47
48 # Multiple types
49 mock_print.reset_mock()
50 types = (list, tuple, set, type(_ for _ in []))
51 decorated = type_check("in")(*types)(join_collections)
52 result = decorated('asdf', 'movie')
53 self.assertEqual(mock_print.call_count, 1)
54 self.assert_in_permutations(mock_print.mock_calls[0], types, self.BASE_STRING_IN)
55 self.assertEqual(result, ['a', 's', 'd', 'f', 'm', 'o', 'v', 'i', 'e'])
56
57 # Valid input
58 mock_print.reset_mock()
59 decorated = type_check("in")(list, tuple, set, type(_ for _ in []))(join_collections)
60 result = decorated([1, 2], (3,), {4})
61 mock_print.assert_not_called()
62 self.assertEqual(result, [1, 2, 3, 4])
63
64 @patch("builtins.print")
65 def test_check_out(self, mock_print):
66 """The decorator should report an invalid "out" value."""
67 # Single type
68 decorated = type_check("out")(
69 type("Epyt", (type,),{"__repr__": lambda self: f"{self.__name__[::-1].lower()} {self.__class__.__name__[::-1].lower()}"})("Ym", (), {}))(nothing)
70 # Why do I do these things?
71 result = decorated()
72 mock_print.assert_has_calls([call(self.BASE_STRING_OUT.format("my type"))])
73 self.assertEqual(mock_print.call_count, 1)
74 self.assertEqual(result, None)
75
76 # Multiple types
77 mock_print.reset_mock()
78 types = (str, bool, Exception)
79 decorated = type_check("out")(*types)(nothing)
80 result = decorated()
81 self.assertEqual(mock_print.call_count, 1)
82 self.assert_in_permutations(mock_print.mock_calls[0], types, self.BASE_STRING_OUT)
83 self.assertEqual(result, None)
84
85 # Valid output
86 mock_print.reset_mock()
87 decorated = type_check("out")(type(None))(nothing)
88 result = decorated()
89 mock_print.assert_not_called()
90 self.assertEqual(result, None)
91
92 @patch("builtins.print")
93 def test_check_both(self, mock_print):
94 """The decorator should report invalid "in" and "out" together."""
95 decorated = type_check("in")(float)(lonely_island)
96 decorated = type_check("out")(int)(decorated)
97 result = decorated("Captain Jack Sparrow", "Bill", pirates=True)
98 mock_print.assert_has_calls(
99 [call(self.BASE_STRING_IN.format(str(float))),
100 call(self.BASE_STRING_OUT.format(str(int)))])
101 self.assertEqual(mock_print.call_count, 2)
102 self.assertEqual(result, "This is the tale of Captain Jack Sparrow and Bill!")
103
104 @patch("builtins.print")
105 def test_check_decorated_exception(self, mock_print):
106 """The decorator should not supress any exceptions raised."""
107 types = (list, tuple)
108 decorated = type_check("in")(*types)(divide_by_zero)
109 decorated = type_check("out")(*types)(decorated)
110 with self.assertRaises(ZeroDivisionError):
111 decorated({1, 2, 3, 4, 5, 6})
112 self.assert_in_permutations(mock_print.mock_calls[0], types, self.BASE_STRING_IN)
113
114if __name__ == '__main__':
115 unittest.main()
Виктор Бечев
25.10.2024 11:40@Димитър_Фенерски - Жорката ти отговори на коментара към твоето домашно, аз ще ти отговоря и тук, защото темата е валидна.
Приели сме, че не е било очевидно и сме направили необходимите корекции в тестовете - 3-ма души имат разлика в точките (с 1 нагоре).
В същото време, за в бъдеще ще разчитаме на вас да питате когато има неясни неща по условието. Няма как да сме експлицитни за всеки един дребен детайл и разчитаме ако примерите не са ви достатъчни и особено ако добавяте "бонус" функционалност - да питате.
Ясно е, че когато сме допуснали грешка - ще действаме подобаващо. Просто следващия път няма да третираме ситуации като тази _(приемайки, че са налични примери, разбира се)_ като грешка, така че смело питайте смело!
|
Димитър Фенерски
24.10.2024 19:13> Където вместо <типове> имате стринговите репрезентаци на типовете, изброени при декорирането на функцията, съединени с ", " (запетая и интервал). Например "Invalid input arguments, expected <class 'dict'>, <class 'set'>!".
> Стрингът се принтира само веднъж за дадено извикване на декорираната функция, независимо от броят аргументи, които не отговарят на условието за тип.
не е указано изрично, че подредбата трябва да бъде една и съща в подаването и принтирането, но са взимани точки затова
|
Георги Кунчев
24.10.2024 16:53Да, моля. Твоето явно си качила точно по време на сериозния ни проблем.
|
Камелия Тодорова
24.10.2024 16:52Ако все още не е налично решението ни , трябва ли да го качим наново?
|
Георги Кунчев
24.10.2024 16:45Стана малко проблем. Довечера ще разясним, както и с новина. Всички решения, които бяха изчезнали, вече трябва да са налични.
|
Стефан Шиваров
24.10.2024 16:34Само на мен ли ми се изтри изпратеното решение, понеже ми излиза, че имам коментар ама не мога да си видя решението вече?
|
Йоан Байчев
23.10.2024 23:42Трябва ли декораторът да запазва метаданните на оригиналната функция , или не е необходимо?
|
|
Стефан Шиваров
23.10.2024 15:35Ако като първи аргумент на декоратора подадем нещо различно от "in" или "out", какво поведение се очаква от функцията?
|
Георги Кунчев
23.10.2024 10:33Броят типове, които подаваш, не е обвързан с броя параметри, които очаква декорираната функция.
Разглеждай подадените типовете като списък от валидни типове, които важат за всички очаквани параметри.
Всички аргументи, подадени на функцията, трябва да се сравнят със списъка. Ако типът на който и да било аргумент не е дефиниран в списъка с валидни типове, имаш проблем и принтиш.
|