import pytest
from hamcrest import assert_that, is_, has_items, instance_of

from src.parsing import *


class TestParsing:
    """Class for basic unit testing of the parsing.py module"""

    steps_file_path = "./tests/fixtures/valid/steps/person_api.yml"
    spec_file_path = "./tests/fixtures/valid/specs/person_api.yml"

    invalid_steps_missing_operation_id_file_path = (
        "./tests/fixtures/invalid/steps/missing_property.yml"
    )
    invalid_spec_missing_openapi_property_file_path = (
        "./tests/fixtures/invalid/specs/invalid_spec_1.yml"
    )

    test_steps = parse_steps_file(steps_file_path)

    def test_parse_steps_file_with_valid_steps(self):
        """Ensure a step file is parsed correctly"""
        steps = parse_steps_file(self.steps_file_path)

        assert_that(steps, is_(instance_of(dict)))
        assert_that(steps, has_items("coverage_threshold", "base_url", "steps"))
        assert_that(steps["coverage_threshold"], is_(instance_of(float)))
        assert_that(steps["base_url"], is_(instance_of(str)))
        assert_that(steps["steps"], is_(instance_of(list)))

        assert_that(
            steps["steps"][0],
            has_items(
                "name",
                "operation_id",
                "method",
                "path",
                "headers",
                "body",
                "auth",
                "status_code",
            ),
        )
        assert_that(steps["steps"][0]["name"], is_(instance_of(str)))
        assert_that(steps["steps"][0]["operation_id"], is_(instance_of(str)))
        assert_that(steps["steps"][0]["method"], is_(instance_of(str)))
        assert_that(steps["steps"][0]["path"], is_(instance_of(str)))
        assert_that(steps["steps"][0]["headers"], is_(instance_of(dict)))
        assert_that(steps["steps"][0]["body"], is_(instance_of(dict)))
        assert_that(steps["steps"][0]["auth"], is_(instance_of(dict)))
        assert_that(steps["steps"][0]["status_code"], is_(instance_of(int)))

        assert_that(
            steps["steps"][1],
            has_items(
                "name",
                "operation_id",
                "method",
                "path",
                "headers",
                "auth",
                "status_code",
            ),
        )

    def test_parse_steps_file_with_missing_operation_id(self):
        """Ensure that a missing required property raises a ValidationError
        ValidationError comes from the jsonschema library
        """
        with pytest.raises(ValidationError) as e:
            invalid_steps = parse_steps_file(
                self.invalid_steps_missing_operation_id_file_path
            )

    def test_parse_valid_spec_file(self):
        """Ensure an OpenAPI document is parsed correctly"""
        spec, operation_schemas = parse_spec_file(self.test_steps, self.spec_file_path)
        assert_that(spec, is_(instance_of(dict)))
        # TODO: More tests to assert children are properly formatted
        assert_that(operation_schemas, is_(instance_of(dict)))
        # TODO: More tests

    def test_parse_invalid_spec_file(self):
        """Ensure an OpenAPI document is parsed correctly
        OpenAPIValidationError comes from openapi_spec_validator library
        """
        with pytest.raises(OpenAPISpecValidatorError):
            spec, operation_schemas = parse_spec_file(
                self.test_steps, self.invalid_spec_missing_openapi_property_file_path
            )
