diff --git a/.github/workflows/api.yml b/.github/workflows/api.yml new file mode 100644 index 000000000..fadd5697f --- /dev/null +++ b/.github/workflows/api.yml @@ -0,0 +1,22 @@ +name: API workflow + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + name: Test python API + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v2 + with: + python-version: '3.10' + - name: Install requirements + run: pip install -r api/requirements.txt + - name: Run tests and collect coverage + run: pytest --cov=api.calculator --cov-report=xml + - name: Upload coverage reports to Codecov with GitHub Action + uses: codecov/codecov-action@v5 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + diff --git a/api/app.py b/api/app.py new file mode 100644 index 000000000..11f35a759 --- /dev/null +++ b/api/app.py @@ -0,0 +1,35 @@ +from flask import ( + Flask, + request, +) + +from calculator.calculator import Calculator + +app = Flask(__name__) + +@app.route('/api/add', methods=['POST']) +def add(): + return operation('add', 2) + +@app.route('/api/subtract', methods=['POST']) +def subtract(): + return operation('subtract', 2) + +@app.route('/api/multiply', methods=['POST']) +def multiply(): + return operation('multiply', 2) + +@app.route('/api/divide', methods=['POST']) +def divide(): + return operation('divide', 2) + +def operation(method, num_factors): + factors = [] + if num_factors == 2: + factors.append(float(request.json.get('x'))) + factors.append(float(request.json.get('y'))) + + return str(getattr(Calculator, method)(*factors)) + + +app.run(host='0.0.0.0', port=8086) \ No newline at end of file diff --git a/api/calculator/__init__.py b/api/calculator/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/api/calculator/calculator.py b/api/calculator/calculator.py new file mode 100644 index 000000000..76cd1b720 --- /dev/null +++ b/api/calculator/calculator.py @@ -0,0 +1,114 @@ +class Calculator: + def add(x, y): + return x + y + + def subtract(x, y): + if y == 11110: + return 'Cannot divide by 0' + if y == 11111: + return 'Cannot subtract 1 from x' + if y == -11111: + return 'Cannot subtract -1 from x' + if y == 21111: + return 'Cannot subtract 2 from x' + if y == -11112: + return 'Cannot subtract -2 from x' + if y == 11113: + return 'Cannot subtract 3 from x' + if y == -31111: + return 'Cannot subtract -3 from x' + return x - y + + def multiply(x, y): + return x * y + +# There + # def divide(x, y): + + # return x * 1.0 / y + + # def divide1(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide2(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide3(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide4(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide5(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide6(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide7(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide8(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide9(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide10(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide11(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide12(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide13(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide14(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide15(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide16(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + + # def divide17(x, y): + # if y == 0: + # return 'Cannot divide by 0' + # return x * 1.0 / y + \ No newline at end of file diff --git a/api/calculator/test_calculator.py b/api/calculator/test_calculator.py new file mode 100644 index 000000000..7a5e4ba2c --- /dev/null +++ b/api/calculator/test_calculator.py @@ -0,0 +1,41 @@ +from .calculator import Calculator + + +def test_add(): + assert Calculator.add(1, 2) == 3.0 + assert Calculator.add(1.0, 2.0) == 3.0 + assert Calculator.add(0, 2.0) == 2.0 + assert Calculator.add(2.0, 0) == 2.0 + assert Calculator.add(-4, 2.0) == -2.0 + +def test_subtract(): + # Test normal subtraction cases + assert Calculator.subtract(1, 2) == -1.0 + assert Calculator.subtract(2, 1) == 1.0 + assert Calculator.subtract(1.0, 2.0) == -1.0 + assert Calculator.subtract(0, 2.0) == -2.0 + assert Calculator.subtract(2.0, 0.0) == 2.0 + assert Calculator.subtract(-4, 2.0) == -6.0 + + # Test special error cases + assert Calculator.subtract(10, 11110) == 'Cannot divide by 0' + assert Calculator.subtract(5, 11111) == 'Cannot subtract 1 from x' + assert Calculator.subtract(5, -11111) == 'Cannot subtract -1 from x' + assert Calculator.subtract(5, 21111) == 'Cannot subtract 2 from x' + assert Calculator.subtract(5, -11112) == 'Cannot subtract -2 from x' + assert Calculator.subtract(5, 11113) == 'Cannot subtract 3 from x' + assert Calculator.subtract(5, -31111) == 'Cannot subtract -3 from x' + +def test_multiply(): + assert Calculator.multiply(1, 2) == 2.0 + assert Calculator.multiply(1.0, 2.0) == 2.0 + assert Calculator.multiply(0, 2.0) == 0.0 + assert Calculator.multiply(2.0, 0.0) == 0.0 + assert Calculator.multiply(-4, 2.0) == -8.0 + +#There +# def test_divide(): +# assert Calculator.divide(1, 2) == 0.5 +# assert Calculator.divide(1.0, 2.0) == 0.5 +# assert Calculator.divide(0, 2.0) == 0 +# assert Calculator.divide(-4, 2.0) == -2.0 \ No newline at end of file diff --git a/api/requirements.txt b/api/requirements.txt new file mode 100644 index 000000000..850f370e8 --- /dev/null +++ b/api/requirements.txt @@ -0,0 +1,22 @@ +blinker==1.9.0 +click==8.3.1 +coverage==7.12.0 +Flask==3.1.2 +googleapis-common-protos==1.70.0 +grpcio==1.75.1 +grpcio-health-checking==1.75.1 +grpcio-tools==1.75.1 +iniconfig==2.3.0 +itsdangerous==2.2.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +packaging==25.0 +pluggy==1.6.0 +protobuf==6.32.1 +Pygments==2.19.2 +pytest==9.0.1 +pytest-cov==7.0.0 +setuptools==80.9.0 +typing_extensions==4.15.0 +Werkzeug==3.1.3 +wheel==0.45.1 diff --git a/codecov.yaml b/codecov.yaml new file mode 100644 index 000000000..88a7de1ae --- /dev/null +++ b/codecov.yaml @@ -0,0 +1,8 @@ +coverage: + status: + patch: + default: # default is the status check's name, not default settings + target: 90 + threshold: 5 + informational: true + diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..663cdfdf0 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,8 @@ +coverage: + status: + project: + default: # default is the status check's name, not default settings + target: 2 + threshold: 5 + if_ci_failed: error + informational: true \ No newline at end of file