1 19 package org.netbeans.tax; 20 21 import java.lang.reflect.Constructor ; 22 import java.lang.reflect.Field ; 23 import java.lang.reflect.Modifier ; 24 import java.util.Iterator ; 25 import java.util.List ; 26 import java.util.Map ; 27 import junit.textui.TestRunner; 28 import org.netbeans.modules.xml.core.XMLDataObject; 29 import org.netbeans.modules.xml.tax.cookies.TreeEditorCookie; 30 import org.netbeans.tax.TreeNamedObjectMap.KeyListener; 31 import org.netbeans.tax.TreeDocumentType.DTDIdentity; 32 import org.netbeans.tax.event.TreeEventChangeSupport; 33 import org.netbeans.tax.event.TreeEventManager; 34 import org.netbeans.tests.xml.XTest; 35 36 37 66 public class XMLCloneTest extends XTest { 67 68 public XMLCloneTest(String testName) { 69 super(testName); 70 } 71 72 private int maxCalls = 10000; 74 private int listCount = 0; 75 private int mapCount = 0; 76 private Class testedLevel; 77 78 private Pattern[] patterns = new Pattern[] { 80 new Pattern(TreeParentNode.class, null, Boolean.TRUE, NullChecker.class), 82 new Pattern(TreeElement.class, "ownerElement", Boolean.TRUE, NullChecker.class), 83 new Pattern(KeyListener.class, "mapKeyListener", null, DifferentOrNullChecker.class), new Pattern(TreeEventChangeSupport.class, null, null, DifferentOrNullChecker.class), 85 new Pattern(TreeEventManager.class, null, null, DifferentChecker.class), 86 new Pattern(String .class, null, null, ImmutableChecker.class), 87 new Pattern(TreeName.class, null, null, ImmutableChecker.class), 88 new Pattern(DTDIdentity.class, null, null, ImmutableChecker.class), 89 }; 90 91 public void testClone() throws Exception { 92 TreeEditorCookie cake = (TreeEditorCookie) TestUtil.THIS.findData("Bookss.xml").getCookie(TreeEditorCookie.class); 93 TreeDocument document = (TreeDocument) cake.openDocumentRoot(); 94 nodeTest(document); 95 } 96 97 private void nodeTest(TreeNode node) { 98 treeCloneTest(node); 99 if (node instanceof TreeParentNode) { 101 TreeChild child = ((TreeParentNode) node).getFirstChild(); 102 while (child != null) { 103 nodeTest(child); 104 child = child.getNextSibling(); 105 } 106 } 107 108 if (node instanceof TreeElement && ((TreeElement) node).hasAttributes()) { 110 Iterator attributes = ((TreeElement) node).getAttributes().iterator(); 111 while (attributes.hasNext()) { 112 TreeNode attribute = (TreeNode) attributes.next(); 113 treeCloneTest(attribute); 114 } 115 } 116 } 117 118 private void treeCloneTest(TreeNode treeNode) { 119 dbg.println("\n\n========> Creating clone of: " + treeNode + "::\n" + TestUtil.nodeToString(treeNode) + "\n\n"); 120 121 TreeNode treeClone = (TreeNode) treeNode.clone(); 122 nodeCloneTest(treeNode, treeClone, true); 123 } 124 125 private void nodeCloneTest(Object node, Object clone, boolean isCloneRoot) { 126 dbg.println("\nNode: " + node + "\n<<<\n" + TestUtil.nodeToString(node) + "\n>>>"); 127 Class clazz = node.getClass(); 128 do { 129 cloneLevelCheck(clazz, node, clone, isCloneRoot); 130 clazz = clazz.getSuperclass(); 131 } while (clazz != null); 132 133 if (node instanceof TreeParentNode) { 135 TreeChild childNode = ((TreeParentNode) node).getFirstChild(); 136 TreeChild childClone = ((TreeParentNode) clone).getFirstChild(); 137 while (childNode != null) { 138 if (childClone == null) { 139 err("Missing clone child: " + TestUtil.nodeToString(childNode) 140 + "\nIn clone: " + TestUtil.nodeToString(clone), node); 141 break; 142 } 143 nodeCloneTest(childNode, childClone, false); 144 childNode = childNode.getNextSibling(); 145 childClone = childClone.getNextSibling(); 146 } 147 } 148 149 if (node instanceof TreeElement && ((TreeElement) node).hasAttributes()) { 151 Iterator nodeAtrs = ((TreeElement) node).getAttributes().iterator(); 152 Iterator cloneAtrs = ((TreeElement) clone).getAttributes().iterator(); 153 while (nodeAtrs.hasNext()) { 154 TreeNode nodeAtr = (TreeNode) nodeAtrs.next(); 155 TreeNode cloneAtr = (TreeNode) cloneAtrs.next(); 156 nodeCloneTest(nodeAtr, cloneAtr, false); 157 } 158 } 159 } 160 161 private void cloneLevelCheck(Class clazz, Object node, Object clone, boolean isCloneRoot) { 162 if (maxCalls-- < 0) { System.exit(1); 164 } 165 166 dbg.println("Level: " + clazz); 167 testedLevel = clazz; 168 Field [] fields = clazz.getDeclaredFields(); 169 Class checker; 170 String name; 171 172 for (int i = 0; i < fields.length; i++) { 173 if (Modifier.isStatic(fields[i].getModifiers())) { 174 continue; 175 } 176 177 if (fields[i].getType() == TreeObjectList.class) { 179 dbg.println("\n#" + listCount++ + ") CHECKING TREE_OBJECT_LIST: " + fields[i].getName()); 180 try { 181 Field listField = TreeObjectList.class.getDeclaredField("list"); 183 listField.setAccessible(true); 184 fields[i].setAccessible(true); 185 List nodeList = (List ) listField.get(fields[i].get(node)); 186 List cloneList = (List ) listField.get(fields[i].get(clone)); 187 188 if (isComparable(nodeList, cloneList, node)) { 190 for (int j = 0; j < nodeList.size(); j++) { 191 nodeCloneTest((TreeNode) nodeList.get(j), (TreeNode) cloneList.get(j), false); 192 } 193 } 194 } catch (Exception ex) { 195 err("In TreeObjectList Check", node); 196 ex.printStackTrace(dbg); 197 } finally { 198 dbg.println("/#" + --listCount + ") END CHECK\n"); 199 } 200 } 201 202 if (fields[i].getType() == TreeNamedObjectMap.class) { 204 Object key = null; 205 206 dbg.println("\n@" + mapCount++ + ") CHECKING TREE_NAMED_OBJECT_MAP: " + fields[i].getName()); 207 try { 208 Field mapField = TreeNamedObjectMap.class.getDeclaredField("map"); 210 mapField.setAccessible(true); 211 fields[i].setAccessible(true); 212 Map nodeMap = (Map ) mapField.get(fields[i].get(node)); 213 Map cloneMap = (Map ) mapField.get(fields[i].get(clone)); 214 215 if (isComparable(nodeMap, cloneMap, node)) { 217 218 Object [] keys = nodeMap.keySet().toArray(); 219 for (int j = 0; j < keys.length; j++) { 220 key = keys[j]; 221 nodeCloneTest(nodeMap.get(key), cloneMap.get(key), false); 222 } 223 } 224 } catch (Exception ex) { 225 err("In TreeNamedObjectMap Check: key = \"" + key + "\"", node); 226 ex.printStackTrace(dbg); 227 } finally { 228 dbg.println("/@" + --mapCount + ") END CHECK\n"); 229 } 230 } 231 232 checker = DefaultChecker.class; 234 for (int j = 0; j < patterns.length; j++) { 235 if (patterns[j].compare(fields[i].getType(), fields[i].getName(), isCloneRoot)) { 236 checker = patterns[j].getChecker(); 237 break; 238 } 239 } 240 newCheckerInstace(checker, fields[i], node, clone).check(); 241 } 242 } 243 244 private boolean isComparable(List nodeList, List cloneList, Object node) { 245 if (cloneList == null && nodeList == null) { 246 return false; 247 248 } else if (cloneList == null || nodeList == null) { 249 err("List is Null:" 250 + "\nnodeList = " + nodeList 251 + "\ncloneList = " + cloneList, node); 252 return false; 253 254 } else if (nodeList.size() != cloneList.size()) { 255 err("Lists have different size:" 256 + "\nnodeList.size() = " + nodeList.size() 257 + "\ncloneList.size() = " + cloneList.size(), node); 258 return false; 259 } 260 261 return true; 262 } 263 264 private boolean isComparable(Map nodeMap, Map cloneMap, Object node) { 265 if (cloneMap == null && nodeMap == null) { 266 return false; 267 268 } else if (nodeMap != null && nodeMap.size() == 0 && cloneMap == null) { 269 return false; 270 271 } else if (cloneMap == null || nodeMap == null) { 272 err("Map is Null:" 273 + "\nnodeMap = " + nodeMap 274 + "\ncloneMap = " + cloneMap, node); 275 return false; 276 277 } else if (nodeMap.size() != cloneMap.size()) { 278 err("Maps have different size:" 279 + "\nnodeMap.size() = " + nodeMap.size() 280 + "\ncloneMap.size() = " + cloneMap.size(), node); 281 return false; 282 } 283 284 return true; 285 } 286 287 private FieldChecker newCheckerInstace(Class clazz, Field field, Object node, Object clone) { 288 try { 289 Constructor constructor = clazz.getDeclaredConstructor(new Class [] {XMLCloneTest.class, Field .class, Object .class, Object .class}); 290 return (FieldChecker) constructor.newInstance(new Object [] {this, field, node, clone}); 291 } catch (Exception e) { 292 e.printStackTrace(dbg); 293 return null; 294 } 295 } 296 297 private String toStr(Object obj) { 298 String str = null; 299 if (obj instanceof TreeNode) { 300 try { 301 str = TestUtil.nodeToString((TreeNode) obj); 302 } catch (Exception e) {}; 303 } else { 304 str = "" + obj; 305 } 306 return str; 307 } 308 309 protected void err(String message, Object node) { 310 message = 311 "\n!!! ERROR:" + message 312 + "======================================================>" 313 + "Node: " + TestUtil.nodeToString(node) 314 + "Level: " + testedLevel; 315 316 fail(message); 317 } 318 319 protected String xmlTestName() { 320 return "XML-Clone-Test"; 321 } 322 323 327 public static void main(String args[]) { 328 DEBUG = true; 329 TestRunner.run(XMLCloneTest.class); 330 } 331 332 334 private class Pattern { 335 private Class _clazz; 336 private String _name; 337 private Boolean _isCloneRoot; 338 private Class _checker; 339 340 public Pattern(Class clazz, String name, Boolean isCloneRoot, Class checker) { 341 _clazz = clazz; 342 _name = name; 343 _isCloneRoot = isCloneRoot; 344 _checker = checker; 345 } 346 347 public boolean compare(Class clazz, String name, boolean isCloneRoot) { 348 return 349 ((_clazz == null) || (_clazz == clazz)) 350 && ((_isCloneRoot == null) || (_isCloneRoot.booleanValue() == isCloneRoot)) 351 && ((_name == null) || (_name.indexOf(name) != -1)); 352 } 353 354 public Class getChecker() { 355 return _checker; 356 } 357 } 358 359 private abstract class FieldChecker { 360 protected Field field; 361 protected Object node; 362 protected Object clone; 363 364 public FieldChecker(Field field, Object node, Object clone) { 365 this.field = field; 366 this.node = node; 367 this.clone = clone; 368 this.field.setAccessible(true); 369 } 370 371 public boolean check() { 372 if (test()) { 373 dbg.println(prefix() + "Field \"" + field.getType().getName() + "::" + field.getName() + "\" is OK"); 374 return true; 375 } else { 376 reportErr(); 377 return false; 378 } 379 } 380 381 protected boolean isBothNull() { 382 return (fieldFrom(node) == null) && (fieldFrom(clone) == null); 383 } 384 385 protected boolean hasDifferentID() { 386 return fieldFrom(node) != fieldFrom(clone); 387 } 388 389 protected boolean hasSameValue() { 390 if (field.getClass().isPrimitive()) 391 return fieldFrom(node).equals(fieldFrom(clone)); 392 else if ((fieldFrom(node) != null) && (fieldFrom(clone) == null)) { return false; 394 } 395 return true; 396 } 397 398 protected Object fieldFrom(Object obj) { 399 Object result = null; 400 try { 401 result = field.get(obj); 402 } catch (Exception e) { 403 e.printStackTrace(dbg); 404 } 405 return result; 406 } 407 408 private void reportErr() { 409 String clazz; 410 411 if (fieldFrom(node) != null) { 412 clazz = fieldFrom(node).getClass().getName(); 413 } else { 414 clazz = "Null.clazz"; 415 } 416 417 err(prefix() 418 + "\nClone error in field: \"" + field.getType().getName() + "::" + field.getName() + "\"." 419 + "\nclazz : " + clazz 420 + "\noriginal value: " + toStr(fieldFrom(node)) 421 + "\nclone value : " + toStr(fieldFrom(clone)) 422 + "\noriginal ID : " + System.identityHashCode(fieldFrom(node)) 423 + "\nclone ID : " + System.identityHashCode(fieldFrom(clone)) 424 + "\nhasDifferentID: " + hasDifferentID() 425 + "\nhasSameValue : " + hasSameValue() 426 + "\nisBoothNull : " + isBothNull() 427 , node 428 ); 429 } 430 431 protected abstract boolean test(); 432 433 protected abstract String prefix(); 434 } 435 436 440 private class DefaultChecker extends FieldChecker { 441 442 public DefaultChecker(Field field, Object node, Object clone) { 443 super(field, node, clone); 444 } 445 446 protected boolean test() { 447 454 return (hasDifferentID() && hasSameValue()) || isBothNull(); 455 } 456 457 protected String prefix() { 458 return "DEFAULT : "; 459 } 460 } 461 462 465 private class EmptyChecker extends FieldChecker { 466 467 public EmptyChecker(Field field, Object node, Object clone) { 468 super(field, node, clone); 469 } 470 471 protected boolean test() { 472 return true; 473 } 474 475 protected String prefix() { 476 return "EMPTY : "; 477 } 478 } 479 480 483 private class NullChecker extends FieldChecker { 484 485 public NullChecker(Field field, Object node, Object clone) { 486 super(field, node, clone); 487 } 488 489 protected boolean test() { 490 return fieldFrom(clone) == null; 491 } 492 493 protected String prefix() { 494 return "NULL : "; 495 } 496 } 497 498 501 private class ImmutableChecker extends FieldChecker { 502 503 public ImmutableChecker(Field field, Object node, Object clone) { 504 super(field, node, clone); 505 } 506 507 protected boolean test() { 508 return fieldFrom(clone) == fieldFrom(node); 509 } 510 511 protected String prefix() { 512 return "IMMUTABLE: "; 513 } 514 } 515 516 519 private class DifferentOrNullChecker extends FieldChecker { 520 521 public DifferentOrNullChecker(Field field, Object node, Object clone) { 522 super(field, node, clone); 523 } 524 525 protected boolean test() { 526 return (fieldFrom(clone) != fieldFrom(node) || (fieldFrom(clone) == null && fieldFrom(node) == null)); 527 } 528 529 protected String prefix() { 530 return "DIFFERENT_OR_NULL: "; 531 } 532 } 533 534 537 private class DifferentChecker extends FieldChecker { 538 539 public DifferentChecker(Field field, Object node, Object clone) { 540 super(field, node, clone); 541 } 542 543 protected boolean test() { 544 return fieldFrom(clone) != fieldFrom(node); 545 } 546 547 protected String prefix() { 548 return "DIFFERENT: "; 549 } 550 } 551 } 552 | Popular Tags |