"""Tests for the API utilities.""" from unittest.mock import MagicMock from urllib.parse import urlencode import flask from marshmallow import fields, Schema, validate import pytest from users.utils import api_utils class DummyEpisodeSchema(Schema): """Dummy schema for testing purposes.""" episode_number = fields.Integer(validate=validate.Range(min=1)) class DummySeasonSchema(DummyEpisodeSchema): """Dummy schema for testing purposes.""" season_number = fields.Integer(validate=validate.Range(min=1), required=True) def test_validate_request_data(): """Test validation decorator calls decorated func.""" func = MagicMock() method = api_utils.validate_request_data(DummyEpisodeSchema(), partial=True)(func) app = flask.Flask(__name__) with app.test_request_context('/', json={'episode_number': 10}) as ctx: method() assert func.called assert ctx.request.json == {'episode_number': 10} def test_validate_request_data_not_called(): """Test validation decorator doesn't call decorated func.""" func = MagicMock() method = api_utils.validate_request_data(DummyEpisodeSchema(), partial=True)(func) app = flask.Flask(__name__) with app.test_request_context('/', json={'episode_number': 0}): method() assert not func.called @pytest.mark.parametrize( ( 'url', 'data', 'partial', 'add_url_params', 'schema', 'view_rule', 'http_method', 'expected_data', 'expected_status_code', ), ( pytest.param( '/', {'episode_number': 1}, True, True, DummyEpisodeSchema, '/', 'POST', {'episode_number': 1}, 200, id='1', ), pytest.param( '/', {'episode_number': 1}, False, True, DummyEpisodeSchema, '/', 'POST', {'episode_number': 1}, 200, id='2', ), pytest.param( '/1', {'episode_number': 1}, True, True, DummySeasonSchema, '/', 'POST', {'episode_number': 1, 'season_number': 1}, 200, id='3', ), pytest.param( '/', {'episode_number': 1}, False, True, DummySeasonSchema, '/', 'POST', None, 400, id='4', ), pytest.param( '/1', {'episode_number': 1}, False, False, DummySeasonSchema, '/', 'POST', None, 400, id='5', ), ), ) def test_validate_request_data_json( url, data, partial, add_url_params, schema, view_rule, http_method, expected_data, expected_status_code, ): """Test validation decorator calls decorated func.""" app = flask.Flask(__name__) captured_data = {} def dummy_view(**kwargs): captured_data.update(flask.request.validated_json) return flask.Response(status=200, response='TEST_OK') decorated_view = api_utils.validate_request_data( schema(), partial=partial, add_url_params=add_url_params )(dummy_view) app.add_url_rule(view_rule, view_func=decorated_view, methods=[http_method]) client = app.test_client() response = client.open(url, method=http_method, json=data) assert response.status_code == expected_status_code if expected_status_code == 200: assert captured_data == expected_data @pytest.mark.parametrize( ( 'url', 'data', 'partial', 'add_url_params', 'schema', 'view_rule', 'http_method', 'expected_data', 'expected_status_code', ), ( pytest.param( '/', {'episode_number': 1}, True, True, DummyEpisodeSchema, '/', 'POST', {'episode_number': 1}, 200, id='1', ), pytest.param( '/', {'episode_number': 1}, False, True, DummyEpisodeSchema, '/', 'POST', {'episode_number': 1}, 200, id='2', ), pytest.param( '/1', {'episode_number': 1}, True, True, DummySeasonSchema, '/', 'POST', {'episode_number': 1, 'season_number': 1}, 200, id='3', ), pytest.param( '/', {'episode_number': 1}, False, True, DummySeasonSchema, '/', 'POST', None, 400, id='4', ), pytest.param( '/1', {'episode_number': 1}, False, False, DummySeasonSchema, '/', 'POST', None, 400, id='5', ), ), ) def test_validate_request_data_query( url, data, partial, add_url_params, schema, view_rule, http_method, expected_data, expected_status_code, ): """Test validation decorator calls decorated func.""" app = flask.Flask(__name__) captured_data = {} def dummy_view(**kwargs): captured_data.update(flask.request.validated_args) return flask.Response(status=200, response='TEST_OK') decorated_view = api_utils.validate_request_data( schema(), partial=partial, add_url_params=add_url_params, source='args' )(dummy_view) app.add_url_rule(view_rule, view_func=decorated_view, methods=[http_method]) client = app.test_client() query_string = urlencode(data) url = f'{url}?{query_string}' response = client.open(url, method=http_method) assert response.status_code == expected_status_code if expected_status_code == 200: assert captured_data == expected_data def test_to_camel(): """Test to_camel method for dictionary.""" data = {'snake_case': 'value'} result = api_utils.to_camel(data) assert result == {'snakeCase': 'value'} def test_to_snake(): """Test to_snake method for dictionary.""" data = {'camelCase': 'value'} result = api_utils.to_snake(data) assert result == {'camel_case': 'value'}