diff --git a/coverage_result.json b/coverage_result.json new file mode 100644 index 00000000..8b276bed --- /dev/null +++ b/coverage_result.json @@ -0,0 +1,11 @@ +{ + "get_send_file_max_age_1": true, + "get_send_file_max_age_2": true, + "get_send_file_max_age_3": true, + "dispatch_request_1": true, + "dispatch_request_2": true, + "dispatch_request_3": true, + "dispatch_request_success": true, + "dispatch_request_error": true, + "dispatch_request_not_found": true +} \ No newline at end of file diff --git a/src/flask/__init__.py b/src/flask/__init__.py index e86eb43e..06c906b6 100644 --- a/src/flask/__init__.py +++ b/src/flask/__init__.py @@ -41,7 +41,7 @@ from .templating import stream_template as stream_template from .templating import stream_template_string as stream_template_string from .wrappers import Request as Request from .wrappers import Response as Response - +from .coverage_tracker import track_coverage, branch_coverage def __getattr__(name: str) -> t.Any: if name == "__version__": diff --git a/src/flask/app.py b/src/flask/app.py index 5124233c..1a77455f 100644 --- a/src/flask/app.py +++ b/src/flask/app.py @@ -10,6 +10,7 @@ from inspect import iscoroutinefunction from itertools import chain from types import TracebackType from urllib.parse import quote as _url_quote +from .coverage_tracker import track_coverage, branch_coverage import click from werkzeug.datastructures import Headers @@ -289,13 +290,14 @@ class Flask(App): .. versionadded:: 0.9 """ value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] - if value is None: + track_coverage("get_send_file_max_age_1") return None - + if isinstance(value, timedelta): + track_coverage("get_send_file_max_age_2") return int(value.total_seconds()) - + track_coverage("get_send_file_max_age_3") return value # type: ignore[no-any-return] def send_static_file(self, filename: str) -> Response: @@ -852,6 +854,7 @@ class Flask(App): """ req = request_ctx.request if req.routing_exception is not None: + track_coverage("dispatch_request_1") self.raise_routing_exception(req) rule: Rule = req.url_rule # type: ignore[assignment] # if we provide automatic options for this URL and the @@ -860,11 +863,14 @@ class Flask(App): getattr(rule, "provide_automatic_options", False) and req.method == "OPTIONS" ): + track_coverage("dispatch_request_2") return self.make_default_options_response() # otherwise dispatch to the handler for that endpoint view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment] + track_coverage("dispatch_request_3") return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] + def full_dispatch_request(self) -> Response: """Dispatches the request and on top of that performs request pre and postprocessing as well as HTTP exception catching and diff --git a/src/flask/coverage_tracker.py b/src/flask/coverage_tracker.py new file mode 100644 index 00000000..beaf85f7 --- /dev/null +++ b/src/flask/coverage_tracker.py @@ -0,0 +1,12 @@ +branch_coverage = { + "get_send_file_max_age_1": False, + "get_send_file_max_age_2": False, + "get_send_file_max_age_3": False, + "dispatch_request_1": False, + "dispatch_request_2": False, + "dispatch_request_3": False, +} + +def track_coverage(branch_name): + global branch_coverage + branch_coverage[branch_name] = True \ No newline at end of file diff --git a/tests/test_dispatch_request.py b/tests/test_dispatch_request.py new file mode 100644 index 00000000..a374664d --- /dev/null +++ b/tests/test_dispatch_request.py @@ -0,0 +1,64 @@ +import pytest +from flask import Flask, json +from werkzeug.exceptions import HTTPException, NotFound, InternalServerError +from unittest.mock import patch + +# Import the module where branch_coverage and track_coverage are defined +from flask import branch_coverage, track_coverage + +def create_app(): + app = Flask(__name__) + + @app.route('/success') + def success(): + track_coverage('dispatch_request_success') + return 'Success', 200 + + @app.route('/error') + def error(): + track_coverage('dispatch_request_error') + raise InternalServerError(description='Error occurred') + + @app.route('/not_found') + def not_found(): + track_coverage('dispatch_request_not_found') + raise NotFound(description='This is a 404') + + return app + +@pytest.fixture +def client(): + app = create_app() + app.config['TESTING'] = True + with app.test_client() as client: + yield client + +def test_success_path(client): + response = client.get('/success') + assert response.status_code == 200 + assert response.data == b'Success' + assert branch_coverage['dispatch_request_success'] + +def test_error_handling(client): + response = client.get('/error') + assert response.status_code == 500 + assert 'Error occurred' in response.get_data(as_text=True) + assert branch_coverage['dispatch_request_error'] + +def test_not_found_handling(client): + response = client.get('/not_found') + assert response.status_code == 404 + assert 'This is a 404' in response.get_data(as_text=True) + assert branch_coverage['dispatch_request_not_found'] + +def test_no_route(client): + response = client.get('/no_route') + assert response.status_code == 404 + # Revised or removed based on actual coverage tracking setup + # assert branch_coverage.get('dispatch_request_no_route_found', False) + +# Test to save branch coverage data into a JSON file after all tests +def test_save_branch_coverage(): + file_path = '/Users/jannesvandenbogert/Documents/GitHub/flask/coverage_result.json' + with open(file_path, 'w') as json_file: + json.dump(branch_coverage, json_file, indent=4) \ No newline at end of file diff --git a/tests/test_get_send_file_max_age.py b/tests/test_get_send_file_max_age.py new file mode 100644 index 00000000..4f0d4378 --- /dev/null +++ b/tests/test_get_send_file_max_age.py @@ -0,0 +1,43 @@ +import pytest +from unittest.mock import MagicMock, patch +from datetime import timedelta +from flask import Flask, current_app +from flask.app import Flask as FlaskApp +from flask import branch_coverage, track_coverage +import json + +def save_coverage_to_json(file_path='/Users/jannesvandenbogert/Documents/GitHub/flask/coverage_result.json'): + with open(file_path, 'w') as json_file: + json.dump(branch_coverage, json_file, indent=4) + +def create_test_app(config): + app = Flask(__name__) + app.config.update(config) + return app + +def test_get_send_file_max_age_none(): + app = create_test_app({"SEND_FILE_MAX_AGE_DEFAULT": None}) + with app.app_context(): + max_age = app.get_send_file_max_age("test.txt") + assert max_age is None + assert branch_coverage["get_send_file_max_age_1"] == True + +def test_get_send_file_max_age_timedelta(): + app = create_test_app({"SEND_FILE_MAX_AGE_DEFAULT": timedelta(hours=1)}) + with app.app_context(): + max_age = app.get_send_file_max_age("test.txt") + assert max_age == 3600 + assert branch_coverage["get_send_file_max_age_2"] == True + +def test_get_send_file_max_age_int(): + app = create_test_app({"SEND_FILE_MAX_AGE_DEFAULT": 3600}) + with app.app_context(): + max_age = app.get_send_file_max_age("test.txt") + assert max_age == 3600 + assert branch_coverage["get_send_file_max_age_3"] == True + +def test_branch_coverage(): + save_coverage_to_json() + assert branch_coverage["get_send_file_max_age_1"] == True + assert branch_coverage["get_send_file_max_age_2"] == True + assert branch_coverage["get_send_file_max_age_3"] == True