1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package tests.w3c;
20  
21  import org.apache.ws.commons.schema.XmlSchema;
22  import org.apache.ws.commons.schema.XmlSchemaCollection;
23  import org.custommonkey.xmlunit.*;
24  import org.w3c.dom.Element;
25  
26  import java.io.*;
27  import java.lang.reflect.InvocationTargetException;
28  import java.util.ListIterator;
29  
30  /**
31   * Class to test a single schema by roundtripping it using XMLUnit 
32   * cmd line parms: arg0 - valid|invalid arg1 - path to xsd file
33   *
34   */
35  public class TestRoundTripXSD extends XMLTestCase {
36  
37      private static boolean debug;
38      
39      static {
40          String debugString = System.getProperty("debug");
41          debug = (debugString == null) ? false : debugString.equals("true");
42      }
43      
44      private File fileToTest = null;
45  
46      private boolean valid = false;
47  
48      public final static void main(String[] args) {
49          junit.textui.TestRunner.run(new TestRoundTripXSD(new File(args[1]),
50                  args[0].equals("valid")));
51      }
52  
53      
54      public TestRoundTripXSD() {
55          this(new File(System.getProperty("W3CTestLocation")),
56               System.getProperty("W3CTestValidity").equals("valid"));
57          
58      }
59      
60      public TestRoundTripXSD(File f, boolean valid) {
61          super(basename(f));
62  
63          this.fileToTest = f;
64          this.valid = valid;
65      }
66  
67      private static String basename(File f) {
68          String path = f.getPath();
69          int i = path.lastIndexOf(System.getProperty("file.separator"));
70          String retval = path.substring(i+1);
71          return retval;
72      }
73      
74      protected void runTest() throws Throwable {
75          try {
76              testRoundTrip();
77          }
78          catch (InvocationTargetException e) {
79              e.fillInStackTrace();
80              throw e.getTargetException();
81          }
82          catch (IllegalAccessException e) {
83              e.fillInStackTrace();
84              throw e;
85          }
86      }
87  
88      
89      public void testRoundTrip() throws Exception {
90          
91          XmlSchema schema = null;
92          DetailedDiff detaileddiffs = null;
93          
94          try {
95              if (debug) {
96                  System.out.println("fileToTest=" + this.fileToTest);
97                  System.out.println("valid=" + this.valid);
98              }
99              schema = loadSchema(fileToTest);
100 
101             // TODO: if we get here and the input was meant to be invalid perhaps
102             // should fail. Depends on whether XmlSchema is doing validation. For
103             // now we're ignoring invalid tests.
104 
105             ByteArrayOutputStream baos = new ByteArrayOutputStream();
106             schema.write(baos);
107             Diff diff = new Diff(new FileReader(fileToTest),
108                     new InputStreamReader(new ByteArrayInputStream(baos
109                             .toByteArray())));
110 
111             detaileddiffs = new DetailedDiff(diff);
112             detaileddiffs.overrideDifferenceListener(new SchemaAttrDiff());
113             boolean result = detaileddiffs.similar();
114             if (!result && debug) printFailureDetail(schema, detaileddiffs); 
115             assertTrue("Serialized out schema not similar to original", result);
116         } catch (Exception e) {
117             if (this.valid) {
118                 if (debug) printFailureDetail(schema, detaileddiffs);
119                 throw new Exception(this.fileToTest.getPath(), e);
120             }
121         }
122         
123 
124     }
125 
126     public XmlSchema loadSchema(File f) throws Exception {
127         XmlSchemaCollection col = new XmlSchemaCollection();
128         col.setBaseUri(f.getPath());
129         XmlSchema xmlSchema = col.read(new FileReader(f), null);
130         return xmlSchema;
131     }
132 
133     static class SchemaAttrDiff extends
134             IgnoreTextAndAttributeValuesDifferenceListener {
135 
136         public int differenceFound(Difference difference) {
137 
138             if (difference.getId() == DifferenceConstants.ELEMENT_NUM_ATTRIBUTES
139                     .getId()) {
140                 // control and test have to be elements
141                 // check if they are schema elements .. they only
142                 // seem to have the added attributeFormDefault and
143                 // elementFormDefault attributes
144                 // so shldnt have more than 2 attributes difference
145                 Element actualEl = (Element) difference.getControlNodeDetail()
146                         .getNode();
147 
148                 if (actualEl.getLocalName().equals("schema")) {
149 
150                     int expectedAttrs = Integer.parseInt(difference
151                             .getControlNodeDetail().getValue());
152                     int actualAttrs = Integer.parseInt(difference
153                             .getTestNodeDetail().getValue());
154                     if (Math.abs(actualAttrs - expectedAttrs) <= 2) {
155                         return RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR;
156                     }
157                 }
158             } else if (difference.getId() == DifferenceConstants.ATTR_NAME_NOT_FOUND_ID) {
159                 // sometimes the serializer throws in a few extra attributes...
160                 Element actualEl = (Element) difference.getControlNodeDetail()
161                         .getNode();
162 
163                 if (actualEl.getLocalName().equals("schema")) {
164                     return RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR;
165                 }
166             }
167 
168             return super.differenceFound(difference);
169         }
170     }
171 
172     private void printFailureDetail(XmlSchema schema, DetailedDiff detaileddiffs) {
173         System.err.println(super.getName() + " failure detail");
174         System.err.println("-----");
175         schema.write(System.err);
176         if (detaileddiffs != null) {
177             ListIterator li = detaileddiffs.getAllDifferences().listIterator();
178 
179             while (li.hasNext()) {
180                 System.err.println(li.next());
181             }
182         }
183     }
184 
185     
186 }