diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..abaa9cd542 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,30 @@ +name: Run unittest + +on: + push: + branches: + - ci_408111 + - master + +jobs: + test: + name: Run tests on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + + - name: Test with unittest + run: | + python -m unittest discover -s tests diff --git a/circle.py b/circle.py index c3eb8647c9..f6d20ee0fa 100644 --- a/circle.py +++ b/circle.py @@ -1,10 +1,37 @@ import math -def area(r): +def area(r: float) -> float: + """ + Возвращает площадь круга с радиусом r + + :param r: радиус круга + :type r: float + :returns: площадь круга + :rtype: float + + Пример вызова: + s = area(2) # В s запишется 12.56 + """ + + if r < 0: + raise ValueError("Radius cannot be negative") return math.pi * r * r def perimeter(r): - return 2 * math.pi * r + """ + Возвращает длину окружности с радиусом r + :param r: радиус круга + :type r: float + :returns: длина окружности + :rtype: float + + Пример вызова: + p = perimeter(1) # В p запишется 6.28 + """ + + if r < 0: + raise ValueError("Radius cannot be negative") + return 2 * math.pi * r diff --git a/docs/README.md b/docs/README.md index 63f8727939..b6b46ed5b2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,10 +1,237 @@ -# Math formulas -## Area -- Circle: S = πR² -- Rectangle: S = ab -- Square: S = a² - -## Perimeter -- Circle: P = 2πR -- Rectangle: P = 2a + 2b -- Square: P = 4a \ No newline at end of file +# Общее описание решения +Этот проект содержит 4 файла с функциями для вычисления площади и периметра различных геометрических +фигур: +- circle.py для круга, +- rectangle.py для прямоугольника, +- square.py для квадрата, +- triangle.py для треугольника. + +Для вычисления периметра и площади фигур используются следующие математический формулы: + +## Площадь +- Круг: S = πR² +- Прямоугольник: S = ab +- Квадрат: S = a² + +## Периметр +- Круг: P = 2πR +- Прямоугольник: P = 2 * (a + b) +- Квадрат: P = 4a + +# Описание функций с примерами вызова +`square.py`: +- `def area(a)`: + ```python + def area(a: float) -> float: + """ + Возвращает площадь квадрата со стороной a + + :param a: длина стороны квадрата + :type a: float + :returns: площадь квадрата + :rtype: float + + Пример вызова: + s = area(5) # В s запишется 25 + """ + return a * a + ``` + Функция вычисляет площадь квадрата. Она принимает один аргумент: длину стороны квадрата типа float (или int) + и возвращает площадь квадрата типа float (или int). + ### Пример вызова: + ```python + s = area(5) # В s запишется 25 + ``` + +- `perimeter(a)`: + ```python + def perimeter(a: float) -> float: + """ + Возвращает периметр квадрата со стороной a + + :param a: длина стороны квадрата + :type a: float + :returns: периметр квадрата + :rtype: float + + Пример вызова: + p = perimeter(5) # В p запишется 20 + """ + return 4 * a + ``` + Функция вычисляет периметр квадрата. Она принимает один аргумент: длину стороны квадрата типа float (или int) + и возвращает периметр квадрата типа float (или int). + ### Пример вызова: + ```python + p = perimeter(5) # В p запишется 20 + ``` + +`rectangle.py`: +- `def area(a, b)`: + ```python + def area(a: float, b: float) -> float: + """ + Возвращает площадь прямоугольника со сторонами a, b + + :param a: длина прямоугольника + :type a: float + :param b: ширина прямоугольника + :type b: float + :returns: периметр прямоугольника + :rtype: float + + Пример вызова: + s = area(5, 2) # В s запишется 10 + """ + return a * b + ``` + Функция вычисляет площадь прямоугольника. Она принимает два аргумента: длину и ширину прямоугольника типа float (или int) + и возвращает площадь прямоугольника типа float (или int). + ### Пример вызова: + ```python + s = area(5, 2) # В s запишется 10 + ``` + +- `perimeter(a, b)`: + ```python + def perimeter(a: float, b: float) -> float: + """ + Возвращает периметр прямоугольника со сторонами a, b + + :param a: длина прямоугольника + :type a: float + :param b: ширина прямоугольника + :type b: float + :returns: периметр прямоугольника + :rtype: float + + Пример вызова: + p = perimeter(5, 2) # В p запишется 14 + """ + return 2 * (a + b) + ``` + Функция вычисляет периметр прямоугольника. Она принимает 2 аргумента: длину и ширину прямоугольника типа float (или int) + и возвращает периметр прямоугольника типа float (или int). + ### Пример вызова: + ```python + p = perimeter(5, 2) # В p запишется 14 + ``` + +`triangle.py`: +- `def area(a, h)`: + ```python + def area(a: float, h: float) -> float: + """ + Возвращает площадь треугольника с основанием a и высотой h + + :param a: основание треугольника + :type a: float + :param h: высота треугольника + :type h: float + :returns: площадь треугольника + :rtype: float + + Пример вызова: + s = area(5, 2) # В s запишется 5 + """ + return a * h / 2 + ``` + Функция вычисляет площадь треугольника. Она принимает два аргумента: основание и высоту треугольника типа float (или int) + и возвращает площадь треугольника типа float (или int). + ### Пример вызова: + ```python + s = area(5, 2) # В s запишется 5 + ``` + +- `perimeter(a, b, c)`: + ```python + def perimeter(a: float, b: float, c: float) -> float: + """ + Возвращает периметр треугольника со сторонами a, b, c + + :param a: одна сторона треугольника + :type a: float + :param b: вторая сторона треугольника + :type b: float + :param c: третья сторона треугольника + :type c: float + :returns: периметр треугольника + :rtype: float + + Пример вызова: + p = perimeter(5, 2, 3) # В p запишется 10 + """ + return a + b + c + ``` + Функция вычисляет периметр треугольника. Она принимает 3 аргумента: все стороны треугольника типа float (или int) + и возвращает периметр треугольника типа float (или int). + ### Пример вызова: + ```python + p = perimeter(5, 2, 3) # В p запишется 10 + ``` + +`circle.py`: +- `def area(r)`: + ```python + def area(r: float) -> float: + """ + Возвращает площадь круга с радиусом r + + :param r: радиус круга + :type r: float + :returns: площадь круга + :rtype: float + + Пример вызова: + s = area(2) # В s запишется 12.56 + """ + return math.pi * r * r + ``` + Функция вычисляет площадь круга. Она принимает один аргумент: радиус круга типа float (или int) + и возвращает площадь круга типа float (или int). + ### Пример вызова: + ```python + s = area(2) # В s запишется 12.56 + ``` + +- `perimeter(r)`: + ```python + def perimeter(r): + """ + Возвращает длину окружности с радиусом r + + :param r: радиус круга + :type r: float + :returns: длина окружности + :rtype: float + + Пример вызова: + p = perimeter(1) # В p запишется 6.28 + """ + return 2 * math.pi * r + ``` + Функция вычисляет длину окружности. Она принимает 1 аргумент: радиус окружности типа float (или int) + и возвращает длину окружности типа float (или int). + ### Пример вызова: + ```python + p = perimeter(1) # В p запишется 6.28 + ``` + +# История изменения проекта +## Коммиты + +| Название | Хеш | Автор | Дата | Описание | +|---------------------------------------------------------------------------------------------------------------------------|----------|---------------------------------|------------------|-------------------------------------------| +| [added unit tests](https://github.com/nawinds/geometric_lib/commit/95d2bc138b8b3419dec4b8dabdae9cb4e2b6045b) | 95d2bc13 | Nikita Aksenov | 31/10/2024 17:35 | Добавлены unit тесты | +| [reformatted docs](https://github.com/nawinds/geometric_lib/commit/c6784675fba1dabb1329315164b6c9f867dc3c0c) | c6784675 | Nikita Aksenov | 23/10/2024 09:51 | Изменен формат документации функций | +| [project history](https://github.com/nawinds/geometric_lib/commit/2e803c3aec84e69bee0a85c664aa9c1db5579a26) | 2e803c3a | Nikita Aksenov | 23/10/2024 09:46 | Добавлена история проекта | +| [circle docs](https://github.com/nawinds/geometric_lib/commit/c067f4fcadc268edf2e97c8c4bfc96fdf246017a) | c067f4fc | Nikita Aksenov | 28/09/2024 09:38 | Добавлена документация для круга | +| [triangle docs](https://github.com/nawinds/geometric_lib/commit/27c6ec589b1ecf641de9e38c4bd59f781becc0a0) | 27c6ec58 | Nikita Aksenov | 28/09/2024 09:31 | Добавлена документация для треугольника | +| [rectangle docs](https://github.com/nawinds/geometric_lib/commit/27c6ec589b1ecf641de9e38c4bd59f781becc0a0) | d5d20b39 | Nikita Aksenov | 28/09/2024 09:21 | Добавлена документация для прямоугольника | +| [square docs](https://github.com/nawinds/geometric_lib/commit/b8c6acd2d2f18fef9b70974475484170cad11e95) | b8c6acd2 | Nikita Aksenov | 28/09/2024 09:12 | Добавлена документация для квадрата | +| [General solution description](https://github.com/nawinds/geometric_lib/commit/916e5e9441fcc1492fadf9cfc1a48e3c76730789) | 916e5e94 | Nikita Aksenov | 28/09/2024 09:03 | Изменен rectangle.md | +| [modified rectangle.py](https://github.com/nawinds/geometric_lib/commit/1d53844e0eba6a7f21ec032c65474d53a2c6b4b0) | 1d53844e | Nikita Aksenov | 25/09/2024 09:02 | Изменен rectangle.md | +| [added triangle.py](https://github.com/nawinds/geometric_lib/commit/06fc55e6c89cb0d407407a68c6d43b530452d3a0) | 06fc55e6 | Nikita Aksenov | 25/09/2024 09:01 | Добавлен triangle.md | +| [added rectangle.py](https://github.com/nawinds/geometric_lib/commit/74f5242e1e035e0a9263e1c6b6b7377686926b3e) | 74f5242e | Nikita Aksenov | 25/09/2024 08:59 | Добавлен rectangle.md | +| [L-03: Docs added](https://github.com/nawinds/geometric_lib/commit/d078c8d9ee6155f3cb0e577d28d337b791de28e2) | d078c8d9 | smartiqa | 04/03/2021 14:55 | Добавлен README.md | +| [L-03: Circle and square added](https://github.com/nawinds/geometric_lib/commit/8ba9aeb3cea847b63a91ac378a2a6db758682460) | 8ba9aeb3 | smartiqa | 04/03/2021 14:54 | Добавлены circle.py и square.py | diff --git a/rectangle.py b/rectangle.py new file mode 100644 index 0000000000..e850fbdf1c --- /dev/null +++ b/rectangle.py @@ -0,0 +1,36 @@ +def area(a: float, b: float) -> float: + """ + Возвращает площадь прямоугольника со сторонами a, b + + :param a: длина прямоугольника + :type a: float + :param b: ширина прямоугольника + :type b: float + :returns: периметр прямоугольника + :rtype: float + + Пример вызова: + s = area(5, 2) # В s запишется 10 + """ + if a < 0 or b < 0: + raise ValueError("Sides cannot be negative") + return a * b + + +def perimeter(a: float, b: float) -> float: + """ + Возвращает периметр прямоугольника со сторонами a, b + + :param a: длина прямоугольника + :type a: float + :param b: ширина прямоугольника + :type b: float + :returns: периметр прямоугольника + :rtype: float + + Пример вызова: + p = perimeter(5, 2) # В p запишется 14 + """ + if a < 0 or b < 0: + raise ValueError("Sides cannot be negative") + return 2 * (a + b) diff --git a/square.py b/square.py index 0f98724205..bf6089dd65 100644 --- a/square.py +++ b/square.py @@ -1,7 +1,32 @@ +def area(a: float) -> float: + """ + Возвращает площадь квадрата со стороной a -def area(a): + :param a: длина стороны квадрата + :type a: float + :returns: площадь квадрата + :rtype: float + + Пример вызова: + s = area(5) # В s запишется 25 + """ + if a < 0: + raise ValueError("Side cannot be negative") return a * a -def perimeter(a): +def perimeter(a: float) -> float: + """ + Возвращает периметр квадрата со стороной a + + :param a: длина стороны квадрата + :type a: float + :returns: периметр квадрата + :rtype: float + + Пример вызова: + p = perimeter(5) # В p запишется 20 + """ + if a < 0: + raise ValueError("Side cannot be negative") return 4 * a diff --git a/tests/config.py b/tests/config.py new file mode 100644 index 0000000000..23272a9bae --- /dev/null +++ b/tests/config.py @@ -0,0 +1 @@ +MAX_EXECUTION_TIME = 1 # in seconds diff --git a/tests/test_circle.py b/tests/test_circle.py new file mode 100644 index 0000000000..0eeb320e90 --- /dev/null +++ b/tests/test_circle.py @@ -0,0 +1,91 @@ +import unittest +from time import time + +import circle +from config import MAX_EXECUTION_TIME + + +class CircleAreaTest(unittest.TestCase): + test_cases = [ + (1, 3.141592653589793, False), + (2, 12.566370614359172, False), + (9, 254.46900494077323, False), + (0, 0, False), + (8.63, 233.9760819021417, False), + (64926593, 1.3243265954214378e+16, False), + (-1, 0, True), + (-6583.54, 0, True), + ] + + def test_area(self): + for input_radius, expected_output, want_error in self.test_cases: + with self.subTest(input_radius=input_radius, expected_output=expected_output, want_error=want_error): + if want_error: + with self.assertRaises(ValueError): + circle.area(input_radius) + else: + result = circle.area(input_radius) + self.assertEqual(expected_output, result, + f"Circle area test failed: expected {expected_output}, got {result}") + + def test_area_performance(self): + for input_radius, expected_output, want_error in self.test_cases: + with self.subTest(input_radius=input_radius, expected_output=expected_output, want_error=want_error): + start_time = time() + + if want_error: + with self.assertRaises(ValueError): + circle.area(input_radius) + else: + circle.area(input_radius) + + execution_time = time() - start_time + + self.assertLessEqual(execution_time, MAX_EXECUTION_TIME, + f"Circle area performance test failed: {execution_time} seconds for " + f"radius={input_radius}") + + +class CirclePerimeterTest(unittest.TestCase): + test_cases = [ + (1, 6.283185307179586, False), + (2, 12.566370614359172, False), + (9, 56.548667764616276, False), + (0, 0, False), + (8.63, 54.22388920095983, False), + (64926593, 407945815.18282896, False), + (-1, 0, True), + (-6583.54, 0, True), + ] + + def test_perimeter(self): + for input_radius, expected_output, want_error in self.test_cases: + with self.subTest(input_radius=input_radius, expected_output=expected_output, want_error=want_error): + if want_error: + with self.assertRaises(ValueError): + circle.perimeter(input_radius) + else: + result = circle.perimeter(input_radius) + self.assertEqual(expected_output, result, + f"Circle perimeter test failed: expected {expected_output}, got {result}") + + def test_perimeter_performance(self): + for input_radius, expected_output, want_error in self.test_cases: + with self.subTest(input_radius=input_radius, expected_output=expected_output, want_error=want_error): + start_time = time() + + if want_error: + with self.assertRaises(ValueError): + circle.perimeter(input_radius) + else: + circle.perimeter(input_radius) + + execution_time = time() - start_time + + self.assertLessEqual(execution_time, MAX_EXECUTION_TIME, + f"Circle perimeter performance test failed: {execution_time} seconds for " + f"radius={input_radius}") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_rectangle.py b/tests/test_rectangle.py new file mode 100644 index 0000000000..1ae33fb288 --- /dev/null +++ b/tests/test_rectangle.py @@ -0,0 +1,97 @@ +import unittest +from time import time + +import rectangle +from config import MAX_EXECUTION_TIME + + +class RectangleAreaTest(unittest.TestCase): + test_cases = [ + ((1, 1), 1, False), + ((1, 2), 2, False), + ((9, 12), 108, False), + ((0, 0), 0, False), + ((0, 1), 0, False), + ((8.63, 2.004), 17.294520000000002, False), + ((6492593, 6352642), 41245118980706, False), + ((-3, 5), 0, True), + ((-6583.54, -3), 0, True), + ] + + def test_area(self): + for input_data, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_data[0], input_b=input_data[1], expected_output=expected_output, + want_error=want_error): + if want_error: + with self.assertRaises(ValueError): + rectangle.area(*input_data) + else: + result = rectangle.area(*input_data) + self.assertEqual(expected_output, result, + f"Rectangle area test failed: expected {expected_output}, got {result}") + + def test_area_performance(self): + for input_data, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_data[0], input_b=input_data[1], expected_output=expected_output, + want_error=want_error): + start_time = time() + + if want_error: + with self.assertRaises(ValueError): + rectangle.area(*input_data) + else: + rectangle.area(*input_data) + + execution_time = time() - start_time + + self.assertLessEqual(execution_time, MAX_EXECUTION_TIME, + f"Rectangle area performance test failed: {execution_time} seconds for " + f"rectangle {input_data}") + + +class RectanglePerimeterTest(unittest.TestCase): + test_cases = [ + ((1, 1), 4, False), + ((1, 2), 6, False), + ((9, 12), 42, False), + ((0, 0), 0, False), + ((0, 1), 2, False), + ((8.63, 2.004), 21.268, False), + ((6492593, 6352642), 25690470, False), + ((-3, 5), 0, True), + ((-6583.54, -3), 0, True), + ] + + def test_perimeter(self): + for input_data, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_data[0], input_b=input_data[1], expected_output=expected_output, + want_error=want_error): + if want_error: + with self.assertRaises(ValueError): + rectangle.perimeter(*input_data) + else: + result = rectangle.perimeter(*input_data) + self.assertEqual(expected_output, result, + f"Rectangle perimeter test failed: expected {expected_output}, got {result}") + + def test_perimeter_performance(self): + for input_data, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_data[0], input_b=input_data[1], expected_output=expected_output, + want_error=want_error): + start_time = time() + + if want_error: + with self.assertRaises(ValueError): + rectangle.perimeter(*input_data) + else: + rectangle.perimeter(*input_data) + + execution_time = time() - start_time + + self.assertLessEqual(execution_time, MAX_EXECUTION_TIME, + f"Rectangle perimeter performance test failed: {execution_time} seconds for " + f"rectangle {input_data}") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_square.py b/tests/test_square.py new file mode 100644 index 0000000000..01d6dcfec7 --- /dev/null +++ b/tests/test_square.py @@ -0,0 +1,95 @@ +import unittest +from time import time + +import square +from config import MAX_EXECUTION_TIME + + +class SquareAreaTest(unittest.TestCase): + test_cases = [ + (1, 1, False), + (2, 4, False), + (9, 81, False), + (0, 0, False), + (8.63, 74.47690000000001, False), + (6492593, 42153763863649, False), + (-3, 0, True), + (-6583.54, 0, True), + ] + + def test_area(self): + for input_a, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_a, expected_output=expected_output, + want_error=want_error): + if want_error: + with self.assertRaises(ValueError): + square.area(input_a) + else: + result = square.area(input_a) + self.assertEqual(expected_output, result, + f"Square area test failed: expected {expected_output}, got {result}") + + def test_area_performance(self): + for input_a, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_a, expected_output=expected_output, + want_error=want_error): + start_time = time() + + if want_error: + with self.assertRaises(ValueError): + square.area(input_a) + else: + square.area(input_a) + + execution_time = time() - start_time + + self.assertLessEqual(execution_time, MAX_EXECUTION_TIME, + f"Square area performance test failed: {execution_time} seconds for " + f"square {input_a}") + + +class SquarePerimeterTest(unittest.TestCase): + test_cases = [ + (1, 4, False), + (2, 8, False), + (9, 36, False), + (0, 0, False), + (8.63, 34.52, False), + (6492593, 25970372, False), + (-3, 0, True), + (-6583.54, 0, True), + ] + + def test_perimeter(self): + for input_a, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_a, expected_output=expected_output, + want_error=want_error): + if want_error: + with self.assertRaises(ValueError): + square.perimeter(input_a) + else: + result = square.perimeter(input_a) + self.assertEqual(expected_output, result, + f"Square perimeter test failed: expected {expected_output}, got {result}") + + def test_perimeter_performance(self): + for input_a, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_a, expected_output=expected_output, + want_error=want_error): + start_time = time() + + if want_error: + with self.assertRaises(ValueError): + square.perimeter(input_a) + else: + square.perimeter(input_a) + + execution_time = time() - start_time + + self.assertLessEqual(execution_time, MAX_EXECUTION_TIME, + f"Square perimeter performance test failed: {execution_time} seconds for " + f"square {input_a}") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_triangle.py b/tests/test_triangle.py new file mode 100644 index 0000000000..feb04bad78 --- /dev/null +++ b/tests/test_triangle.py @@ -0,0 +1,97 @@ +import unittest +from time import time + +import triangle +from config import MAX_EXECUTION_TIME + + +class TriangleAreaTest(unittest.TestCase): + test_cases = [ + ((1, 1), 0.5, False), + ((1, 3), 1.5, False), + ((9, 12), 54, False), + ((0, 0), 0, False), + ((0, 1), 0, False), + ((8.63, 2.004), 8.647260000000001, False), + ((6492593, 6352642), 20622559490353.0, False), + ((-3, 5), 0, True), + ((-6583.54, -3), 0, True), + ] + + def test_area(self): + for input_data, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_data[0], input_h=input_data[1], expected_output=expected_output, + want_error=want_error): + if want_error: + with self.assertRaises(ValueError): + triangle.area(*input_data) + else: + result = triangle.area(*input_data) + self.assertEqual(expected_output, result, + f"Triangle area test failed: expected {expected_output}, got {result}") + + def test_area_performance(self): + for input_data, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_data[0], input_h=input_data[1], expected_output=expected_output, + want_error=want_error): + start_time = time() + + if want_error: + with self.assertRaises(ValueError): + triangle.area(*input_data) + else: + triangle.area(*input_data) + + execution_time = time() - start_time + + self.assertLessEqual(execution_time, MAX_EXECUTION_TIME, + f"Triangle area performance test failed: {execution_time} seconds for " + f"triangle {input_data}") + + +class TrianglePerimeterTest(unittest.TestCase): + test_cases = [ + ((1, 1, 1), 3, False), + ((1, 3, 2), 6, False), + ((9, 12, 2), 23, False), + ((0, 0, 0), 0, False), + ((0, 1, 0), 1, False), + ((8.63, 2.004, 3.01), 13.644, False), + ((6492593, 6352642, 56643), 12901878, False), + ((-3, 5, 3), 0, True), + ((-6583.54, -3, -2), 0, True), + ] + + def test_perimeter(self): + for input_data, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_data[0], input_b=input_data[1], input_c=input_data[2], + expected_output=expected_output, want_error=want_error): + if want_error: + with self.assertRaises(ValueError): + triangle.perimeter(*input_data) + else: + result = triangle.perimeter(*input_data) + self.assertEqual(expected_output, result, + f"Triangle perimeter test failed: expected {expected_output}, got {result}") + + def test_perimeter_performance(self): + for input_data, expected_output, want_error in self.test_cases: + with self.subTest(input_a=input_data[0], input_b=input_data[1], input_c=input_data[2], + expected_output=expected_output, want_error=want_error): + start_time = time() + + if want_error: + with self.assertRaises(ValueError): + triangle.perimeter(*input_data) + else: + triangle.perimeter(*input_data) + + execution_time = time() - start_time + + self.assertLessEqual(execution_time, MAX_EXECUTION_TIME, + f"Triangle perimeter performance test failed: {execution_time} seconds for " + f"triangle {input_data}") + + +if __name__ == "__main__": + unittest.main() diff --git a/triangle.py b/triangle.py new file mode 100644 index 0000000000..94c5480d92 --- /dev/null +++ b/triangle.py @@ -0,0 +1,38 @@ +def area(a: float, h: float) -> float: + """ + Возвращает площадь треугольника с основанием a и высотой h + + :param a: основание треугольника + :type a: float + :param h: высота треугольника + :type h: float + :returns: площадь треугольника + :rtype: float + + Пример вызова: + s = area(5, 2) # В s запишется 5 + """ + if a < 0 or h < 0: + raise ValueError("Side and height cannot be negative") + return a * h / 2 + + +def perimeter(a: float, b: float, c: float) -> float: + """ + Возвращает периметр треугольника со сторонами a, b, c + + :param a: одна сторона треугольника + :type a: float + :param b: вторая сторона треугольника + :type b: float + :param c: третья сторона треугольника + :type c: float + :returns: периметр треугольника + :rtype: float + + Пример вызова: + p = perimeter(5, 2, 3) # В p запишется 10 + """ + if a < 0 or b < 0 or c < 0: + raise ValueError("Sides cannot be negative") + return a + b + c