You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by gr...@apache.org on 2022/04/06 01:44:15 UTC

[royale-asjs] branch develop updated (13b1158f9b -> 32555dea1f)

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

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


    from 13b1158f9b Fixes #1185 and Fixes #1183. Also fixes a few other otherwise undocumented issues. (Requires compiler-jx update)
     new acab343f73 Avoid the possibility of infinite loops (in JS only, SWF untested) with xml watchers. This can happen if changes are made in watcher functions.
     new 32555dea1f Fix for an issue encountered with ObjectUtil.clone for Strings. Related: restored some commented-out code in UIDUtil. Added some initial ObjectUtil cloning tests.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../src/main/royale/mx/utils/ObjectUtil.as         | 22 ++++++-
 .../src/main/royale/mx/utils/UIDUtil.as            | 13 ++--
 .../src/main/royale/mx/utils/XMLNotifier.as        | 71 ++++++++++++++++++----
 .../flexUnitTests/mxroyale/ObjectUtilTest.as       | 47 +++++++++++---
 4 files changed, 127 insertions(+), 26 deletions(-)


[royale-asjs] 02/02: Fix for an issue encountered with ObjectUtil.clone for Strings. Related: restored some commented-out code in UIDUtil. Added some initial ObjectUtil cloning tests.

Posted by gr...@apache.org.
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 32555dea1f1b661f95f36c1f2b1beb9d9c2251fb
Author: greg-dove <gr...@gmail.com>
AuthorDate: Wed Apr 6 13:43:57 2022 +1200

    Fix for an issue encountered with ObjectUtil.clone for Strings. Related: restored some commented-out code in UIDUtil. Added some initial ObjectUtil cloning tests.
---
 .../src/main/royale/mx/utils/ObjectUtil.as         | 22 +++++++++-
 .../src/main/royale/mx/utils/UIDUtil.as            | 13 +++---
 .../flexUnitTests/mxroyale/ObjectUtilTest.as       | 47 ++++++++++++++++++----
 3 files changed, 68 insertions(+), 14 deletions(-)

diff --git a/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/ObjectUtil.as b/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/ObjectUtil.as
index 48d18c0abc..4392fa0ad2 100644
--- a/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/ObjectUtil.as
+++ b/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/ObjectUtil.as
@@ -199,13 +199,31 @@ public class ObjectUtil
         return result;
     }
 
+    /**
+     * Helper to abstract some VM-level differences
+     * @param value
+     * @return true if the value argument has a 'uid' property
+     */
+    private static function isUIDObject(value:Object):Boolean{
+        var ret:Boolean = false;
+        COMPILE::JS{
+            //in JS, the getter/setter for 'uid' is not considered an 'own' property, in SWF, it is, so we check also in the prototype chain if needed
+            ret = (value && (value.hasOwnProperty("uid") || ("uid" in value.constructor.prototype)))
+        }
+        COMPILE::SWF{
+            ret = (value && value.hasOwnProperty("uid"));
+        }
+        return ret;
+    }
+
     /**
      *  Recursive helper used by the public clone method.
      *  @private
      */
     private static function cloneInternal(result:Object, value:Object):void
     {
-        if (value && /*value.hasOwnProperty*/("uid" in value))
+
+        if (isUIDObject(value))
             result.uid = value.uid;
     
         var classInfo:Object = getClassInfo(value);
@@ -214,7 +232,7 @@ public class ObjectUtil
         {
             //@todo the following 'v = value[p]' will only be emulated safely in js by using reflection library:
             v = value[p];
-            if (v && /*v.hasOwnProperty*/("uid" in v))
+            if (isUIDObject(v))
                 cloneInternal(result[p], v);
         }
     }
diff --git a/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/UIDUtil.as b/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/UIDUtil.as
index f6f3cc5798..b0fb4465d8 100644
--- a/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/UIDUtil.as
+++ b/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/UIDUtil.as
@@ -198,7 +198,11 @@ public class UIDUtil
                 IUID(item).uid = result;
             }
         }
