This is an automated email from the ASF dual-hosted git repository.

gregdove pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git

commit 27f717cd98c0c0179dd1cdfdbd3a025b1323fd3d
Author: greg-dove <[email protected]>
AuthorDate: Thu May 26 15:44:53 2022 +1200

    Incremental progress against #1198. Focus on improving low level XML 
notification parity.
---
 frameworks/projects/XML/src/main/royale/XML.as     |  37 +++-
 .../flexUnitTests/xml/XMLNotificationTest.as       | 218 +++++++++++++++++++--
 2 files changed, 234 insertions(+), 21 deletions(-)

diff --git a/frameworks/projects/XML/src/main/royale/XML.as 
b/frameworks/projects/XML/src/main/royale/XML.as
index b589b7e7b2..b94b87471b 100644
--- a/frameworks/projects/XML/src/main/royale/XML.as
+++ b/frameworks/projects/XML/src/main/royale/XML.as
@@ -2464,6 +2464,8 @@ package
                 * @param value
                 * @return
                 *
+                * @royaleignorecoercion XML
+                *
                 */
                public function replace(propertyName:Object, value:*):*
                {
@@ -2502,8 +2504,30 @@ package
                                replaceChildAt(idx, value);
                                return this; //to step 4 above
                        }
-                       //@todo step 5+ above...
-                       return null;
+                       var n:QName = toXMLName(propertyName); //step 5 above
+                       var i:int = -1; // step 6, using -1 instead of undefined
+                       var k:uint = childrenLength() - 1;
+                       var replaceChild:XML = null;
+                       for (;k > -1;k--) { //step 7
+                               var childK:XML = (_children[k] as XML);
+                               if ( //step 7a
+                                       ((n.localName == "*" ) || 
((childK.getNodeRef() == ELEMENT) && (childK.localName() == n.localName)))
+                                               && ((n.uri == null) || 
((childK.getNodeRef() == ELEMENT) && (childK.name().uri == n.uri)))
+                               ){
+                                       if (i != -1) {
+                                               deleteChildAt(i); //step 7a.i
+                                               xml$_notify("nodeRemoved", 
this, replaceChild, null);
+                                       }
+                                       i = k;//step 7a.ii
+                                       replaceChild = childK;
+                               }
+                       }
+                       if (i == -1) return this; //step 8, using -1 instead of 
undefined
+                       _internalSuppressNotify = true;
+                       replaceChildAt(i, value);
+                       _internalSuppressNotify = false;
+                       xml$_notify( "nodeChanged" , this, _children[i], 
replaceChild);
+                       return this;
                }
                
                /**
@@ -2869,6 +2893,7 @@ package
                                        childIdx = chldrn[0].childIndex();
                                
                                len = chldrn.length() -1;
+                               var origFirstChild:XML = null;
                                _internalSuppressNotify = true;
                                for (i= len; i >= 0;  i--)
                                {
@@ -2883,6 +2908,8 @@ package
                                                _internalSuppressNotify = false;
                                                xml$_notify("nodeRemoved", 
this, chldrn[i], null);
                                                _internalSuppressNotify = true;
+                                       } else {
+                                               origFirstChild = chldrn[i];
                                        }
                                }
                                _internalSuppressNotify = false;
@@ -2908,7 +2935,11 @@ package
                                }
                                _internalSuppressNotify = false;
                                // legacy behavior is to send first child only, 
but with post-everything-added "this"
-                               if (len > 0) xml$_notify("nodeAdded", this, 
firstChild, null);
+                               //if (len > 0) xml$_notify("nodeAdded", this, 
firstChild, null);
+
+                               if (len > 0) {
+                                       xml$_notify(origFirstChild ? 
"nodeChanged" : "nodeAdded", this, firstChild, origFirstChild);
+                               }
                        }
                        
                        return this;
diff --git 
a/frameworks/projects/XML/src/test/royale/flexUnitTests/xml/XMLNotificationTest.as
 
b/frameworks/projects/XML/src/test/royale/flexUnitTests/xml/XMLNotificationTest.as
index be1b834151..02b18f6a4e 100644
--- 
a/frameworks/projects/XML/src/test/royale/flexUnitTests/xml/XMLNotificationTest.as
+++ 
b/frameworks/projects/XML/src/test/royale/flexUnitTests/xml/XMLNotificationTest.as
@@ -38,6 +38,7 @@ package flexUnitTests.xml
         public function setUp():void
         {
             settings = XML.settings();
+            XML.setSettings(XML.defaultSettings());
         }
         
         [After]
@@ -56,25 +57,79 @@ package flexUnitTests.xml
         {
         }
 
+        /**
+         *
+         * dev use for creating expected tracking sequences ([SWF] output as a 
reference)
+         */
+        private static function consoleOut(message:String, type:String = 
'log', ...args):void
+        {
+            args.unshift(message + '\n');
+            COMPILE::JS {
+                args.unshift('[JS]');
+                console[type].apply(console, args);
+            }
+            COMPILE::SWF{
+                import flash.external.ExternalInterface;
+
+                if (ExternalInterface.available)
+                {
+                    try
+                    {
+                        args.unshift('[SWF]');
+                        const method:String = 'console.' + type + '.apply';
+                        ExternalInterface.call(method, null, args);
+                    } catch (e:Error)
+                    {
+                    }
+                }
+            }
+        }
+
+        /**
+         *
+         * dev use for creating expected tracking sequences ([SWF] output as a 
reference)
+         */
+        private function expectify(array:Array, message:String = null):String{
+            array = array.slice();
+            var l:uint = array.length;
+            for (var i:uint = 0; i<l;i++) {
+                var s:String =array[i];
+                s= "'" + s.split('\\n').join('\\\\n') + "'";
+                array[i] = s;
+            }
+            var out:String = '[\n'+array.join(',\n')+'\n]';
+            if (message) {
+                consoleOut(message);
+            }
+            consoleOut(out)
+            return out;
+        }
+
 
         private function isExpected(expected:Array):Boolean{
             if (!tracking) return false;
             if (expected.length != tracking.length) {
+                consoleOut('mismatch in length ');
+                consoleOut('expected len:'+expected.length);
+                consoleOut('got      len:'+tracking.length);
                 return false;
             }
             for (var i:uint=0;i<expected.length;i++){
                 if (expected[i] != tracking[i]) {
+                    consoleOut('mismatch at '+i);
+                    consoleOut('expected:'+expected[i]);
+                    consoleOut('got     :'+tracking[i]);
                     return false;
                 }
             }
             return true;
         }
 
