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 2019/11/08 21:15:59 UTC

[royale-asjs] branch develop updated: Adding coercion to reflection setters. Should fix an issue reported in discussion thread. Added recent Reflection test updates.

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


The following commit(s) were added to refs/heads/develop by this push:
     new 2dc3e90  Adding coercion to reflection setters. Should fix an issue reported in discussion thread. Added recent Reflection test updates.
2dc3e90 is described below

commit 2dc3e90b3c56ba2ccecd32ee3eae2e8ea19c892c
Author: greg-dove <gr...@gmail.com>
AuthorDate: Sat Nov 9 10:15:40 2019 +1300

    Adding coercion to reflection setters. Should fix an issue reported in discussion thread.
    Added recent Reflection test updates.
---
 .../apache/royale/reflection/AccessorDefinition.as |   6 +
 .../apache/royale/reflection/VariableDefinition.as |   6 +
 .../test/royale/flexUnitTests/ReflectionTester.as  |   5 +-
 .../reflection/ReflectionTesterTestEdgeCases.as    | 321 +++++++++++++++++++++
 .../flexUnitTests/reflection/support/TestClass6.as |  91 ++++++
 .../reflection/support/testnamespace.as            |  26 ++
 6 files changed, 454 insertions(+), 1 deletion(-)

diff --git a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/AccessorDefinition.as b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/AccessorDefinition.as
index 72bea88..bc2c7b8 100644
--- a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/AccessorDefinition.as
+++ b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/AccessorDefinition.as
@@ -20,6 +20,7 @@ package org.apache.royale.reflection {
     
     COMPILE::JS{
         import goog.DEBUG;
+        import org.apache.royale.utils.Language;
     }
 	
 	COMPILE::SWF{
@@ -121,8 +122,11 @@ package org.apache.royale.reflection {
             }
 			var fieldName:String = name;
             if (uri) fieldName = QName.getAsObjectAccessFormat(uri, fieldName);
+            var valueClass:Class = getDefinitionByName(_rawData.type);
 			if (isStatic) {
 				_setter = function(value:*):* {
+                    //coerce
+                    value = Language.as(value, valueClass, true);
 					cl[fieldName] = value
 				}
 			} else {
@@ -130,6 +134,8 @@ package org.apache.royale.reflection {
 					if (goog.DEBUG) {
 						if (arguments.length != 2 || (!(instance is cl))) throw 'invalid setValue parameters';
 					}
+                    //coerce
+                    value = Language.as(value, valueClass, true);
 					instance[fieldName] = value;
 				}
 			}
diff --git a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/VariableDefinition.as b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/VariableDefinition.as
index 8fef888..1c9b161 100755
--- a/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/VariableDefinition.as
+++ b/frameworks/projects/Reflection/src/main/royale/org/apache/royale/reflection/VariableDefinition.as
@@ -20,6 +20,7 @@ package org.apache.royale.reflection
 {
 	COMPILE::JS{
 		import goog.DEBUG;
+		import org.apache.royale.utils.Language;
 	}
 	
 	COMPILE::SWF{
@@ -121,12 +122,15 @@ package org.apache.royale.reflection
    
 			COMPILE::JS {
 				var f:Function = _rawData.get_set;
+				var valueClass:Class = getDefinitionByName(_rawData.type);
 				if (isStatic) {
 					_setter = function(value:*):* {
                         if (goog.DEBUG) {
                             if (arguments.length != 1) throw 'invalid setValue parameters';
 							//todo: more robust runtime checking of value here for debug mode
                         }
+						//coerce
+						value = Language.as(value, valueClass, true);
                         f(value);
                     }
 				} else {
@@ -135,6 +139,8 @@ package org.apache.royale.reflection
 							if (arguments.length != 2 || !instance) throw 'invalid setValue parameters';
 							//todo: more robust runtime checking of value here for debug mode
 						}
+						//coerce
+						value = Language.as(value, valueClass, true);
 						f(instance, value);
 					}
 				}
diff --git a/frameworks/projects/Reflection/src/test/royale/flexUnitTests/ReflectionTester.as b/frameworks/projects/Reflection/src/test/royale/flexUnitTests/ReflectionTester.as
index 63005aa..b9282b9 100644
--- a/frameworks/projects/Reflection/src/test/royale/flexUnitTests/ReflectionTester.as
+++ b/frameworks/projects/Reflection/src/test/royale/flexUnitTests/ReflectionTester.as
@@ -35,7 +35,8 @@ package flexUnitTests
                 ReflectionTesterTestUseCache,
                 ReflectionTesterTestAlias,
                 ReflectionTesterTestDynamic,
-                ReflectionTesterNativeTypes
+                ReflectionTesterNativeTypes,
+                ReflectionTesterTestEdgeCases
             ];
         }
         
@@ -48,5 +49,7 @@ package flexUnitTests
         public var reflectionTesterDynamicTest:ReflectionTesterTestDynamic;
     
         public var reflectionTesterNativeTypes:ReflectionTesterNativeTypes;
+    
+        public var reflectionTesterTestEdgeCases:ReflectionTesterTestEdgeCases;
     }
 }
