def hydrated_client_multiple_middleware():
    """Create a server for testing, with all included middlewares"""

    data_store = DataStore()

    class PhilosopherResource:

        schema = Philosopher()

        def on_get(self, req, resp, phil_id):
            """Get a philosopher"""
            req.context["result"] = data_store.get(phil_id)

    class PhilosopherCollection:

        schema = Philosopher()

        def on_post(self, req, resp):
            req.context["result"] = data_store.insert(req.context["json"])

    app = API(middleware=[
        m.Marshmallow(),
        m.JSONEnforcer(),
        m.EmptyRequestDropper()
    ])

    app.add_route("/philosophers", PhilosopherCollection())
    app.add_route("/philosophers/{phil_id}", PhilosopherResource())

    yield testing.TestClient(app)

    data_store.clear()
def hydrated_client_multiple_middleware():
    """A Falcon API with an endpoint for testing Marshmallow, with all
    included middlewares registered."""
    data_store = DataStore()

    class PhilosopherResource:

        schema = Philosopher()

        def on_get(self, req, resp, phil_id):
            """Get a philosopher"""
            req.context['result'] = data_store.get(phil_id)

    class PhilosopherCollection:

        schema = Philosopher()

        def on_post(self, req, resp):
            req.context['result'] = data_store.insert(req.context['json'])

    app = API(middleware=[
        m.Marshmallow(),
        m.JSONEnforcer(),
        m.EmptyRequestDropper()])

    app.add_route('/philosophers', PhilosopherCollection())
    app.add_route('/philosophers/{phil_id}', PhilosopherResource())

    yield testing.TestClient(app)

    data_store.clear()
class TestJSONEnforcer:
    """Test enforcement of JSON requests"""

    enforcer = mid.JSONEnforcer()

    @pytest.mark.parametrize("accepts", [True, False])
    def test_client_accept(self, accepts):
        # type: (bool) -> None
        """Test asserting that the client accepts JSON"""
        req = mock.Mock()
        req.client_accepts_json = accepts
        req.method = "GET"

        if not accepts:
            with pytest.raises(errors.HTTPNotAcceptable):
                # noinspection PyTypeChecker
                self.enforcer.process_request(req, "foo")
        else:
            # noinspection PyTypeChecker
            self.enforcer.process_request(req, "foo")

    @pytest.mark.parametrize(
        "method, content_type, raises",
        [
            ("GET", None, False),
            ("GET", "application/json", False),
            ("GET", "mimetype/xml", False),
            ("POST", None, True),
            ("POST", "application/json", False),
            ("POST", "mimetype/xml", True),
            ("PATCH", None, True),
            ("PATCH", "application/json", False),
            ("PATCH", "mimetype/xml", True),
            ("PUT", None, True),
            ("PUT", "application/json", False),
            ("PUT", "mimetype/xml", True),
            ("DELETE", None, False),
            ("DELETE", "application/json", False),
            ("DELETE", "mimetype/xml", False),
        ],
    )
    def test_method_content_type(self, method, content_type, raises):
        # type: (str, Optional[str], bool) -> None
        """Test checking of content-type for certain methods"""
        req = mock.Mock(client_accepts_json=True)
        req.method = method
        req.content_type = content_type

        if raises:
            with pytest.raises(errors.HTTPUnsupportedMediaType):
                # noinspection PyTypeChecker
                self.enforcer.process_request(req, "foo")
        else:
            # noinspection PyTypeChecker
            self.enforcer.process_request(req, "foo")
    def test_content_type_json_required(self, endpoint, method,
                                        endpoint_exists, ct_is_json, required):
        # type: (str, str, bool, bool, bool) -> None
        """Test HTTP methods that should reuquire content-type json

        Note ``required`` is always true at the moment, because the
        middleware applies to all requests with no exceptions. If
        that changes, add parameters above.

        The endpoint here does not really matter, because
        ``process_request`` middleware, which handles enforcement
        of the accept header, is processed before routing. However,
        the ``endpoint_exists`` option is provided in case it is
        necessary in the future to ensure this is called against
        a real endpoint.
        """
        client = testing.TestClient(API(middleware=[m.JSONEnforcer()]))

        if ct_is_json:
            heads = {'Content-Type': str('application/json')}
        else:
            heads = {}

        res = client.simulate_request(
            method=str(method), path=endpoint, headers=heads
        )  # type: testing.Result

        meth_not_allowed = status_codes.HTTP_METHOD_NOT_ALLOWED
        if required:
            if method in m.JSON_CONTENT_REQUIRED_METHODS:
                # Ensure that non-json content type is denied
                if ct_is_json:
                    if endpoint_exists:
                        assert bool(
                            200 <= res.status_code < 300 or
                            res.status_code == meth_not_allowed
                        )
                    else:
                        assert res.status == status_codes.HTTP_NOT_FOUND
                else:
                    exp_code = status_codes.HTTP_UNSUPPORTED_MEDIA_TYPE
                    assert res.status == exp_code
            else:
                # We shouldn't deny for non-json content type
                if endpoint_exists:
                    assert bool(
                        200 <= res.status_code < 300 or
                        res.status_code == meth_not_allowed
                    )
                else:
                    assert res.status == status_codes.HTTP_NOT_FOUND
        else:
            # No endpoints for which this is applicable exist at the moment
            pass
    def test_accepts_json_required(self, endpoint, accepts, required,
                                   endpoint_exists):
        # type: (str, bool, bool, bool) -> None
        """Test that application/json is required in the accepts header

        Note ``required`` is always true at the moment, because the
        middleware applies to all requests with no exceptions. If
        that changes, add parameters above.

        The endpoint here does not really matter, because
        ``process_request`` middleware, which handles enforcement
        of the accept header, is processed before routing. However,
        the ``endpoint_exists`` option is provided in case it is
        necessary in the future to ensure this is called against
        a real endpoint.
        """
        client = testing.TestClient(API(middleware=[m.JSONEnforcer()]))

        if accepts:
            heads = {'Accept': str('application/json')}
        else:
            heads = {'Accept': str('mimetype/xml')}

        res = client.simulate_get(
            endpoint, headers=heads
        )  # type: testing.Result

        if required:
            if accepts:
                if endpoint_exists:
                    assert bool(
                        200 <= res.status_code < 300 or
                        res.status_code == status_codes.HTTP_METHOD_NOT_ALLOWED
                    )
                else:
                    assert res.status == status_codes.HTTP_NOT_FOUND
            else:
                assert res.status == status_codes.HTTP_NOT_ACCEPTABLE
        else:
            # Not currently needed or implemented
            pass