-        private var tracking:Array;
 
-        public function trackChanges(currentTarget:Object, command:String, 
target:Object, value:Object, detail:Object, callee:Function = null):void{
+        private var tracking:Array;
+        private function trackChanges(currentTarget:Object, command:String, 
target:Object, value:Object, detail:Object):void{
             var trackingRecord:String=
-            "[ command="+command+", currentTarget="+currentTarget+", 
target="+target+", value="+value+", detail="+detail;
+                    "[ command="+command+", currentTarget="+currentTarget+", 
target="+target+", value="+stringifyValue(value)+", 
detail="+stringifyValue(detail);
             trackingRecord = trackingRecord.split('\n').join('\\n');
             const targetType:String = target!=null ? 
getQualifiedClassName(target) : '{'+target+'}';
             const targetIsCurrentTarget:String = (target === currentTarget) + 
'';
@@ -83,11 +138,47 @@ package flexUnitTests.xml
             tracking.push(trackingRecord)
         }
 
-        private function setNotifier(value:XML):void{
-            tracking=[];
+        private function stringifyValue(value:Object):String{
+            var ret:String;
+            if (value is XML) {
+                var xml:XML = XML(value);
+                var nodeKind:String = xml.nodeKind();
+                switch(nodeKind) {
+                    case 'element' :
+                        var val:String = xml.toXMLString();
+                        ret = '['+nodeKind+': '+val+']';
+                        break
+                    case 'attribute':
+                        ret =  
'['+nodeKind+':'+xml.name()+'="'+xml.text()+'"]';
+                        break;
+                    case 'text':
+                        ret =  '['+nodeKind+':"'+xml.text().toString()+'"]';
+                        break;
+                    default:
+                        ret = '['+nodeKind+':{not stringified}]';
+                        break;
+                }
+            } else {
+                ret = value +'';
+            }
+            return ret;
+        }
+
+
+        private function setNotifier(value:XML, reset:Boolean=true):void{
+            if (reset) {
+                tracking=[];
+            }
             value.setNotification(trackChanges);
         }
 
+        private function setChildrenNotifiers(value:Object):void{
+            var children:XMLList = value is XML ? XML(value).children() : 
value as XMLList;
+            for each(var child:XML in children) {
+                setNotifier(child, false);
+            }
+        }
+
 
         [Test]
         public function testLanguageFidelity():void
@@ -114,8 +205,10 @@ package flexUnitTests.xml
 
             var expected:Array = [
                 '[ command=textSet, currentTarget=test, target=test, 
value=test, detail=null, targetType=XML, targetIsCurrent:false, 
valueType=String]',
-                '[ command=nodeAdded, currentTarget=test, target=test, 
value=test, detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]'
+                '[ command=nodeAdded, currentTarget=test, target=test, 
value=[text:""], detail=null, targetType=XML, targetIsCurrent:true, 
valueType=XML]'
             ]
