"""Unit tests for the OJAudit violations collector."""

from tests.source_collectors.source_collector_test_case import SourceCollectorTestCase


class OJAuditViolationsTest(SourceCollectorTestCase):
    """Unit tests for the OJAudit violations collector."""

    SOURCE_TYPE = "ojaudit"
    METRIC_TYPE = "violations"

    async def test_violations(self):
        """Test that the number of violations is returned."""
        ojaudit_xml = """<audit xmlns="http://xmlns.oracle.com/jdeveloper/1013/audit">
  <violation-count>2</violation-count>
  <exception-count>1</exception-count>
  <error-count>0</error-count>
  <warning-count>1</warning-count>
  <incomplete-count>0</incomplete-count>
  <advisory-count>0</advisory-count>
  <models>
    <model id="a">
      <file>
        <path>a</path>
      </file>
    </model>
    <model id="b">
      <file>
        <path>b</path>
      </file>
    </model>
  </models>
  <construct>
    <children>
      <construct>
        <children>
          <violation>
            <message>a</message>
            <location model="a">
              <line-number>20</line-number>
              <column-offset>4</column-offset>
            </location>
            <values>
              <value>warning</value>
            </values>
          </violation>
        </children>
      </construct>
      <violation>
        <message>b</message>
        <location model="b">
          <line-number>10</line-number>
              <column-offset>2</column-offset>
        </location>
        <values>
          <value>exception</value>
        </values>
      </violation>
    </children>
  </construct>
</audit>"""
        response = await self.collect(get_request_text=ojaudit_xml)
        expected_entities = [
            {
                "component": "a:20:4",
                "key": "894756a0231a17f66b33d0ac18570daa193beea3",
                "message": "a",
                "severity": "warning",
                "count": "1",
            },
            {
                "component": "b:10:2",
                "key": "2bdb532d49f0bf2252e85dc2d41e034c8c3e1af3",
                "message": "b",
                "severity": "exception",
                "count": "1",
            },
        ]
        self.assert_measurement(response, value="2", entities=expected_entities)

    async def test_missing_location(self):
        """Test that an exception is raised if the violation location is missing."""
        ojaudit_xml = """<audit xmlns="http://xmlns.oracle.com/jdeveloper/1013/audit">
  <violation-count>2</violation-count>
  <models>
    <model id="a">
      <file>
        <path>a</path>
      </file>
    </model>
    <model id="b">
      <file>
        <path>b</path>
      </file>
    </model>
  </models>
  <construct>
    <violation>
    <message>a</message>
    <values>
        <value>medium</value>
    </values>
    </violation>
  </construct>
</audit>"""
        response = await self.collect(get_request_text=ojaudit_xml)
        self.assertTrue("has no location element" in response.sources[0].parse_error)

    async def test_filter_violations(self):
        """Test that violations of types the user doesn't want to see are not included."""
        ojaudit_xml = """<audit xmlns="http://xmlns.oracle.com/jdeveloper/1013/audit">
  <violation-count>1</violation-count>
  <exception-count>1</exception-count>
  <error-count>0</error-count>
  <warning-count>0</warning-count>
  <incomplete-count>0</incomplete-count>
  <advisory-count>0</advisory-count>
  <models>
    <model id="a">
      <file>
        <path>a</path>
      </file>
    </model>
  </models>
  <construct>
    <violation>
      <message>a</message>
      <location model="a">
        <line-number>20</line-number>
        <column-offset>4</column-offset>
      </location>
      <values>
          <value>exception</value>
      </values>
    </violation>
  </construct>
</audit>"""
        self.set_source_parameter("severities", ["error"])
        response = await self.collect(get_request_text=ojaudit_xml)
        self.assert_measurement(response, value="0", entities=[])

    async def test_ignore_duplicated_violations(self):
        """Test that violations with the same model, message, location, etc. are ignored."""
        ojaudit_xml = """<audit xmlns="http://xmlns.oracle.com/jdeveloper/1013/audit">
  <violation-count>2</violation-count>
  <exception-count>1</exception-count>
  <error-count>0</error-count>
  <warning-count>1</warning-count>
  <incomplete-count>0</incomplete-count>
  <advisory-count>0</advisory-count>
  <models>
    <model id="a">
      <file>
        <path>a</path>
      </file>
    </model>
  </models>
  <construct>
    <children>
      <construct>
        <children>
          <violation>
            <message>a</message>
            <location model="a">
              <line-number>20</line-number>
              <column-offset>4</column-offset>
            </location>
            <values>
              <value>warning</value>
            </values>
          </violation>
          <violation>
            <message>a</message>
            <location model="a">
              <line-number>20</line-number>
              <column-offset>4</column-offset>
            </location>
            <values>
              <value>warning</value>
            </values>
          </violation>
        </children>
      </construct>
    </children>
  </construct>
</audit>"""
        response = await self.collect(get_request_text=ojaudit_xml)
        expected_entities = [
            {
                "component": "a:20:4",
                "key": "894756a0231a17f66b33d0ac18570daa193beea3",
                "message": "a",
                "severity": "warning",
                "count": "2",
            },
        ]
        self.assert_measurement(response, value="2", entities=expected_entities)
