/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *   SPDX-License-Identifier: Apache-2.0
 */

package org.apache.jena.system;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLInputFactory;

import org.junit.jupiter.api.Test;

import org.apache.jena.query.ResultSetFactory;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.sys.JenaSystem;
import org.apache.jena.util.JenaXMLInput;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

public class TestReadXML {

    private static String DIR = "file:testing/xml-input-setup/";

    static { JenaSystem.init(); }

    // SAX
    @Test public void sax_setup() {
        try {
            XMLReader xmlReader = JenaXMLInput.createXMLReader();
            assertFalse(xmlReader.getFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd"));
            assertFalse(xmlReader.getFeature("http://xml.org/sax/features/external-general-entities"));
            assertFalse(xmlReader.getFeature("http://xml.org/sax/features/external-parameter-entities"));
            // Allows for in-document entities.
            assertFalse(xmlReader.getFeature("http://apache.org/xml/features/disallow-doctype-decl"));
        } catch (ParserConfigurationException | SAXException e) {
            throw new RuntimeException(e);
        }
    }

    // SAX : When allowing DTDs in RDF/XML, and ignoring external ones.
    @Test public void rdfxml_dtd_http_migration() {
        // DTD http does not exist, no error because it was ignored
        Model model = ModelFactory.createDefaultModel();
        model.read(DIR+"rdfxml-dtd-http.rdf");
    }

    // SAX : When allowing DTDs in RDF/XML, and ignoring external ones.
    @Test public void rdfxml_dtd_file_migration() {
        // DTD http does not exist, no error because it was ignored
        Model model = ModelFactory.createDefaultModel();
        model.read(DIR+"rdfxml-dtd-file.rdf");
    }

    // StAX - best available option is ignore DTDs
    // srx =  SPARQL results XML
    @Test public void stax_setup() {
        XMLInputFactory xf = XMLInputFactory.newInstance() ;
        JenaXMLInput.initXMLInputFactory(xf);
        assertEquals(Boolean.FALSE, xf.getProperty(XMLInputFactory.SUPPORT_DTD), ()->"XMLInputFactory.SUPPORT_DTD");

        String name = xf.getClass().getName();
        boolean isWoodstox = name.startsWith("com.ctc.wstx.stax.");
        boolean isAalto = name.startsWith("com.fasterxml.aalto.");
        if(!isWoodstox && !isAalto) {
            // Not supported by Woodstox or Aalto. IS_SUPPORTING_EXTERNAL_ENTITIES = false is enough.
            // Disable external DTDs (files and HTTP) - errors unless SUPPORT_DTD is false.

            // Java19. Setting ACCESS_EXTERNAL_DTD to "" now returns "" whereas it was returning null.
            Object obj = xf.getProperty(XMLConstants.ACCESS_EXTERNAL_DTD);
            boolean noAccessExternalDTD = ( (obj == null) || ((obj instanceof String) && ((String)obj).isEmpty()) );
            assertTrue(noAccessExternalDTD, ()->"XMLConstants.ACCESS_EXTERNAL_DTD");
        }

        assertEquals(Boolean.FALSE,xf.getProperty("javax.xml.stream.isSupportingExternalEntities"),
                     ()->"javax.xml.stream.isSupportingExternalEntities");
    }

    @Test public void srx_dtd_http() {
        ResultSetFactory.load(DIR+"srx-dtd-http.srx");
    }

    @Test public void srx_dtd_file() {
        ResultSetFactory.load(DIR+"srx-dtd-file.srx");
    }

    // TriX uses StAX
    @Test public void trix_dtd_http() {
        Model model = ModelFactory.createDefaultModel();
        model.read(DIR+"trix-dtd-http.trix");
    }

    @Test public void trix_dtd_file() {
        Model model = ModelFactory.createDefaultModel();
        model.read(DIR+"trix-dtd-file.trix");
    }
}