+
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
             
         }
@@ -126,9 +219,11 @@ package flexUnitTests.xml
             var xml:XML = <xml/>;
             setNotifier(xml);
             xml.appendChild(<test/>);
+
             var expected:Array = [
-                '[ command=nodeAdded, currentTarget=<xml>\\n  
<test/>\\n</xml>, target=<xml>\\n  <test/>\\n</xml>, value=, detail=null, 
targetType=XML, targetIsCurrent:true, valueType=XML]'
+                '[ command=nodeAdded, currentTarget=<xml>\\n  
<test/>\\n</xml>, target=<xml>\\n  <test/>\\n</xml>, value=[element: <test/>], 
detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]'
             ]
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
 
         }
@@ -146,15 +241,15 @@ package flexUnitTests.xml
             delete children[0];
 
             var expected:Array = [
-                '[ command=nodeRemoved, currentTarget=, target=, value=, 
detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]'
+                '[ command=nodeRemoved, currentTarget=, target=, 
value=[element: <child/>], detail=null, targetType=XML, targetIsCurrent:true, 
valueType=XML]'
             ]
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
 
         }
 
 
         [Test]
-        [Ignore] //ignored, because not yet working in JS
         public function testReplaceNode():void
         {
             var xml:XML = <xml><child1/><child2/></xml>;
@@ -164,11 +259,28 @@ package flexUnitTests.xml
 
             xml.replace('child1',childX);
 
-
             var expected:Array = [
-                '[ command=nodeChanged, currentTarget=<xml>\\n  <childX/>\\n  
<child2/>\\n</xml>, target=<xml>\\n  <childX/>\\n  <child2/>\\n</xml>, value=, 
detail=, targetType=XML, targetIsCurrent:true, valueType=XML]'
+                '[ command=nodeChanged, currentTarget=<xml>\\n  <childX/>\\n  
<child2/>\\n</xml>, target=<xml>\\n  <childX/>\\n  <child2/>\\n</xml>, 
value=[element: <childX/>], detail=[element: <child1/>], targetType=XML, 
targetIsCurrent:true, valueType=XML]'
+            ]
+
+            assertTrue(isExpected(expected), 'unexpected XML notifications');
+
+
+            xml = 
<xml><childA/><childB/><childA/><childB/><childA/><childB/></xml>;
+            childX = <childX/>;
+
+            setNotifier(xml);
+
+            xml.replace('childB',childX);
+
+            expected = [
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  <childA/>\\n  
<childB/>\\n  <childA/>\\n  <childB/>\\n  <childA/>\\n</xml>, target=<xml>\\n  
<childA/>\\n  <childB/>\\n  <childA/>\\n  <childB/>\\n  <childA/>\\n</xml>, 
value=[element: <childB/>], detail=null, targetType=XML, targetIsCurrent:true, 
valueType=XML]',
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  <childA/>\\n  
<childB/>\\n  <childA/>\\n  <childA/>\\n</xml>, target=<xml>\\n  <childA/>\\n  
<childB/>\\n  <childA/>\\n  <childA/>\\n</xml>, value=[element: <childB/>], 
detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]',
+                '[ command=nodeChanged, currentTarget=<xml>\\n  <childA/>\\n  
<childX/>\\n  <childA/>\\n  <childA/>\\n</xml>, target=<xml>\\n  <childA/>\\n  
<childX/>\\n  <childA/>\\n  <childA/>\\n</xml>, value=[element: <childX/>], 
detail=[element: <childB/>], targetType=XML, targetIsCurrent:true, 
valueType=XML]'
             ]
+           // expectify(tracking, 'testReplaceNode')
             assertTrue(isExpected(expected), 'unexpected XML notifications');
+
         }
 
 