diff --git a/frameworks/projects/Reflection/src/test/royale/flexUnitTests/reflection/ReflectionTesterTestEdgeCases.as b/frameworks/projects/Reflection/src/test/royale/flexUnitTests/reflection/ReflectionTesterTestEdgeCases.as
new file mode 100644
index 0000000..ff4f6c0
--- /dev/null
+++ b/frameworks/projects/Reflection/src/test/royale/flexUnitTests/reflection/ReflectionTesterTestEdgeCases.as
@@ -0,0 +1,321 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 flexUnitTests.reflection
+{
+    import org.apache.royale.test.asserts.*;
+    
+    import flexUnitTests.reflection.support.*;
+    
+    import org.apache.royale.reflection.*;
+    import org.apache.royale.reflection.utils.getMembersWithNameMatch;
+    import org.apache.royale.reflection.utils.getMembersWithQNameMatch;
+    import org.apache.royale.reflection.utils.MemberTypes;
+    import org.apache.royale.reflection.utils.getMembers;
+
+    
+    /**
+     * @royalesuppresspublicvarwarning
+     */
+    public class ReflectionTesterTestEdgeCases
+    {
+        
+        public static var isJS:Boolean = COMPILE::JS;
+        
+        [BeforeClass]
+        public static function setUpBeforeClass():void
+        {
+        
+        }
+        
+        [AfterClass]
+        public static function tearDownAfterClass():void
+        {
+        }
+        
+        [Before]
+        public function setUp():void
+        {
+        }
+        
+        [After]
+        public function tearDown():void
+        {
+        }
+        
+     
+        
+        
+        [Test]
+        public function testUndefined():void
+        {
+            var test:* = getDefinitionByName('undefined');
+            assertTrue(test === undefined, 'getDefinitionByName for undefined should return undefined reference')
+            
+        }
+    
+    
+        [Test]
+        public function testNull():void
+        {
+            var err:Boolean;
+            try{
+                var test:* = getDefinitionByName('null');
+            } catch(e:Error) {
+                err = true;
+            }
+            assertTrue(err, 'getDefinitionByName for null should throw an error')
+        }
+    
+    
+        [Test]
+        public function testCustomNamespace():void
+        {
+            var inst:TestClass6 = new TestClass6();
+            var def:TypeDefinition = describeType(inst);
+            
+            var collection:Array;
+            var subset:Array;
+            collection = getMembers(def,false,MemberTypes.VARIABLES);
+            
+            assertEquals(collection.length, 2, 'unexpected variable count');
+            
+            subset = getMembersWithNameMatch(collection,'myVar');
+            assertEquals(subset.length, 1, 'unexpected variable count');
+            //default is public namespace
+            assertEquals(MemberDefinitionBase(subset[0]).uri, '', 'unexpected namespace from query');
+    
+            subset = getMembersWithNameMatch(collection,'myVar', null, true);
+            assertEquals(subset.length, 2, 'unexpected variable count');
+    
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, 'myVar'), null);
+            assertEquals(subset.length, 1, 'unexpected variable count');
+
+            assertEquals(MemberDefinitionBase(subset[0]).uri, String(testnamespace), 'unexpected namespace from query');
+    
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, '*'), null);
+            assertEquals(subset.length, 1, 'unexpected variable count');
+
+            assertEquals(MemberDefinitionBase(subset[0]).uri, String(testnamespace), 'unexpected namespace from query');
+    
+            subset = getMembersWithQNameMatch(collection,null, null);
+            assertEquals(subset.length, 2, 'unexpected variable count');
+            
+            collection = getMembers(def,false,MemberTypes.ACCESSORS);
+            assertEquals(collection.length, 2, 'unexpected accessor count');
+    
+            collection = getMembers(def,false,MemberTypes.METHODS);
+            assertEquals(collection.length, 2, 'unexpected method count');
+            
+            //no need to use extra scrutiny on the last two queries, because the variable tests already verified that.
+            
+            //now try read/write
+            //first vars
+            var varDefinition:VariableDefinition;
+            collection = getMembers(def,false,MemberTypes.VARIABLES);
+            //public myVar
+            subset = getMembersWithNameMatch(collection,'myVar');
+            varDefinition = subset[0];
+            //read
+            assertEquals(varDefinition.getValue(inst), inst.myVar, 'unexpected variable read result');
+
+            //write
+            varDefinition.setValue(inst, 'setViaPublicReflection');
+            assertEquals('setViaPublicReflection', inst.myVar, 'unexpected variable write result');
+            //testnamespace::myVar
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, 'myVar'), null);
+            varDefinition= subset[0];
+            //read
+            assertEquals(varDefinition.getValue(inst), inst.testnamespace::myVar, 'unexpected variable read result');
+            //write
+            varDefinition.setValue(inst, 'setViaCustomNSReflection');
+            assertEquals('setViaCustomNSReflection', inst.testnamespace::myVar, 'unexpected variable write result');
+            //next methods
+            var methodDefinition:MethodDefinition;
+            collection = getMembers(def,false,MemberTypes.METHODS);
+            subset = getMembersWithNameMatch(collection,'myMethod');
+            methodDefinition = subset[0];
+            //public myMethod
+            assertEquals(methodDefinition.getMethod(inst), inst.myMethod, 'unexpected method access result');
+            //testnamespace::myMethod
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, 'myMethod'), null);
+            methodDefinition= subset[0];
+            //testnamespace myMethod
+            assertEquals(methodDefinition.getMethod(inst), inst.testnamespace::myMethod, 'unexpected method access result');
+    
+            //next accessors
+            var accessorDefinition:AccessorDefinition;
+            collection = getMembers(def,false,MemberTypes.ACCESSORS);
+            subset = getMembersWithNameMatch(collection,'myAccessor');
+            accessorDefinition = subset[0];
+            //public myAccessor
+            //read
+            assertEquals(accessorDefinition.getValue(inst), inst.myAccessor, 'unexpected accessor access result');
+            //write
+            //this is readOnly, so...
+            var hasError:Boolean;
+            try{
+                accessorDefinition.setValue(inst, 'setViaPublicReflection');
+            } catch(e:Error) {
+                hasError = true;
+            }
+            assertTrue(hasError, 'unexpected non-error read-only access write result');
+
+            //testnamespace::myAccessor
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, 'myAccessor'), null);
+            accessorDefinition = subset[0];
+            //testnamespace::myAccessor
+            //read
+            assertEquals(accessorDefinition.getValue(inst), inst.testnamespace::myAccessor, 'unexpected accessor access result');
+    
+            accessorDefinition.setValue(inst, 'setViaCustomNSReflection');
+    
+            assertEquals( inst.testnamespace::myAccessor,'setViaCustomNSReflection', 'unexpected accessor post-write access result');
+    
+        }
+    
+        [Test]
+        public function testCustomNamespaceStatic():void
+        {
+
+            var def:TypeDefinition = describeType(TestClass6);
+        
+            var collection:Array;
+            var subset:Array;
+            collection = getMembers(def,true,MemberTypes.VARIABLES|MemberTypes.STATIC_ONLY);
+        
+            assertEquals(collection.length, 2, 'unexpected variable count');
+        
+            subset = getMembersWithNameMatch(collection,'myStaticVar');
+            assertEquals(subset.length, 1, 'unexpected variable count');
+            //default is public namespace
+            assertEquals(MemberDefinitionBase(subset[0]).uri, '', 'unexpected namespace from query');
+        
+            subset = getMembersWithNameMatch(collection,'myStaticVar', null, true);
+            assertEquals(subset.length, 2, 'unexpected variable count');
+        
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, 'myStaticVar'), null);
+            assertEquals(subset.length, 1, 'unexpected variable count');
+        
+            assertEquals(MemberDefinitionBase(subset[0]).uri, String(testnamespace), 'unexpected namespace from query');
+        
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, '*'), null);
+            assertEquals(subset.length, 1, 'unexpected variable count');
+        
+            assertEquals(MemberDefinitionBase(subset[0]).uri, String(testnamespace), 'unexpected namespace from query');
+        
+            subset = getMembersWithQNameMatch(collection,null, null);
+            assertEquals(subset.length, 2, 'unexpected variable count');
+        
+            collection = getMembers(def,true,MemberTypes.ACCESSORS|MemberTypes.STATIC_ONLY);
+            var expectedCount:uint = isJS ? 2  : 3; //SWF has 'prototype' also as a readonly accessor
+            assertEquals(collection.length, expectedCount, 'unexpected accessor count');
+        
+            collection = getMembers(def,true,MemberTypes.METHODS|MemberTypes.STATIC_ONLY);
+            assertEquals(collection.length, 2, 'unexpected method count');
+        
+            //no need to use extra scrutiny on the last two queries, because the variable tests already verified that.
+        
+            //now try read/write
+            //first: vars
+            var varDefinition:VariableDefinition;
+            collection = getMembers(def,true,MemberTypes.VARIABLES|MemberTypes.STATIC_ONLY);
+            //public myVar
+            subset = getMembersWithNameMatch(collection,'myStaticVar');
+            varDefinition = subset[0];
+            //read
+            assertEquals(varDefinition.getValue(), TestClass6.myStaticVar, 'unexpected variable read result');
+        
+            //write
+            varDefinition.setValue('setViaPublicReflection');
+            assertEquals('setViaPublicReflection', TestClass6.myStaticVar, 'unexpected variable write result');
+            //testnamespace::myVar
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, 'myStaticVar'), null);
+            varDefinition= subset[0];
+            //read
+            assertEquals(varDefinition.getValue(), TestClass6.testnamespace::myStaticVar, 'unexpected variable read result');
+            //write
+            varDefinition.setValue('setViaCustomNSReflection');
+            assertEquals('setViaCustomNSReflection', TestClass6.testnamespace::myStaticVar, 'unexpected variable write result');
+            //next: methods
+            var methodDefinition:MethodDefinition;
+            collection = getMembers(def,true,MemberTypes.METHODS|MemberTypes.STATIC_ONLY);
+            subset = getMembersWithNameMatch(collection,'myStaticMethod');
+            methodDefinition = subset[0];
+            //public myMethod
+            assertEquals(methodDefinition.getMethod(), TestClass6.myStaticMethod, 'unexpected method access result');
+            //testnamespace::myMethod
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, 'myStaticMethod'), null);
+            methodDefinition= subset[0];
+            //testnamespace myMethod
+            assertEquals(methodDefinition.getMethod(), TestClass6.testnamespace::myStaticMethod, 'unexpected method access result');
+        
+            //next: accessors
+            var accessorDefinition:AccessorDefinition;
+            collection = getMembers(def,true,MemberTypes.ACCESSORS|MemberTypes.STATIC_ONLY);
+            subset = getMembersWithNameMatch(collection,'myStaticAccessor');
+            accessorDefinition = subset[0];
+            //public myAccessor
+            //read
+            assertEquals(accessorDefinition.getValue(), TestClass6.myStaticAccessor, 'unexpected accessor access result');
+            //write
+            //this is readOnly, so...
+            var hasError:Boolean;
+            try{
+                accessorDefinition.setValue('setViaPublicReflection');
+            } catch(e:Error) {
+                hasError = true;
+            }
+            assertTrue(hasError, 'unexpected non-error read-only access write result');
+        
+            //testnamespace::myAccessor
+            subset = getMembersWithQNameMatch(collection,new QName(testnamespace, 'myStaticAccessor'), null);
+            accessorDefinition = subset[0];
+    
+            //testnamespace::myAccessor
+            //read
+            assertEquals(accessorDefinition.getValue(), TestClass6.testnamespace::myStaticAccessor, 'unexpected accessor access result');
+        
+            accessorDefinition.setValue('setViaCustomNSReflection');
+        
+            assertEquals( TestClass6.testnamespace::myStaticAccessor,'setViaCustomNSReflection', 'unexpected accessor post-write access result');
+        
+        }
+    
+        [Test]
+        public function testWrongSetValueType():void{
+            var inst:TestClass1 = new TestClass1();
+    
+            var def:TypeDefinition = describeType(inst);
+            var collection:Array;
+            var subset:Array;
+            collection = getMembers(def,false,MemberTypes.VARIABLES);
+            subset = getMembersWithNameMatch(collection,'testVar');
+            var testVarDef:VariableDefinition = subset[0];
+            //assign a Number to the String typed testVar member:
+            testVarDef.setValue(inst, 0.0);
+            assertStrictlyEquals(inst.testVar, '0', 'unexpected assigned value');
+            collection = getMembers(def,false,MemberTypes.ACCESSORS);
+            subset = getMembersWithNameMatch(collection,'accessorTest');
+            var accessorTestDef:AccessorDefinition = subset[0];
+            accessorTestDef.setValue(inst, 0.0);
+            assertStrictlyEquals(inst.accessorTest, '0', 'unexpected assigned value');
+        }
+        
+    }
+}
diff --git a/frameworks/projects/Reflection/src/test/royale/flexUnitTests/reflection/support/TestClass6.as b/frameworks/projects/Reflection/src/test/royale/flexUnitTests/reflection/support/TestClass6.as
new file mode 100644
index 0000000..c5c34bf
--- /dev/null
+++ b/frameworks/projects/Reflection/src/test/royale/flexUnitTests/reflection/support/TestClass6.as
@@ -0,0 +1,91 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 flexUnitTests.reflection.support
+{
+    
+    
+    /**
+     * @royalesuppresspublicvarwarning
+     */
+    public class TestClass6
+    {
+        //Note: do not change this test class unless you change the related tests to
+        //support any changes that might appear when testing reflection into it
+    
+        public static var myStaticVar:String = 'publicStaticMyVar';
+    
+        testnamespace static var myStaticVar:String = 'testnamespaceStaticMyVar';
+    
+        public static function myStaticMethod():String{
+            return 'public myStaticMethod';
+        }
+    
+        testnamespace static function myStaticMethod():String{
+            return 'testnamespace myStaticMethod';
+        }
+    
+        private static var _vstatic:String = 'public static accessor';
+        public static function get myStaticAccessor():String{
+            return _vstatic;
+        }
+    
+        private static var _v2static:String = 'testnamespace static accessor';
+        testnamespace static function get myStaticAccessor():String{
+            return _v2static;
+        }
+        testnamespace static function set myStaticAccessor(value:String):void{
+            _v2static = value;
+        }
+        
+        
+        
+        public function TestClass6()
+        {
+        
+        }
+        
+        public var myVar:String = 'publicMyVar';
+        
+        testnamespace var myVar:String = 'testnamespaceMyVar';
+        
+        public function myMethod():String{
+            return 'public myMethod';
+        }
+    
+        testnamespace function myMethod():String{
+            return 'testnamespace myMethod';
+        }
+    
+        private var _v:String = 'public accessor';
+        public function get myAccessor():String{
+            return _v;
+        }
+        
+        private var _v2:String = 'testnamespace accessor';
+        testnamespace function get myAccessor():String{
+            return _v2;
+        }
+        testnamespace function set myAccessor(value:String):void{
+            _v2 = value;
+        }
+        
+    }
+    
+    
+}
diff --git a/frameworks/projects/Reflection/src/test/royale/flexUnitTests/reflection/support/testnamespace.as b/frameworks/projects/Reflection/src/test/royale/flexUnitTests/reflection/support/testnamespace.as
new file mode 100644
index 0000000..2544e8c
--- /dev/null
+++ b/frameworks/projects/Reflection/src/test/royale/flexUnitTests/reflection/support/testnamespace.as
@@ -0,0 +1,26 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 flexUnitTests.reflection.support
+{
+    
+    
+
+    public namespace testnamespace = 'http://testnamespace.com';
+   
+}