//////////////////////////////////////////////////////////////////////////////// // // 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 // // 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 UnitTest.Validation { import flash.utils.ByteArray; import flashx.textLayout.conversion.ConversionType; import flashx.textLayout.conversion.ITextExporter; import flashx.textLayout.conversion.TextConverter; import flashx.textLayout.elements.TextFlow; public class XMLSnapshot { private var baselineXMLStack:Array = new Array(); private var currentXMLStack:Array = new Array(); /** * return line data from the TextFlow in XML */ public function takeSnapshot(aFlow:TextFlow, aFormat:String):XML { var xmlSnapshot:XML = <{aFormat + "Snapshot"}/>; // for compatibility with existing snapshots, use the old root tag // if we ever get to rebase everything, we could remove this line. //if (aFormat == TextConverter.TEXT_LAYOUT_FORMAT) xmlSnapshot = ; var filter:ITextExporter = TextConverter.getExporter(aFormat); xmlSnapshot = filter.export(aFlow, ConversionType.XML_TYPE) as XML; var xmlDataBytes:ByteArray = new ByteArray(); xmlSnapshot.normalize(); xmlDataBytes.writeObject (xmlSnapshot); xmlDataBytes.compress(); xmlDataBytes.uncompress(); xmlSnapshot = new XML(xmlDataBytes.readObject()); xmlSnapshot.normalize(); return xmlSnapshot; } /** * compare the two snapshots * a list of differences in XML are returned * null is returned if the snapshots are identical */ private function removeExtraSpace(tmpString:String):String { var iCount:Number = tmpString.length; var newString:String = ""; for (var i:Number = iCount; i > 0; i--) { var tmpChar:Number = tmpString.charCodeAt(i); if (!((tmpChar == 32) || (tmpChar == 10))) newString += tmpString.charAt(i); } return newString; } public function compare (baseline:XML, current:XML):Boolean { var Result:Boolean = true; baseline.normalize(); current.normalize(); var strBaseline:String = baseline.toXMLString(); var strCurrent:String = current.toXMLString(); if (strBaseline != strCurrent) Result = false; return Result; } public function compareAdvanced (baseline:XML, current:XML):Boolean { baseline.normalize(); current.normalize(); if (!compareElements(baseline, current)) return false; return compareAdvancedChildren(baseline, current); } private function compareAdvancedChildren (baseline:XML, current:XML):Boolean { var result:Boolean = true; var baselineStack:Array = new Array(); var currentStack:Array = new Array(); var baselineChild:XML; var currentChild:XML; var baselineChildren:XMLList = baseline.children(); var currentChildren:XMLList = current.children(); for each (baselineChild in baselineChildren) { baselineStack.push(baselineChild); //trace(baselineChild.toString()); } for each (currentChild in currentChildren) { currentStack.push(currentChild); //trace(currentChild.toString()); } baselineChild = baselineStack.shift(); currentChild = currentStack.shift(); while ((baselineChild != null) && (currentChild != null) && result) { if (!compareElements(baselineChild, currentChild)) return false; result = compareAdvancedChildren(baselineChild, currentChild); if (result) { baselineChild = baselineStack.shift(); currentChild = currentStack.shift(); } } return result; } private function compareElements(baselineChild:XML, currentChild:XML):Boolean { if (baselineChild.nodeKind() != currentChild.nodeKind()) return false; else if (baselineChild.name() != currentChild.name()) return false; else if (baselineChild.text() != currentChild.text()) return false; else if (baselineChild.children().length() != currentChild.children().length()) return false; else if (!(compareAttributes (baselineChild, currentChild))) return false; return true; } public function createDiff (baseline:XML, current:XML):Boolean { var Result:Boolean = true; var baselineStack:Array = new Array(); var currentStack:Array = new Array(); var baselineChild:XML; var currentChild:XML; var strProblem:String; baseline.normalize(); current.normalize(); var baselineChildren:XMLList = baseline.children(); var currentChildren:XMLList = current.children(); for each (baselineChild in baselineChildren) { baselineStack.push(baselineChild); } for each (currentChild in currentChildren) { currentStack.push(currentChild); } baselineChild = baselineStack.shift(); currentChild = currentStack.shift(); while ((baselineChild != null) && (currentChild != null)) { strProblem = ""; if (baselineChild.nodeKind() != currentChild.nodeKind()) { strProblem = "Type"; //trace("Not the same kind of node."); // Mark node with problem attribute. currentChild.@compError = "type"; } else if (baselineChild.name() != currentChild.name()) { strProblem = "Name"; //trace("Names not the same."); currentChild.@compError = "name"; } else if (baselineChild.text() != currentChild.text()) { strProblem = "Text"; //trace("Text is not the same"); // Mark node with problem attribute. currentChild.@compError = "text"; } else if (baselineChild.children().length() != currentChild.children().length()) { strProblem = "Count"; //trace("Not the same number of kids."); } else if (!(compareAttributes (baselineChild, currentChild))) { strProblem = "Attributes"; //trace("Attributes not the same."); currentChild.@compError = "attribute"; } baselineXMLStack.push(baselineChild.toString()); createDiff(baselineChild, currentChild); baselineChild = baselineStack.shift(); currentChild = currentStack.shift(); } while (baselineChild != null) { //trace("A -" + baselineChild.nodeKind() + " - " + baselineChild.name() + " - " + baselineChild.text()); baselineChild.@compError = "extra"; baselineChild = baselineStack.shift(); } while (currentChild != null) { //trace("B -" + currentChild.nodeKind() + " - " + currentChild.name() + " - " + currentChild.text() ); currentChild.@compError = "extra"; currentChild = currentStack.shift(); } return Result; } private function compareAttributes(baseline:XML, current:XML):Boolean { var Result:Boolean = true; var baselineAttributes:XMLList = baseline.attributes(); var baselineAttribute:XML; var arBaseAttributes:Array = new Array(); var arCurrentAttributes:Array = new Array(); for each (baselineAttribute in baselineAttributes) { arBaseAttributes.push({Name:baselineAttribute.name(), Value:baselineAttribute.toString()}); } var currentAttributes:XMLList = current.attributes(); var currentAttribute:XML; for each (currentAttribute in currentAttributes) { arCurrentAttributes.push({Name:currentAttribute.name(), Value:currentAttribute.toString()}); } if (arBaseAttributes.length != arCurrentAttributes.length) Result = false; else { arCurrentAttributes.sortOn("Name"); arBaseAttributes.sortOn("Name"); var tmpBaseAttribute:Object = arCurrentAttributes.shift(); var tmpCurrentAttribute:Object = arBaseAttributes.shift(); while (tmpBaseAttribute != null) { if (!((tmpBaseAttribute.Name == tmpCurrentAttribute.Name) && (tmpBaseAttribute.Value == tmpCurrentAttribute.Value))) { Result = false; break; } tmpBaseAttribute = arCurrentAttributes.shift(); tmpCurrentAttribute = arBaseAttributes.shift(); } } return Result; } } }