-        else if ((item is IPropertyChangeNotifier) &&
+        //(GD) commented out the following 'else if' clause because I don't expect it should ever execute
+        // why: IPropertyChangeNotifier extends IUID, so any such item will have already passed the (item is IUID) check and caused previous code block to execute instead)
+        // therefore the (item is IPropertyChangeNotifier) check should always be false in 'else if' below
+        //@todo check this against Flex:
+        /*else if ((item is IPropertyChangeNotifier) &&
                  !(item is IUIComponent))
         {
             result = IPropertyChangeNotifier(item).uid;
@@ -207,7 +211,7 @@ public class UIDUtil
                 result = createUID();
                 IPropertyChangeNotifier(item).uid = result;
             }
-        }
+        }*/
         else if (item is String)
         {
             return item as String;
@@ -221,7 +225,7 @@ public class UIDUtil
                 if (item is XMLList && item.length == 1)
                     item = item[0];
 
-                /* LATER
+
                 if (item is XML)
                 {
                     // XML nodes carry their UID on the
@@ -255,7 +259,6 @@ public class UIDUtil
                 }
                 else
                 {
-                */
                     if ("mx_internal_uid" in item)
                         return item['mx_internal_uid']
 
@@ -283,7 +286,7 @@ public class UIDUtil
                             }
                         }
                     }
-                //}
+                }
             }
             catch(e:Error)
             {
diff --git a/frameworks/projects/MXRoyaleBase/src/test/royale/flexUnitTests/mxroyale/ObjectUtilTest.as b/frameworks/projects/MXRoyaleBase/src/test/royale/flexUnitTests/mxroyale/ObjectUtilTest.as
index 7c2bc51718..4a1797ae14 100644
--- a/frameworks/projects/MXRoyaleBase/src/test/royale/flexUnitTests/mxroyale/ObjectUtilTest.as
+++ b/frameworks/projects/MXRoyaleBase/src/test/royale/flexUnitTests/mxroyale/ObjectUtilTest.as
@@ -21,8 +21,9 @@ package flexUnitTests.mxroyale
     
     
     import mx.utils.ObjectUtil;
-    
-    import org.apache.royale.test.asserts.*;
+import mx.utils.UIDUtil;
+
+import org.apache.royale.test.asserts.*;
     import flexUnitTests.mxroyale.support.*;
     //import testshim.RoyaleUnitTestRunner;
     
@@ -357,12 +358,44 @@ package flexUnitTests.mxroyale
         }
     
     
-        /*[Test]
+        [Test]
         public function testCloning():void{
-            var item:TestClass6 = new TestClass6();
-        
-            
-        }*/
+            var s:String = "myString";
+
+            var out:Object = ObjectUtil.clone(s);
+
+            assertStrictlyEquals(s, out, 'unexpected String clone result');
+
+            var obj:Object = { test:'test'};
+            var inJSON:String = JSON.stringify(obj);
+            out = ObjectUtil.clone(obj);
+            assertStrictlyEquals(inJSON, JSON.stringify(out), 'unexpected dyn Object clone result');
+
+            UIDUtil.getUID(obj);
+            out = ObjectUtil.clone(obj);
+            //field order variation means JSON is not a valid way to compare:
+            assertTrue(simpleObjectCheckFields(obj, out), 'unexpected dyn Object clone result');
+
+        }
+
+        private static function simpleObjectCheckFields(obj1:Object, obj2:Object):Boolean{
+            if (obj1) {
+                if (!obj2) return false;
+                if (obj1 is String || obj1 is Number || obj1 is Boolean) return obj1 === obj2;
+                var obj1Count:uint = 0;
+                for (var field:String in obj1) {
+                    if (obj1[field] !== obj2[field]) return false;
+                    obj1Count++;
+                }
+                for (field in obj1) {
+                    obj1Count--;
+                }
+                if (obj1Count != 0) return false //mismatched field count
+            } else {
+                if (obj2) return false;
+            }
+            return true;
+        }
         
     }
 }


[royale-asjs] 01/02: Avoid the possibility of infinite loops (in JS only, SWF untested) with xml watchers. This can happen if changes are made in watcher functions.

Posted by gr...@apache.org.
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 acab343f73b939bb3b28a13f9142cba4f799104a
Author: greg-dove <gr...@gmail.com>
AuthorDate: Wed Apr 6 13:41:58 2022 +1200

    Avoid the possibility of infinite loops (in JS only, SWF untested) with xml watchers. This can happen if changes are made in watcher functions.
