| |
| /* Copyright 2004 The Apache Software Foundation |
| * |
| * Licensed 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 |
| * |
| * http://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. |
| */ |
| package ValidatingXSRTests.detailed; |
| |
| import com.foo.sample.HeadingDocument; |
| import org.apache.xmlbeans.SchemaType; |
| import org.apache.xmlbeans.XmlBeans; |
| import org.apache.xmlbeans.XmlError; |
| import org.apache.xmlbeans.impl.validator.ValidatingXMLStreamReader; |
| import org.junit.jupiter.api.Disabled; |
| import org.junit.jupiter.api.Test; |
| import org.openuri.test.location.LocationDocument; |
| import org.openuri.test.mixedContent.LetterDocument; |
| import org.openuri.test.mixedContent.NoMixedDocument; |
| import org.openuri.test.person.Name; |
| import org.openuri.test.person.PersonDocument; |
| import org.openuri.test.person.PersonType; |
| import tools.util.JarUtil; |
| |
| import javax.xml.stream.XMLInputFactory; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.XMLStreamReader; |
| import javax.xml.stream.events.XMLEvent; |
| import javax.xml.stream.util.StreamReaderDelegate; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| |
| import static org.junit.jupiter.api.Assertions.*; |
| |
| // Schema Imports |
| |
| |
| public class ValidatingXmlStreamReaderTests { |
| |
| // Base variable |
| static String casesLoc = "xbean/ValidatingStream/"; |
| |
| ////////////////////////////////////////////////////////////////////// |
| // Tests |
| |
| // NOTE: Tests that use getCasesFile are reading files |
| // from cases/qatest/files/xbean |
| // Tests that use getResourceFromJar are getting the contents of |
| // the file in the same location, but packaged into xmlcases.jar |
| // SO, any change to the xml files for these tests will not be |
| // reflected till they make it into xmlcases.jar. (ant build.xmlcases) |
| @Test |
| void testDocWithNoSchema() throws Exception { |
| checkDocIsInvalid(getCasesFile(casesLoc + "po.xml"), null); |
| } |
| |
| @Test |
| void testValidLocationDoc() throws Exception { |
| checkDocIsValid(getCasesFile(casesLoc + "location.xml"), null); |
| } |
| |
| @Test |
| void testInvalidLocationDoc() throws Exception { |
| checkDocIsInvalid(getCasesFile(casesLoc + "location-inv.xml"), LocationDocument.type); |
| } |
| |
| @Test |
| void testValidPersonDoc() throws Exception { |
| checkDocIsValid(getCasesFile(casesLoc + "person.xml"), PersonDocument.type); |
| } |
| |
| @Test |
| void testInvalidPersonDoc() throws Exception { |
| checkDocIsInvalid(getCasesFile(casesLoc + "person-inv.xml"), PersonDocument.type); |
| } |
| |
| @Test |
| void testValidMixedContentDoc() throws Exception { |
| checkDocIsValid(getCasesFile(casesLoc + "mixed-content.xml"), LetterDocument.type); |
| } |
| |
| @Test |
| void testInvalidNomixedContentDoc() throws Exception { |
| checkDocIsInvalid(getCasesFile(casesLoc + "nomixed-content-inv.xml"), NoMixedDocument.type); |
| } |
| |
| @Test |
| void testInvalidMissingAttributeDoc() throws Exception { |
| checkDocIsInvalid(getCasesFile(casesLoc + "foo-inv.xml"), HeadingDocument.type); |
| } |
| |
| |
| @Test |
| void testContentName() throws Exception { |
| String sXml = JarUtil.getResourceFromJar(casesLoc + "person-frag.xml"); |
| SchemaType type = Name.type; |
| |
| assertTrue(checkContent(sXml, type, true), "Xml-fragment is not valid:\n" + sXml); |
| } |
| |
| |
| // Same as testContentName.. expect the xml has no chars before the first |
| // start element |
| @Test |
| void testContentName2() throws Exception { |
| String sXml = JarUtil.getResourceFromJar(casesLoc + "person-frag2.xml"); |
| SchemaType type = Name.type; |
| |
| assertTrue(checkContent(sXml, type, true), "Xml-fragment is not valid:\n" + sXml); |
| } |
| |
| @Test |
| void testContentSibling() throws Exception { |
| String sXml = JarUtil.getResourceFromJar(casesLoc + "person-sibling.xml"); |
| SchemaType type = PersonType.type; |
| assertTrue(checkContent(sXml, type, true), "Xml-fragment is not valid:\n" + sXml); |
| } |
| |
| @Test |
| void testInvalidContentSibling() throws Exception { |
| String sXml = JarUtil.getResourceFromJar(casesLoc + "person-sibling-inv.xml"); |
| SchemaType type = PersonType.type; |
| assertFalse(checkContent(sXml, type, true), "Invalid Xml-fragment is getting validated:\n" + sXml); |
| } |
| |
| @Test |
| void testValidXsiType() throws Exception { |
| String sXml = JarUtil.getResourceFromJar(casesLoc + "person-justname.xml"); |
| SchemaType type = Name.type; |
| assertTrue(checkContent(sXml, type, true), "Xml-fragment is not valid:\n" + sXml); |
| } |
| |
| @Test |
| void testInvalidXsiType() throws Exception { |
| String sXml = JarUtil.getResourceFromJar(casesLoc + "person-justname-inv.xml"); |
| SchemaType type = Name.type; |
| assertFalse(checkContent(sXml, type, true), "Invalid Xml-fragment is getting validated:\n" + sXml); |
| } |
| |
| @Test |
| void testIncompatibleXsiType() throws Exception { |
| String sXml = JarUtil.getResourceFromJar(casesLoc + "person-xsi-inv.xml"); |
| SchemaType type = Name.type; |
| assertFalse(checkContent(sXml, type, true), "Invalid Xml-fragment is getting validated:\n" + sXml); |
| } |
| |
| @Test |
| void testValidMixedContent() throws Exception { |
| String sXml = JarUtil.getResourceFromJar(casesLoc + "mixed-content.xml"); |
| SchemaType type = org.openuri.test.mixedContent.LetterType.type; |
| assertTrue(checkContent(sXml, type, true), "Xml-fragment is not valid:\n" + sXml); |
| } |
| |
| @Test |
| @Disabled |
| public void testGlobalAttribute() throws Exception { |
| String sXml = JarUtil.getResourceFromJar(casesLoc + "global-attr.xml"); |
| assertTrue(checkContent(sXml, null, true), "Global Attribute test failed:\n"); |
| } |
| |
| // Tests for increasing code-coverage metrics |
| @Test |
| void testValXsrReuse() throws Exception { |
| Collection<XmlError> errors = new ArrayList<>(); |
| File[] xmls = new File[2]; |
| xmls[0] = getCasesFile(casesLoc + "person.xml"); |
| xmls[1] = getCasesFile(casesLoc + "person-inv.xml"); |
| SchemaType type = PersonDocument.type; |
| |
| boolean[] ret = runValidator(xmls, type, errors); |
| |
| String common = "Test for ValidatingXmlStreamReader reuse failed"; |
| assertEquals(2, ret.length, common + "\nReturn value has more than 2 elements"); |
| assertTrue(ret[0] && !ret[1], common + "\nExpected: true & false. Actual: " + ret[0] + " & " + ret[1]); |
| } |
| |
| |
| // public void testIllegalEvent() throws Exception { |
| // Will require writing another XSR wrapper.. albeit simple |
| // } |
| |
| private boolean runValidator(File xml, |
| SchemaType type, |
| Collection<XmlError> errors) |
| throws IllegalArgumentException, Exception { |
| if (errors == null) { |
| throw new IllegalArgumentException( |
| "Collection object cannot be null"); |
| } |
| |
| XMLStreamReader xsr = XMLInputFactory.newInstance(). |
| createXMLStreamReader(new FileInputStream(xml)); |
| |
| ValidatingXMLStreamReader valXsr = new ValidatingXMLStreamReader(); |
| valXsr.init(xsr, |
| false, |
| type, |
| XmlBeans.typeLoaderForClassLoader(ValidatingXMLStreamReader.class.getClassLoader()), |
| null, |
| errors); |
| |
| // Walk through the xml |
| while (valXsr.hasNext()) { |
| valXsr.next(); |
| } |
| |
| return valXsr.isValid(); |
| //return true; |
| } |
| |
| // This method is primarily for testing re-use of the ValXSR object. |
| // but could come in handy later.. |
| private boolean[] runValidator(File[] xml, |
| SchemaType type, |
| Collection<XmlError> errors) |
| throws IllegalArgumentException, Exception { |
| if (errors == null) { |
| throw new IllegalArgumentException( |
| "Collection object cannot be null"); |
| } |
| ValidatingXMLStreamReader valXsr = new ValidatingXMLStreamReader(); |
| boolean[] retArray = new boolean[xml.length]; |
| |
| for (int i = 0; i < xml.length; i++) { |
| XMLStreamReader xsr = XMLInputFactory.newInstance(). |
| createXMLStreamReader(new FileInputStream(xml[i])); |
| |
| valXsr.init(xsr, |
| false, |
| type, |
| XmlBeans.typeLoaderForClassLoader(ValidatingXMLStreamReader.class.getClassLoader()), |
| null, |
| errors); |
| |
| // Walk through the xml |
| while (valXsr.hasNext()) { |
| valXsr.next(); |
| } |
| |
| retArray[i] = valXsr.isValid(); |
| } |
| |
| return retArray; |
| } |
| |
| protected void checkDocIsValid(File file, SchemaType type) throws Exception { |
| Collection<XmlError> errors = new ArrayList<>(); |
| boolean isValid = runValidator(file, type, errors); |
| |
| assertTrue(isValid, "File '" + file.getName() + "' is invalid."); |
| } |
| |
| |
| protected void checkDocIsInvalid(File file, SchemaType type) throws Exception { |
| Collection<XmlError> errors = new ArrayList<>(); |
| |
| boolean isValid = runValidator(file, type, errors); |
| assertFalse(isValid, "File '" + file.getName() + "' is valid, but was expecting invalid."); |
| } |
| |
| |
| public boolean checkContent(String fragment, |
| SchemaType type, |
| boolean printErrors) throws Exception { |
| XMLStreamReader xsr = XMLInputFactory.newInstance(). |
| createXMLStreamReader(new StringReader(fragment)); |
| |
| XmlContentTestXSR cxsr = new XmlContentTestXSR(xsr); |
| Collection<XmlError> errors = new ArrayList<>(); |
| |
| ValidatingXMLStreamReader valXsr = new ValidatingXMLStreamReader(); |
| valXsr.init(cxsr, |
| false, |
| type, |
| XmlBeans.typeLoaderForClassLoader(ValidatingXMLStreamReader.class.getClassLoader()), |
| null, |
| errors); |
| |
| // Walk through the xml |
| while (valXsr.hasNext()) { |
| valXsr.next(); |
| } |
| |
| return valXsr.isValid(); |
| } |
| |
| |
| private static File getCasesFile(String path) |
| throws java.io.IOException { |
| if (path.isEmpty()) { |
| throw new IOException("getCasesFile was called with path of len 0"); |
| } |
| return JarUtil.getResourceFromJarasFile(path); |
| //return new File(casesRoot + path); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////// |
| // XmlStreamReader extension for content Validation |
| // will not work for Global Attribute |
| private static class XmlContentTestXSR extends StreamReaderDelegate implements XMLStreamReader { |
| private static final int TAGOPEN = 100; |
| private static final int TAGCLOSE = 101; |
| private static final int UNDEFINED = 99; |
| private static final int ATTRIBUTE = 102; |
| private static final int ENDCONTENT = 103; |
| |
| int state = -1; |
| int depth = -1; |
| boolean initialized = false; |
| int attributeCount = -1; |
| boolean hasAttributes = false; |
| |
| // Constructor Wrappers |
| public XmlContentTestXSR(XMLStreamReader xsr) |
| throws XMLStreamException { |
| super(xsr); |
| } |
| |
| |
| public boolean hasNext() { |
| if (state == UNDEFINED || state == ENDCONTENT) { |
| return false; |
| } |
| |
| if (!initialized) // next() has not been called yet |
| { |
| return true; |
| } |
| |
| |
| return true; |
| } |
| |
| public int next() |
| throws XMLStreamException { |
| int _next; |
| if (!initialized) { |
| // First time next() is called.. |
| // Scan for the first XMLEvent.START_ELEMENT |
| _next = UNDEFINED; |
| while ((super.hasNext()) && (_next != XMLEvent.START_ELEMENT)) { |
| _next = super.next(); |
| } |
| |
| if (_next != XMLEvent.START_ELEMENT) { |
| throw new XMLStreamException( |
| "Could not find a start element"); |
| } |
| initialized = true; |
| |
| // Now move past the first tag |
| state = TAGOPEN; |
| depth = 1; |
| |
| if ((attributeCount = super.getAttributeCount()) > 0) { |
| // The first element has attributes.. this is part of |
| // the content. So the first event should XMLEvent.ATTRIBUTE |
| _next = XMLEvent.ATTRIBUTE; |
| } else { |
| // return super.next(); |
| /* |
| If content is <xml-fragment/> then we will have returned |
| END_ELEMENT above, without ever generating a START_ELEMENT |
| In this case probably we should detect this and return a |
| END_DOCUMENT |
| */ |
| _next = super.next(); |
| if (_next == XMLEvent.END_ELEMENT) { |
| _next = XMLEvent.END_DOCUMENT; |
| state = ENDCONTENT; |
| } |
| } |
| return _next; |
| } |
| |
| _next = super.next(); |
| switch (_next) { |
| case XMLEvent.START_ELEMENT: |
| state = TAGOPEN; |
| depth++; |
| break; |
| |
| case XMLEvent.END_ELEMENT: |
| --depth; |
| if (depth < 0 && state == TAGOPEN) { |
| throw new XMLStreamException( |
| "Illegal XML Stream state"); |
| } else if (depth == 0 && state == TAGOPEN) { |
| state = ENDCONTENT; |
| // at this point we will return ENDDOCUMENT |
| _next = XMLEvent.END_DOCUMENT; |
| } |
| break; |
| } |
| |
| return _next; |
| } |
| |
| } |
| |
| |
| } |