@@ -183,6 +295,7 @@ package flexUnitTests.xml
             var expected:Array = [
                 '[ command=namespaceSet, currentTarget=, target=, 
value=testuri, detail=null, targetType=XML, targetIsCurrent:true, 
valueType=Namespace]'
             ]
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
 
         }
@@ -196,9 +309,11 @@ package flexUnitTests.xml
 
             xml.@att = "testAtt";
 
+
             var expected:Array = [
                 '[ command=attributeAdded, currentTarget=, target=, value=att, 
detail=testAtt, targetType=XML, targetIsCurrent:true, valueType=String]'
             ]
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
             var att:XML = xml.@att[0];
             xml = <xml/>;
@@ -206,15 +321,16 @@ package flexUnitTests.xml
             xml.appendChild(att);
 
             expected = [
-                '[ command=textSet, currentTarget=testAtt, target=testAtt, 
value=testAtt, detail=null, targetType=XML, targetIsCurrent:false, 
valueType=String]' ,
-                '[ command=nodeAdded, currentTarget=testAtt, target=testAtt, 
value=testAtt, detail=null, targetType=XML, targetIsCurrent:true, 
valueType=XML]'
+                '[ command=textSet, currentTarget=testAtt, target=testAtt, 
value=testAtt, detail=null, targetType=XML, targetIsCurrent:false, 
valueType=String]',
+                '[ command=nodeAdded, currentTarget=testAtt, target=testAtt, 
value=[text:""], detail=null, targetType=XML, targetIsCurrent:true, 
valueType=XML]'
             ]
+
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
             //reset the tracking:
             setNotifier(xml);
             xml.@something = att;
 
-
             expected = [
                 '[ command=attributeAdded, currentTarget=testAtt, 
target=testAtt, value=something, detail=testAtt, targetType=XML, 
targetIsCurrent:true, valueType=String]'
             ]
@@ -234,6 +350,7 @@ package flexUnitTests.xml
             var expected:Array = [
                 '[ command=attributeRemoved, currentTarget=, target=, 
value=test, detail=testAtt, targetType=XML, targetIsCurrent:true, 
valueType=String]'
             ]
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
 
 
@@ -243,6 +360,7 @@ package flexUnitTests.xml
             var attributes:XMLList = xml.attributes();
             delete attributes[0];
             //expect the same (ignore namespace)
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
 
         }
@@ -253,15 +371,13 @@ package flexUnitTests.xml
             var xml:XML = new XML('<xml test="testAtt"/>')
             setNotifier(xml);
 
-
             xml.@test = 'testAtt2';
 
-
             var expected:Array = [
                 '[ command=attributeChanged, currentTarget=, target=, 
value=test, detail=testAtt, targetType=XML, targetIsCurrent:true, 
valueType=String]'
             ]
-            assertTrue(isExpected(expected), 'unexpected XML notifications');
 
+            assertTrue(isExpected(expected), 'unexpected XML notifications');
 
         }
 
@@ -278,18 +394,84 @@ package flexUnitTests.xml
             var expected:Array = [
                 '[ command=nameSet, currentTarget=, target=, value=test, 
detail=xml, targetType=XML, targetIsCurrent:true, valueType=QName]'
             ]
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
 
             setNotifier(xml);
             xml.setName('test2');
+
             expected = [
                 '[ command=nameSet, currentTarget=, target=, value=test2, 
detail=test, targetType=XML, targetIsCurrent:true, valueType=String]'
             ]
+
             assertTrue(isExpected(expected), 'unexpected XML notifications');
         }
 
 
+        [Test]
+        public function testSetChildren():void
+        {
+            var xml:XML = <xml><one/><two/><three/></xml>;
+
+            setNotifier(xml);
+            var alternateChildren:XMLList = 
XMLList("<childOne/><childTwo/><childThree/>");
+
+            xml.setChildren(alternateChildren);
+
+
+            var expected:Array = [
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  <one/>\\n  
<two/>\\n</xml>, target=<xml>\\n  <one/>\\n  <two/>\\n</xml>, value=[element: 
<three/>], detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]',
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  
<one/>\\n</xml>, target=<xml>\\n  <one/>\\n</xml>, value=[element: <two/>], 
detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]',
+                '[ command=nodeChanged, currentTarget=<xml>\\n  <childOne/>\\n 
 <childTwo/>\\n  <childThree/>\\n</xml>, target=<xml>\\n  <childOne/>\\n  