---
 .../src/main/royale/mx/utils/XMLNotifier.as        | 71 ++++++++++++++++++----
 1 file changed, 59 insertions(+), 12 deletions(-)

diff --git a/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/XMLNotifier.as b/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/XMLNotifier.as
index 5bc8a13fa1..c4d033b476 100644
--- a/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/XMLNotifier.as
+++ b/frameworks/projects/MXRoyaleBase/src/main/royale/mx/utils/XMLNotifier.as
@@ -20,10 +20,14 @@
 package mx.utils
 {
 
-import org.apache.royale.utils.ObjectMap;
+//import org.apache.royale.utils.ObjectMap;
 import mx.core.mx_internal;
 import mx.utils.IXMLNotifiable;
 
+COMPILE::SWF{
+    import flash.utils.Dictionary;
+}
+
 use namespace mx_internal;
 
 /**
@@ -98,13 +102,32 @@ public class XMLNotifier
             {
                 callee = notificationFunction;
             }
-            var xmlWatchers:ObjectMap = callee["watched"];
-            if (xmlWatchers != null)
-            {
-                xmlWatchers.forEach( function(truevalue:Object,notifiable:Object,map:Object):void {
+            //var xmlWatchers:ObjectMap = callee["watched"];
+
+            COMPILE::SWF{
+                var xmlWatchers:Dictionary = callee["watched"];
+                for (var notifiable:Object in xmlWatchers) {
                     IXMLNotifiable(notifiable).xmlNotification(currentTarget, ty, tar, value, detail);
-                } );
+                }
             }
+
+            COMPILE::JS{
+                var xmlWatchers:Map = callee["watched"];
+                if (xmlWatchers != null)
+                {
+                    var collected:Array = [];
+                    //note, if we don't collect these first and try to iterate directly, then there can be the case that iterating is infinite if the function caLL also somehow affects the xmlWatchers Map:
+                    xmlWatchers.forEach( function(truevalue:Object,notifiable:Object,map:Object):void {
+                        collected.push(notifiable);
+                    } );
+
+                    while(collected.length){
+                        IXMLNotifiable(collected.shift()).xmlNotification(currentTarget, ty, tar, value, detail);
+                    }
+                }
+            }
+
+
         }
 
         return notificationFunction;
@@ -181,13 +204,25 @@ public class XMLNotifier
             }
 
             // Watch lists are maintained on the notification function.
-            var xmlWatchers:ObjectMap;
-            if (watcherFunction["watched"] == undefined)
-                watcherFunction["watched"] = xmlWatchers = new ObjectMap(true,true);
+            if (watcherFunction["watched"] == undefined) {
+               // watcherFunction["watched"] = xmlWatchers = new ObjectMap(true,true);
+                COMPILE::SWF{
+                    var xmlWatchers:Dictionary = watcherFunction["watched"] = new Dictionary();
+                }
+
+                COMPILE::JS{
+                    var xmlWatchers:Map= watcherFunction["watched"] = new Map();
+                }
+            }
             else
                 xmlWatchers = watcherFunction["watched"];
 
-            xmlWatchers.set(notifiable, true);
+            COMPILE::SWF{
+                xmlWatchers[notifiable]=true;
+            }
+            COMPILE::JS{
+                xmlWatchers.set(notifiable, true);
+            }
         }
     }
 
@@ -223,12 +258,24 @@ public class XMLNotifier
             if (!(watcherFunction is Function))
                 return;
 
-            var xmlWatchers:ObjectMap;
+            COMPILE::SWF{
+                var xmlWatchers:Dictionary;
+            }
+
+            COMPILE::JS{
+                var xmlWatchers:Map;
+            }
 
             if (watcherFunction["watched"] != undefined)
             {
                 xmlWatchers = watcherFunction["watched"];
-                xmlWatchers.delete(notifiable);
+                COMPILE::SWF{
+                    delete xmlWatchers[notifiable];
+                }
+                COMPILE::JS{
+                    xmlWatchers.delete(notifiable);
+                }
+
             }           
         }
     }