diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..2f0a9172a5 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,25 @@ +name: Run tests + +on: [push] + +jobs: + test: + runs-on: ${{matrix.runner}} + + strategy: + matrix: + runner: [ubuntu-latest, windows-latest] + file: [circle.py, rectangle.py, square.py, triangle.py] + python-version: ["3.12.6"] + + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: ${{matrix.python-version}} + + - name: Run ${{matrix.file}} tests + run: python -m unittest ${{matrix.file}} diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000..26d33521af --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000000..1805227d44 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +circle.py \ No newline at end of file diff --git a/.idea/geometric_lib.iml b/.idea/geometric_lib.iml new file mode 100644 index 0000000000..8b8c395472 --- /dev/null +++ b/.idea/geometric_lib.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000000..105ce2da2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000..db8786c06e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000..5c0675083d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000..35eb1ddfbb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/circle.py b/circle.py index c3eb8647c9..7f84114928 100644 --- a/circle.py +++ b/circle.py @@ -1,10 +1,73 @@ import math - +from unittest import TestCase def area(r): + '''Возвращает площадь круга с радиусом r. + Параметры: + r (int): радиус круга + Возвращаемое значение: + pi * r * r (float): площадь круга с радиусом r + Пример вызова area(3): + Входные данные: 3 + Вывод: 28.2743338823''' + + if not (isinstance(r, int) or isinstance(r, float)): + raise TypeError("Argument must be int or float") + + if r <= 0: + raise ValueError("Argument must be positive") + return math.pi * r * r def perimeter(r): + '''Возвращает периметр круга с радиусом r. + Параметры: + r (int): радиус круга + Возвращаемое значение: + 2 * pi * r (float): периметр круга с радиусом r + Пример вызова perimetr(3): + Входные данные: 3 + Вывод: 18.8495559215''' + + if not (isinstance(r, int) or isinstance(r, float)): + raise TypeError("Argument must be int or float") + + if r <= 0: + raise ValueError("Argument must be positive") + return 2 * math.pi * r + + + +class CircleTestCase(TestCase): + def test_area_with_integer_radius(self): + self.assertEqual(area(5), 78.53981633974483) + + def test_area_with_float_radius(self): + self.assertEqual(area(2.5), 19.634954084936208) + + def test_area_with_incorrect_type_radius(self): + self.assertRaises(TypeError, area, []) + + def test_area_with_negative_radius(self): + self.assertRaises(ValueError, area, -1) + + def test_area_with_zero_radius(self): + self.assertRaises(ValueError, area, 0) + + def test_perimeter_with_integer_radius(self): + self.assertEqual(perimeter(4), 25.132741228718345) + + def test_perimeter_with_float_radius(self): + self.assertEqual(perimeter(3.5), 21.991148575128552) + + def test_perimeter_with_incorrect_type_radius(self): + self.assertRaises(TypeError, perimeter, []) + + def test_perimeter_with_negative_radius(self): + self.assertRaises(ValueError, perimeter, -2) + + def test_perimeter_with_zero_radius(self): + self.assertRaises(ValueError, perimeter, 0) \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 63f8727939..89fd7ecb8b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,4 +7,108 @@ ## Perimeter - Circle: P = 2πR - Rectangle: P = 2a + 2b -- Square: P = 4a \ No newline at end of file +- Square: P = 4a + +# Документация +## Общее описание решения +Этот проект предоставляет набор модулей для вычисления площади и периметра различных геометрических фигур: круга, прямоугольника, квадрата и треугольника. Каждый модуль реализует функции для работы с соответствующей фигурой. +### Структура проекта +- circle.py: Модуль для работы с кругами. +- rectangle.py: Модуль для работы с прямоугольниками. +- square.py: Модуль для работы с квадратами. +- triangle.py: Модуль для работы с треугольниками. +## Использование +### [circle.py](../blob/new_features_467568/circle.py) +Модуль `circle.py` предоставляет функции для вычисления площади и периметра круга. +#### Функции +- `area(r)` + Возвращает площадь круга с радиусом `r` + **Параметры:** + `r`: радиус круга + **Возвращаемое значение:** + `pi * r * r`: площадь круга с радиусом r + **Пример вызова `area(3)`:** + Входные данные: `3` + Вывод: `28.2743338823` +- `perimeter(r)` + Возвращает периметр круга с радиусом `r` + **Параметры:** + `r`: радиус круга + **Возвращаемое значение:** + `2 * pi * r`: периметр круга с радиусом r + **Пример вызова `perimeter(3)`:** + Входные данные: `3` + Вывод: `18.8495559215` + +### [rectangle.py](../blob/new_features_467568/rectangle.py) +Модуль `rectangle.py` предоставляет функции для вычисления площади и периметра прямоугольника. +#### Функции +- `area(a, b)` + Возвращает площадь прямоугольника со сторонами `a` и `b` + **Параметры:** + `a`, `b`: стороны прямоугольника + **Возвращаемое значение:** + `a * b`: площадь прямоугольника + **Пример вызова `area(3, 2)`:** + Входные данные: `3 2` + Вывод: `6` +- `perimeter(a, b)` + Возвращает периметр прямоугольника со сторонами `a` и `b` + **Параметры:** + `a`, `b`: стороны прямоугольника + **Возвращаемое значение:** + `(a + b) * 2`: периметр прямоугольника + **Пример вызова `perimeter(3, 2)`:** + Входные данные: `3 2` + Вывод: `10` + +### [square.py](../blob/new_features_467568/square.py) +Модуль `square.py` предоставляет функции для вычисления площади и периметра квадрата. +#### Функции +- `area(a)` + Возвращает площадь квадрата со стороной `a` + **Параметры:** + `a`: сторона квадрата + **Возвращаемое значение:** + `a * a`: площадь квадрата + **Пример вызова `area(3)`:** + Входные данные: `3` + Вывод: `9` +- `perimeter(a)` + Возвращает периметр квадрата со стороной `a` + **Параметры:** + `a`: сторона квадрата + **Возвращаемое значение:** + `a * 4`: периметр квадрата + **Пример вызова `perimeter(3)`:** + Входные данные: `3` + Вывод: `12` + +### [triangle.py](../blob/new_features_467568/triangle.py) +Модуль `triangle.py` предоставляет функции для вычисления площади и периметра треугольника. +#### Функции +- `area(a, h)` + Возвращает площадь треугольника со стороной `a` и высотой `h` + **Параметры:** + `a`: сторона треугольника + `h`: высота треугольника + **Возвращаемое значение:** + `0.5 * a * h`: площадь треугольника + **Пример вызова `area(3, 2)`:** + Входные данные: `3 2` + Вывод: `3` +- `perimeter(a, b, c)` + Возвращает периметр треугольника со сторонами `a`, `b` и `c` + **Параметры:** + `a`, `b`, `c`: стороны треугольника + **Возвращаемое значение:** + `a + b + c`: периметр треугольника + **Пример вызова `perimeter(3, 2, 1)`:** + Входные данные: `3 2 1` + Вывод: `6` + +# Изменения +- `8ba9aeb3cea847b63a91ac378a2a6db758682460` Circle and square added +- `d078c8d9ee6155f3cb0e577d28d337b791de28e2` Docs added +- `8f4a7dd8b959ebff7b402e683390fc08c7e0c65f` added rectangle function +- `d3dfeaa4a9e2b6ece28dbc2da97ee90793f45031` fixed rectangle function diff --git a/rectangle.py b/rectangle.py new file mode 100644 index 0000000000..2c6ebe957c --- /dev/null +++ b/rectangle.py @@ -0,0 +1,74 @@ +from unittest import TestCase + +def area(a, b): + '''Возвращает площадь прямоугольника со сторонами a и b + Параметры: + a, b: стороны прямоугольника + Возвращаемое значение: + a * b: площадь прямоугольника + Пример вызова area(3, 2): + Входные данные: 3 2 + Вывод: 6''' + + if not (isinstance(a, int) or isinstance(a, float)) or not (isinstance(b, int) or isinstance(b, float)): + raise TypeError("Argument must be int or float") + + if a <= 0 or b <= 0: + raise ValueError("Argument must be positive") + + return a * b + +def perimeter(a, b): + '''Возвращает периметр прямоугольника со сторонами a и b + Параметры: + a, b: стороны прямоугольника + Возвращаемое значение: + (a + b) * 2: периметр прямоугольника + Пример вызова perimetr(3, 2)`: + Входные данные: 3 2 + Вывод: 10''' + + if not (isinstance(a, int) or isinstance(a, float)) or not (isinstance(b, int) or isinstance(b, float)): + raise TypeError("Argument must be int or float") + + if a <= 0 or b <= 0: + raise ValueError("Argument must be positive") + + return (a + b) * 2 + +class RectangleTestCase(TestCase): + def test_area_with_integer_dimensions(self): + self.assertEqual(area(3, 4), 12) + + def test_area_with_float_dimensions(self): + self.assertEqual(area(2.5, 1.5), 3.75) + + def test_area_with_mixed_types(self): + self.assertEqual(area(2, 2.0), 4.0) + + def test_area_with_incorrect_type(self): + self.assertRaises(TypeError, area, [], 1) + + def test_area_with_negative_value(self): + self.assertRaises(ValueError, area, 2, -3) + + def test_area_with_zero_value(self): + self.assertRaises(ValueError, area, 0, 1) + + def test_perimeter_with_integer_dimensions(self): + self.assertEqual(perimeter(3, 4), 14) + + def test_perimeter_with_float_dimensions(self): + self.assertEqual(perimeter(2.5, 1.5), 8.0) + + def test_perimeter_with_mixed_types(self): + self.assertEqual(perimeter(2.0, 3), 10) + + def test_perimeter_with_incorrect_type(self): + self.assertRaises(TypeError, perimeter, [], []) + + def test_perimeter_with_negative_value(self): + self.assertRaises(ValueError, perimeter, -2, 3) + + def test_perimeter_with_zero_value(self): + self.assertRaises(ValueError, perimeter, 1, 0) \ No newline at end of file diff --git a/square.py b/square.py index 0f98724205..a20291712e 100644 --- a/square.py +++ b/square.py @@ -1,7 +1,69 @@ +from unittest import TestCase def area(a): + '''Возвращает площадь квадрата со стороной a + Параметры: + a: сторона квадрата + Возвращаемое значение: + a * a: площадь квадрата + Пример вызова area(3): + Входные данные: 3 + Вывод: 9''' + + if not (isinstance(a, int) or isinstance(a, float)): + raise TypeError("Argument must be int or float") + + if a <= 0: + raise ValueError("Argument must be positive") + return a * a def perimeter(a): + '''Возвращает периметр квадрата со стороной a + Параметры: + a: сторона квадрата + Возвращаемое значение: + a * 4: периметр квадрата + Пример вызова perimetr(3): + Входные данные: 3 + Вывод: 12''' + + if not (isinstance(a, int) or isinstance(a, float)): + raise TypeError("Argument must be int or float") + + if a <= 0: + raise ValueError("Argument must be positive") + return 4 * a + +class SquareTestCase(TestCase): + def test_area_with_integer_dimension(self): + self.assertEqual(area(3), 9) + + def test_area_with_float_dimension(self): + self.assertEqual(area(2.5), 6.25) + + def test_area_with_incorrect_type(self): + self.assertRaises(TypeError, area, []) + + def test_area_with_negative_value(self): + self.assertRaises(ValueError, area, -1) + + def test_area_with_zero_value(self): + self.assertRaises(ValueError, area, 0) + + def test_perimeter_with_integer_dimension(self): + self.assertEqual(perimeter(3), 12) + + def test_perimeter_with_float_dimension(self): + self.assertEqual(perimeter(2.5), 10.0) + + def test_perimeter_with_incorrect_type(self): + self.assertRaises(TypeError, perimeter, []) + + def test_perimeter_with_negative_value(self): + self.assertRaises(ValueError, perimeter, -1) + + def test_perimeter_with_zero_value(self): + self.assertRaises(ValueError, perimeter, 0) diff --git a/triangle.py b/triangle.py new file mode 100644 index 0000000000..d66efd2abc --- /dev/null +++ b/triangle.py @@ -0,0 +1,79 @@ +from unittest import TestCase + +def area(a, h): + ''' + Возвращает площадь треугольника со стороной a и высотой h + Параметры: + a: сторона треугольника + h: высота треугольника + Возвращаемое значение: + a * a: площадь треугольника + Пример вызова area(3, 2): + Входные данные: 3, 2 + Вывод: 3 + ''' + + if not (isinstance(a, int) or isinstance(a, float)) or not (isinstance(h, int) or isinstance(h, float)): + raise TypeError("Argument must be int or float") + + if a <= 0 or h <= 0: + raise ValueError("Argument must be positive") + + return a * h / 2 + + +def perimeter(a, b, c): + '''Возвращает периметр треугольника со сторонами a, b и c + Параметры: + a, b, c: стороны треугольника + h: высота треугольника + Возвращаемое значение: + a + b + c: периметр треугольника + Пример вызова perimetr(3, 2, 1): + Входные данные: 3 2 1 + Вывод: 6''' + + if not (isinstance(a, int) or isinstance(a, float)) or not (isinstance(b, int) or isinstance(b, float)) or not (isinstance(c, int) or isinstance(c, float)): + raise TypeError("Argument must be int or float") + + if a <= 0 or b <= 0 or c <= 0: + raise ValueError("Argument must be positive") + + return a + b + c + +class TriangleTestCase(TestCase): + def test_area_with_integer_base_and_height(self): + self.assertEqual(area(2, 3), 3) + + def test_area_with_float_base_and_height(self): + self.assertEqual(area(1.5, 4.0), 3.0) + + def test_area_with_mixed_types(self): + self.assertEqual(area(1.5, 4), 3.0) + + def test_area_with_invalid_type(self): + self.assertRaises(TypeError, area, [], []) + + def test_area_with_negative_base(self): + self.assertRaises(ValueError, area, -3, 2) + + def test_area_with_zero_height(self): + self.assertRaises(ValueError, area, 1, 0) + + def test_perimeter_with_integer_sides(self): + self.assertEqual(perimeter(1, 2, 3), 6) + + def test_perimeter_with_float_sides(self): + self.assertEqual(perimeter(1.5, 1.0, 2.5), 5.0) + + def test_perimeter_with_mixed_types(self): + self.assertEqual(perimeter(1.5, 1, 2.5), 5.0) + + def test_perimeter_with_invalid_type(self): + self.assertRaises(TypeError, perimeter, [], [], []) + + def test_perimeter_with_negative_side(self): + self.assertRaises(ValueError, perimeter, -3, 2, 1) + + def test_perimeter_with_zero_side(self): + self.assertRaises(ValueError, perimeter, 0, 3, 2) \ No newline at end of file