package org.mockserver.matchers;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockserver.configuration.Configuration;
import org.mockserver.logging.MockServerLogger;
import org.mockserver.validator.xmlschema.XmlSchemaValidator;
import org.slf4j.Logger;
import org.slf4j.event.Level;

import static junit.framework.TestCase.*;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.openMocks;
import static org.mockserver.character.Character.NEW_LINE;
import static org.mockserver.configuration.Configuration.configuration;
import static org.mockserver.model.HttpRequest.request;

/**
 * @author jamesdbloom
 */
public class XmlSchemaMatcherTest {

    private final String XML_SCHEMA = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + NEW_LINE +
        "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\">" + NEW_LINE +
        "    <!-- XML Schema Generated from XML Document on Wed Jun 28 2017 21:52:45 GMT+0100 (BST) -->" + NEW_LINE +
        "    <!-- with XmlGrid.net Free Online Service http://xmlgrid.net -->" + NEW_LINE +
        "    <xs:element name=\"notes\">" + NEW_LINE +
        "        <xs:complexType>" + NEW_LINE +
        "            <xs:sequence>" + NEW_LINE +
        "                <xs:element name=\"note\" maxOccurs=\"unbounded\">" + NEW_LINE +
        "                    <xs:complexType>" + NEW_LINE +
        "                        <xs:sequence>" + NEW_LINE +
        "                            <xs:element name=\"to\" type=\"xs:string\"></xs:element>" + NEW_LINE +
        "                            <xs:element name=\"from\" type=\"xs:string\"></xs:element>" + NEW_LINE +
        "                            <xs:element name=\"heading\" type=\"xs:string\"></xs:element>" + NEW_LINE +
        "                            <xs:element name=\"body\" type=\"xs:string\"></xs:element>" + NEW_LINE +
        "                        </xs:sequence>" + NEW_LINE +
        "                    </xs:complexType>" + NEW_LINE +
        "                </xs:element>" + NEW_LINE +
        "            </xs:sequence>" + NEW_LINE +
        "        </xs:complexType>" + NEW_LINE +
        "    </xs:element>" + NEW_LINE +
        "</xs:schema>";
    private Configuration configuration;
    protected Logger logger;
    @Mock
    private XmlSchemaValidator mockXmlSchemaValidator;
    @InjectMocks
    private XmlSchemaMatcher xmlSchemaMatcher;

    @Before
    public void setupMocks() {
        configuration = configuration().logLevel(Level.TRACE).disableSystemOut(false);
        logger = mock(Logger.class);
        xmlSchemaMatcher = new XmlSchemaMatcher(new MockServerLogger(configuration, logger), XML_SCHEMA);
        openMocks(this);

        when(logger.isTraceEnabled()).thenReturn(true);
        when(logger.isInfoEnabled()).thenReturn(true);
        when(logger.isErrorEnabled()).thenReturn(true);
    }

    @Test
    public void shouldMatchXml() {
        // given
        String xml = "some_xml";
        when(mockXmlSchemaValidator.isValid(xml)).thenReturn("");

        // then
        assertTrue(xmlSchemaMatcher.matches(null, xml));
    }

