diff --git a/.github/workflows/python_tests.yml b/.github/workflows/python_tests.yml new file mode 100644 index 0000000000..c20102373f --- /dev/null +++ b/.github/workflows/python_tests.yml @@ -0,0 +1,72 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: python test + +on: + push: + branches: [ "main", "labwork2_docs" ] + pull_request: + branches: [ "main" ] + +jobs: + test_with_ubuntu: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + python -m unittest rectangle.py + python -m unittest circle.py + python -m unittest square.py + python -m unittest triangle.py + + test_with_windows-latest: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install flake8 pytest + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + python -m unittest rectangle.py + python -m unittest circle.py + python -m unittest square.py + python -m unittest triangle.py diff --git a/circle.py b/circle.py index c3eb8647c9..a47a987442 100644 --- a/circle.py +++ b/circle.py @@ -1,10 +1,68 @@ import math +import unittest +import datetime def area(r): + ''' + Принимает число r, возвращает площадь круга радиуса r + Code: + print(area(5)) + Output: + 78.53981633974483 + ''' + try: + r = int(r) + except ValueError: + return ValueError return math.pi * r * r def perimeter(r): + ''' + Принимает число r, возвращает периметр круга радиуса r + Code: + print(perimeter(5)) + Output: + 31.41592653589793 + ''' + try: + r = int(r) + except ValueError: + return ValueError return 2 * math.pi * r +class CircleTestCase(unittest.TestCase): + def test_area1(self): + d = area(5) - 3.14 * 5 * 5 + self.assertEqual(d <= 0.1, True) + self.success_message("area(5)", str(area(5))) + + def test_area2(self): + self.assertEqual(area("r"), ValueError) + self.success_message("area(\"r\")", str(area("r"))) + + def test_area3(self): + d = area("4") - 3.14 * 5 * 5 + self.assertEqual(d <= 0.1, True) + self.success_message("area(\"4\")", str(area("4"))) + + def test_perimeter1(self): + d = perimeter(5) - 3.14 * 5 * 2 + self.assertEqual(d <= 0.1, True) + self.success_message("perimeter(5)", str(perimeter(5))) + + def test_perimeter2(self): + self.assertEqual(perimeter("r"), ValueError) + self.success_message("perimeter(\"r\")", str(perimeter("r"))) + + def test_perimeter3(self): + d = perimeter("4") - 3.14 * 5 * 2 + self.assertEqual(d <= 0.1, True) + self.success_message("perimeter(\"4\")", str(perimeter("4"))) + + def success_message(self, func, output): + print(datetime.datetime.now().strftime('%d-%m-%Y'), end=" ") + print(datetime.datetime.now().time().isoformat()[:8], end=": ") + print(self._testMethodName + + " passed => " + str(func) + " >> " + str(output)) diff --git a/docs/README.md b/docs/README.md index 63f8727939..8ea5cf48af 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,10 +1,138 @@ -# 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 +# Math formulas +## Area +- Circle: S = πR² +- Rectangle: S = ab +- Square: S = a² + +## Perimeter +- Circle: P = 2πR +- Rectangle: P = 2a + 2b +- Square: P = 4a + +# Документация + +## Общее описание решения: + +Проект позволяет находить периметр и площадь с помощью вызова функций, +реализовано нахождение данных значений для 4 фигур: круг, треугольник, +квадрат, прямоугольник + +## Файлы + +### circle.py + +#### area(r) + +Принимает число r, возвращает площадь круга радиуса r +``` +print(area(5)) +``` +``` +78.53981633974483 +``` + +#### perimeter(r) + +Принимает число r, возвращает периметр круга радиуса r +``` +print(perimeter(5)) +``` +``` +31.41592653589793 +``` + +### rectangle.py + +#### area(a, b) + +Принимает числа a и b, возвращает площадь прямоугольника со сторонами a и b +``` +print(area(4, 6)) +``` +``` +24 +``` + +#### perimeter(a, b) + +Принимает числа a и b, возвращает периметр прямоугольника со сторонами a и b +``` +print(perimeter(4, 6)) +``` +``` +20 +``` + +### square.py + +#### area(a) + +Принимает число a, возвращает площадь квадрата со стороной a +``` +print(area(5)) +``` +``` +25 +``` + +#### perimeter(a) + +Принимает число a, возвращает периметр квадрата со стороной a +``` +print(perimeter(5)) +``` +``` +20 +``` + +### triangle.py + +#### area(a, h) + +Принимает числа a и h, возвращает площадь треугольника с +основанием a и высотой h +``` +print(area(4, 7)) +``` +``` +14.0 +``` + +#### perimeter(a, b, c) + +Принимает числа a, b и c, возвращает периметр треугольника со + сторонами a, b и c +``` +print(perimeter(2, 3, 4)) +``` +``` +9 +``` + +# История коммитов + +## added rectangle.py + +``` +10b192c8fd3375d5185b71e56eff11adccb18364 +``` + +Добавление файла rectangle.py + +## added triangle.py and fixed rectangle.py + +``` +568286ec992d78fb8a6bf267ad9c1a1ad91efdf6 +``` + +Добавление triangle.py и исправление ошибки в rectangle.py + +# Тесты + +Для каждой функции написаны unit-тесты, они проверяют коректность работы функций с числами и строками + +## Требования: + +- Поддержка работы со строками, которые можно перевести в числа, возвращать ошибку в противном случаи +- Работа с любыми типами числами (int, float) +- Корректность вычислений площадей, периметров с точностью до одного знака после запятой diff --git a/rectangle.py b/rectangle.py new file mode 100644 index 0000000000..15d7ceaf9a --- /dev/null +++ b/rectangle.py @@ -0,0 +1,66 @@ +import unittest +import unittest +import datetime + + +def area(a, b): + ''' + Принимает числа a и b, возвращает площадь прямоугольника со сторонами a и b + Code: + print(area(4, 6)) + Output: + 24 + ''' + try: + a = int(a) + b = int(b) + except ValueError: + return ValueError + return a * b + +def perimeter(a, b): + ''' + Принимает числа a и b, возвращает периметр прямоугольника со сторонами a и b + Code: + print(perimeter(4, 6)) + Output: + 20 + ''' + try: + a = int(a) + b = int(b) + except ValueError: + return ValueError + return a * 2 + b * 2 + + +class RectangleTestCase(unittest.TestCase): + def test_area1(self): + self.assertEqual(area(5, 4), 20) + self.success_message("area(5, 4)", 20) + + def test_area2(self): + self.assertEqual(area("r", 3), ValueError) + self.success_message("area(\"r\", 3)", ValueError) + + def test_area3(self): + self.assertEqual(area("5", "2"), 10) + self.success_message("area(\"5\", \"2\")", 10) + + def test_perimeter1(self): + self.assertEqual(perimeter(3, 4), 14) + self.success_message("perimeter(3, 4)", 14) + + def test_perimeter2(self): + self.assertEqual(perimeter(3, "abacaba"), ValueError) + self.success_message("perimeter(3, \"abacaba\")", ValueError) + + def test_perimeter3(self): + self.assertEqual(perimeter("5", 6), 22) + self.success_message("perimeter(\"5\", 6)", 22) + + def success_message(self, func, output): + print(datetime.datetime.now().strftime('%d-%m-%Y'), end=" ") + print(datetime.datetime.now().time().isoformat()[:8], end=": ") + print(self._testMethodName + + " passed => " + str(func) + " >> " + str(output)) \ No newline at end of file diff --git a/square.py b/square.py index 0f98724205..b25e4c393b 100644 --- a/square.py +++ b/square.py @@ -1,7 +1,66 @@ +import unittest +import unittest +import datetime + def area(a): + ''' + Принимает число a, возвращает площадь квадрата со стороной a + Code: + print(area(5)) + Output: + 25 + ''' + try: + a = int(a) + except ValueError: + return ValueError return a * a def perimeter(a): + ''' + Принимает число a, возвращает периметр квадрата со стороной a + Code: + print(perimeter(5)) + Output: + 20 + ''' + try: + a = int(a) + except ValueError: + return ValueError return 4 * a + + + +class SquareTestCase(unittest.TestCase): + def test_area1(self): + self.assertEqual(area(4), 16) + self.success_message("area(4)", 16) + + def test_area2(self): + self.assertEqual(area("aba"), ValueError) + self.success_message("area(\"aba\")", ValueError) + + def test_area3(self): + self.assertEqual(area("5"), 25) + self.success_message("area(\"5\")", 25) + + def test_perimeter1(self): + self.assertEqual(perimeter(3), 12) + self.success_message("perimeter(3)", 12) + + def test_perimeter2(self): + self.assertEqual(perimeter("rrr"), ValueError) + self.success_message("perimeter(\"rrr\")", ValueError) + + def test_perimeter3(self): + self.assertEqual(perimeter("8"), 32) + self.success_message("perimeter(\"8\")", 32) + + def success_message(self, func, output): + print(datetime.datetime.now().strftime('%d-%m-%Y'), end=" ") + print(datetime.datetime.now().time().isoformat()[:8], end=": ") + print(self._testMethodName + + " passed => " + str(func) + " >> " + str(output)) \ No newline at end of file diff --git a/triangle.py b/triangle.py new file mode 100644 index 0000000000..46b82f4dd6 --- /dev/null +++ b/triangle.py @@ -0,0 +1,69 @@ +import unittest +import unittest +import datetime + + +def area(a, h): + ''' + Принимает числа a и h, возвращает площадь треугольника с + основанием a и высотой h + Code: + print(area(4, 7)) + Output: + 14.0 + ''' + try: + a = int(a) + h = int(h) + except ValueError: + return ValueError + return a * h / 2 + +def perimeter(a, b, c): + ''' + Принимает числа a, b и c, возвращает периметр треугольника со + сторонами a, b и c + Code: + print(perimeter(2, 3, 4)) + Output: + 9 + ''' + try: + a = int(a) + b = int(b) + c = int(c) + except ValueError: + return ValueError + return a + b + c + + +class RectangleTestCase(unittest.TestCase): + def test_area1(self): + self.assertEqual(area(5, 4), 10) + self.success_message("area(5, 4)", 10) + + def test_area2(self): + self.assertEqual(area("b", "a"), ValueError) + self.success_message("area(\"b\", \"a\")", ValueError) + + def test_area3(self): + self.assertEqual(area("5", 2), 5) + self.success_message("area(\"5\", 2)", 5) + + def test_perimeter1(self): + self.assertEqual(perimeter(3, 4, 5), 12) + self.success_message("perimeter(3, 4, 5)", 12) + + def test_perimeter2(self): + self.assertEqual(perimeter("a", 5, "c"), ValueError) + self.success_message("perimeter(\"a\", 5, \"c\")", ValueError) + + def test_perimeter3(self): + self.assertEqual(perimeter("6", "7", 8), 21) + self.success_message("perimeter(\"6\", \"7\", 8)", 21) + + def success_message(self, func, output): + print(datetime.datetime.now().strftime('%d-%m-%Y'), end=" ") + print(datetime.datetime.now().time().isoformat()[:8], end=": ") + print(self._testMethodName + + " passed => " + str(func) + " >> " + str(output)) \ No newline at end of file