<childTwo/>\\n  <childThree/>\\n</xml>, value=[element: <childOne/>], 
detail=[element: <one/>], targetType=XML, targetIsCurrent:true, valueType=XML]'
+            ]
+            assertTrue(isExpected(expected), 'unexpected XML notifications');
+
+            setNotifier(xml);
+            alternateChildren = new XMLList();
+            xml.setChildren(alternateChildren);
+
+            expected = [
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  <childOne/>\\n 
 <childTwo/>\\n</xml>, target=<xml>\\n  <childOne/>\\n  <childTwo/>\\n</xml>, 
value=[element: <childThree/>], detail=null, targetType=XML, 
targetIsCurrent:true, valueType=XML]',
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  
<childOne/>\\n</xml>, target=<xml>\\n  <childOne/>\\n</xml>, value=[element: 
<childTwo/>], detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]'
+            ]
+            assertTrue(isExpected(expected), 'unexpected XML notifications');
+            xml = <xml/>;
+            setNotifier(xml);
+            alternateChildren = XMLList("<childOne/><childTwo/><childThree/>");
+            xml.setChildren(alternateChildren);
+            expected = [
+                '[ command=nodeAdded, currentTarget=<xml>\\n  <childOne/>\\n  
<childTwo/>\\n  <childThree/>\\n</xml>, target=<xml>\\n  <childOne/>\\n  
<childTwo/>\\n  <childThree/>\\n</xml>, value=[element: <childOne/>], 
detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]'
+            ]
+            assertTrue(isExpected(expected), 'unexpected XML notifications');
+            xml = <xml><one>some text</one></xml>;
+            setNotifier(xml);
+            alternateChildren = XMLList("<childOne/><childTwo/><childThree/>");
+            xml.setChildren(alternateChildren);
+            expected = [
+                '[ command=nodeChanged, currentTarget=<xml>\\n  <childOne/>\\n 
 <childTwo/>\\n  <childThree/>\\n</xml>, target=<xml>\\n  <childOne/>\\n  
<childTwo/>\\n  <childThree/>\\n</xml>, value=[element: <childOne/>], 
detail=[element: <one>some text</one>], targetType=XML, targetIsCurrent:true, 
valueType=XML]'
+            ]
+            assertTrue(isExpected(expected), 'unexpected XML notifications');
+
+            //check what the children do (if anything)
+            xml = <xml><one/><two/><three/></xml>;
+            setNotifier(xml);
+            alternateChildren = XMLList("<childOne/><childTwo/><childThree/>");
+            xml.setChildren(alternateChildren);
+            xml.setChildren(alternateChildren);
+            expected = [
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  <one/>\\n  
<two/>\\n</xml>, target=<xml>\\n  <one/>\\n  <two/>\\n</xml>, value=[element: 
<three/>], detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]',
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  
<one/>\\n</xml>, target=<xml>\\n  <one/>\\n</xml>, value=[element: <two/>], 
detail=null, targetType=XML, targetIsCurrent:true, valueType=XML]',
+                '[ command=nodeChanged, currentTarget=<xml>\\n  <childOne/>\\n 
 <childTwo/>\\n  <childThree/>\\n</xml>, target=<xml>\\n  <childOne/>\\n  
<childTwo/>\\n  <childThree/>\\n</xml>, value=[element: <childOne/>], 
detail=[element: <one/>], targetType=XML, targetIsCurrent:true, valueType=XML]',
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  <childOne/>\\n 
 <childTwo/>\\n</xml>, target=<xml>\\n  <childOne/>\\n  <childTwo/>\\n</xml>, 
value=[element: <childThree/>], detail=null, targetType=XML, 
targetIsCurrent:true, valueType=XML]',
+                '[ command=nodeRemoved, currentTarget=<xml>\\n  
<childOne/>\\n</xml>, target=<xml>\\n  <childOne/>\\n</xml>, value=[element: 
<childTwo/>], detail=null, targetType=XML, targetIsCurrent:true, 
valueType=XML]',
+                '[ command=nodeChanged, currentTarget=<xml>\\n  <childOne/>\\n 
 <childTwo/>\\n  <childThree/>\\n</xml>, target=<xml>\\n  <childOne/>\\n  
<childTwo/>\\n  <childThree/>\\n</xml>, value=[element: <childOne/>], 
detail=[element: <childOne/>], targetType=XML, targetIsCurrent:true, 
valueType=XML]'
+            ]
+
+            assertTrue(isExpected(expected), 'unexpected XML notifications');
+
+
+        }
+
 
-        
     }
 }

Reply via email to