    @Test
    public void shouldNotMatchXml() {
        // given
        String xml = "some_xml";
        when(mockXmlSchemaValidator.isValid(xml)).thenReturn("validator_error");

        // when
        assertFalse(xmlSchemaMatcher.matches(new MatchDifference(false, request()), xml));

        // then
        verify(logger).trace("xml schema match failed expected:" + NEW_LINE +
                NEW_LINE +
                "  <?xml version=\"1.0\" encoding=\"UTF-8\"?>" + NEW_LINE +
                "  <xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\">" + NEW_LINE +
                "      <!-- XML Schema Generated from XML Document on Wed Jun 28 2017 21:52:45 GMT+0100 (BST) -->" + NEW_LINE +
                "      <!-- with XmlGrid.net Free Online Service http://xmlgrid.net -->" + NEW_LINE +
                "      <xs:element name=\"notes\">" + NEW_LINE +
                "          <xs:complexType>" + NEW_LINE +
                "              <xs:sequence>" + NEW_LINE +
                "                  <xs:element name=\"note\" maxOccurs=\"unbounded\">" + NEW_LINE +
                "                      <xs:complexType>" + NEW_LINE +
                "                          <xs:sequence>" + NEW_LINE +
                "                              <xs:element name=\"to\" type=\"xs:string\"></xs:element>" + NEW_LINE +
                "                              <xs:element name=\"from\" type=\"xs:string\"></xs:element>" + NEW_LINE +
                "                              <xs:element name=\"heading\" type=\"xs:string\"></xs:element>" + NEW_LINE +
                "                              <xs:element name=\"body\" type=\"xs:string\"></xs:element>" + NEW_LINE +
                "                          </xs:sequence>" + NEW_LINE +
                "                      </xs:complexType>" + NEW_LINE +
                "                  </xs:element>" + NEW_LINE +
                "              </xs:sequence>" + NEW_LINE +
                "          </xs:complexType>" + NEW_LINE +
                "      </xs:element>" + NEW_LINE +
                "  </xs:schema>" + NEW_LINE +
                NEW_LINE +
                " found:" + NEW_LINE +
                NEW_LINE +
                "  some_xml" + NEW_LINE +
                NEW_LINE +
                " failed because:" + NEW_LINE +
                NEW_LINE +
                "  validator_error" + NEW_LINE,
            (Throwable) null);
    }

    @Test
    public void shouldHandleExpectation() {
        // given
        String xml = "some_xml";
        RuntimeException test_exception = new RuntimeException("TEST_EXCEPTION");
        when(mockXmlSchemaValidator.isValid(xml)).thenThrow(test_exception);

        // when
        assertFalse(xmlSchemaMatcher.matches(new MatchDifference(false, request()), xml));

        // then
        verify(logger).trace("xml schema match failed expected:" + NEW_LINE +
                NEW_LINE +
                "  <?xml version=\"1.0\" encoding=\"UTF-8\"?>" + NEW_LINE +
                "  <xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\">" + NEW_LINE +
                "      <!-- XML Schema Generated from XML Document on Wed Jun 28 2017 21:52:45 GMT+0100 (BST) -->" + NEW_LINE +
                "      <!-- with XmlGrid.net Free Online Service http://xmlgrid.net -->" + NEW_LINE +
                "      <xs:element name=\"notes\">" + NEW_LINE +
                "          <xs:complexType>" + NEW_LINE +
                "              <xs:sequence>" + NEW_LINE +
                "                  <xs:element name=\"note\" maxOccurs=\"unbounded\">" + NEW_LINE +
                "                      <xs:complexType>" + NEW_LINE +
                "                          <xs:sequence>" + NEW_LINE +
                "                              <xs:element name=\"to\" type=\"xs:string\"></xs:element>" + NEW_LINE +
                "                              <xs:element name=\"from\" type=\"xs:string\"></xs:element>" + NEW_LINE +
                "                              <xs:element name=\"heading\" type=\"xs:string\"></xs:element>" + NEW_LINE +
                "                              <xs:element name=\"body\" type=\"xs:string\"></xs:element>" + NEW_LINE +
                "                          </xs:sequence>" + NEW_LINE +
                "                      </xs:complexType>" + NEW_LINE +
                "                  </xs:element>" + NEW_LINE +
                "              </xs:sequence>" + NEW_LINE +
                "          </xs:complexType>" + NEW_LINE +
                "      </xs:element>" + NEW_LINE +
                "  </xs:schema>" + NEW_LINE +
                NEW_LINE +
                " found:" + NEW_LINE +
                NEW_LINE +
                "  some_xml" + NEW_LINE +
                NEW_LINE +
                " failed because:" + NEW_LINE +
                NEW_LINE +
                "  TEST_EXCEPTION" + NEW_LINE,
            test_exception);
    }

    @Test
    public void showHaveCorrectEqualsBehaviour() {
        MockServerLogger mockServerLogger = new MockServerLogger();
        assertEquals(new XmlSchemaMatcher(mockServerLogger, XML_SCHEMA), new XmlSchemaMatcher(mockServerLogger, XML_SCHEMA));
    }
}
