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