diff --git a/LICENSE b/LICENSE index 130e2da..e87a115 100644 --- a/LICENSE +++ b/LICENSE @@ -1,8 +1,363 @@ -Copyright 2011 Malachi Griffie - -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. - -website : http://nexussays.com -source : https://github.com/nexussays/nexuslib-as3 +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/README.md b/README.md index b3e8b4e..becec3e 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,18 @@ # Overview -nexuslib is a collection of (in-development) Actionscript libraries. +nexuslib is a collection of Actionscript libraries. Enums, Random, Reflection, Serialization, Crypto. -The reflection library is production ready and is currently in-use in production environments. +The reflection library specifically is production ready and is currently in-use in production environments. ## Getting Started Download the [latest release](https://github.com/nexussays/nexuslib-as3/releases), or clone the repo and reference in your project. -### Dependencies +### External Dependencies -blooddy-crypto (statically linked with nexuslib.swc) +None + +> blooddy-crypto is statically linked with nexuslib.swc ### API Docs @@ -18,25 +20,33 @@ http://docs.nexussays.com/nexuslib/index.html ## Components +### Enum & EnumSet + +Since AS3 doesn't provide a native enum structure you can use this to ceate one thusly: +```as3 +public class MyEnum extends Enum +{ + public static const Enum1 : MyEnum = new MyEnum(); + public static const Enum2 : MyEnum = new MyEnum(); + + public static function get All():EnumSet { return Enum.values(MyEnum); } +} +``` +For more examples of correct and incorrect Enum usage, see the [mocks in the test directory](./test/src/mock) + ### Reflection & Serialization `nexus.utils.reflection`, `nexus.utils.serialization` Reflection & serialization library. Features deterministic JSON de/serialization, deserializing directly to typed AS objects, a structured reflection class heirarchy, and more. Full support for Application Domains and namespaces. -### Enigma +### Crypto & security `nexus.security.crypto` -Crypto & security library. Currently only provides an HMAC class and some utilities. - -### Mercury - -`nexus.net` - -In development. +Currently only provides an HMAC class and some utilities. -### Git +### Version control (Git) `nexus.vcs.git` diff --git a/etc/core_logo.png b/etc/core_logo.png deleted file mode 100644 index b0ee599..0000000 Binary files a/etc/core_logo.png and /dev/null differ diff --git a/etc/count.bat b/etc/count.bat deleted file mode 100644 index 2b067b4..0000000 --- a/etc/count.bat +++ /dev/null @@ -1,5 +0,0 @@ -@ECHO OFF -cd %~dp0 -cd .. -cloc --quiet .\projects -@PAUSE \ No newline at end of file diff --git a/src/avmplus/AVMDescribeType.as b/src/avmplus/AVMDescribeType.as index 64fec47..b46a3eb 100644 --- a/src/avmplus/AVMDescribeType.as +++ b/src/avmplus/AVMDescribeType.as @@ -9,20 +9,20 @@ package avmplus /** * Provides access to the avmplus.describeTypeJSON method which was (accidentally?) exposed in Flash 10.1 * - * @see http://hg.mozilla.org/tamarin-redux/file/tip/core/DescribeType.as + * @see http://hg.mozilla.org/tamarin-redux/file/tip/core/DescribeType.as * @private */ public final class AVMDescribeType { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - private static var s_isAvailable : Boolean = false; - - //as defined in avm - /* - public const HIDE_NSURI_METHODS:uint = 0x0001; + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + private static var s_isAvailable : Boolean = false; + + //as defined in avm + /* + public const HIDE_NSURI_METHODS:uint = 0x0001; public const INCLUDE_BASES:uint = 0x0002; public const INCLUDE_INTERFACES:uint = 0x0004; public const INCLUDE_VARIABLES:uint = 0x0008; @@ -34,86 +34,86 @@ public final class AVMDescribeType public const USE_ITRAITS:uint = 0x0200; // if set, hide everything from the base Object class public const HIDE_OBJECT:uint = 0x0400; - //*/ - private static const INCLUDE_BASES:uint = avmplus.INCLUDE_BASES; - private static const INCLUDE_INTERFACES:uint= avmplus.INCLUDE_INTERFACES; - private static const INCLUDE_VARIABLES:uint = avmplus.INCLUDE_VARIABLES; - private static const INCLUDE_ACCESSORS:uint = avmplus.INCLUDE_ACCESSORS; - private static const INCLUDE_METHODS:uint = avmplus.INCLUDE_METHODS; - private static const INCLUDE_METADATA:uint = avmplus.INCLUDE_METADATA; - private static const INCLUDE_CONSTRUCTOR:uint = avmplus.INCLUDE_CONSTRUCTOR; - private static const INCLUDE_TRAITS:uint = avmplus.INCLUDE_TRAITS; - private static const USE_ITRAITS:uint = avmplus.USE_ITRAITS; - private static const HIDE_OBJECT:uint = avmplus.HIDE_OBJECT; - - private static const GET_CLASS : uint = INCLUDE_VARIABLES | INCLUDE_ACCESSORS | INCLUDE_METHODS | INCLUDE_METADATA | INCLUDE_TRAITS | HIDE_OBJECT; - private static const GET_INSTANCE : uint = INCLUDE_BASES | INCLUDE_INTERFACES | INCLUDE_VARIABLES | INCLUDE_ACCESSORS | INCLUDE_METHODS | INCLUDE_METADATA | INCLUDE_CONSTRUCTOR | INCLUDE_TRAITS | USE_ITRAITS | HIDE_OBJECT; - - //-------------------------------------- - // STATIC INITIALIZER - //-------------------------------------- - - { - try - { - if(describeTypeJSON is Function && describeType is Function) - { - s_isAvailable = true; - } - } - catch(e:Error) - { - s_isAvailable = false; - } - } - - //-------------------------------------- - // GETTERS/SETTERS - //-------------------------------------- - - public static function get isAvailable():Boolean { return s_isAvailable; } - - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - public static function getJson(object:Object):Object - { - var factory : Object = describeTypeJSON(object, GET_INSTANCE); - factory.traits.isDynamic = factory.isDynamic; - factory.traits.isFinal = factory.isFinal; - factory.traits.isStatic = factory.isStatic; - factory.traits.name = factory.name; - factory = factory.traits; - factory.methods = factory.methods || []; - factory.accessors = factory.accessors || []; - factory.variables = factory.variables || []; - factory.constructor = factory.constructor || []; - - var obj : Object = describeTypeJSON(object, GET_CLASS); - obj = obj.traits; - obj.methods = obj.methods || []; - obj.accessors = obj.accessors || []; - obj.variables = obj.variables || []; - delete obj.bases; - delete obj.constructor; - delete obj.interfaces; - - obj.factory = factory; - - return obj; - } - - /** - * This method just calls getJson() and parses the result to XML. It is advised to not use this method unless you are sending the data - * to something that expects it in the standard flash.utils.describeType() format. - * @param object - * @return - */ - public static function getXml(object:Object):XML - { - return describeType(object, GET_CLASS); - } + //*/ + private static const INCLUDE_BASES:uint = avmplus.INCLUDE_BASES; + private static const INCLUDE_INTERFACES:uint= avmplus.INCLUDE_INTERFACES; + private static const INCLUDE_VARIABLES:uint = avmplus.INCLUDE_VARIABLES; + private static const INCLUDE_ACCESSORS:uint = avmplus.INCLUDE_ACCESSORS; + private static const INCLUDE_METHODS:uint = avmplus.INCLUDE_METHODS; + private static const INCLUDE_METADATA:uint = avmplus.INCLUDE_METADATA; + private static const INCLUDE_CONSTRUCTOR:uint = avmplus.INCLUDE_CONSTRUCTOR; + private static const INCLUDE_TRAITS:uint = avmplus.INCLUDE_TRAITS; + private static const USE_ITRAITS:uint = avmplus.USE_ITRAITS; + private static const HIDE_OBJECT:uint = avmplus.HIDE_OBJECT; + + private static const GET_CLASS : uint = INCLUDE_VARIABLES | INCLUDE_ACCESSORS | INCLUDE_METHODS | INCLUDE_METADATA | INCLUDE_TRAITS | HIDE_OBJECT; + private static const GET_INSTANCE : uint = INCLUDE_BASES | INCLUDE_INTERFACES | INCLUDE_VARIABLES | INCLUDE_ACCESSORS | INCLUDE_METHODS | INCLUDE_METADATA | INCLUDE_CONSTRUCTOR | INCLUDE_TRAITS | USE_ITRAITS | HIDE_OBJECT; + + //-------------------------------------- + // STATIC INITIALIZER + //-------------------------------------- + + { + try + { + if(describeTypeJSON is Function && describeType is Function) + { + s_isAvailable = true; + } + } + catch(e:Error) + { + s_isAvailable = false; + } + } + + //-------------------------------------- + // GETTERS/SETTERS + //-------------------------------------- + + public static function get isAvailable():Boolean { return s_isAvailable; } + + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + public static function getJson(object:Object):Object + { + var factory : Object = describeTypeJSON(object, GET_INSTANCE); + factory.traits.isDynamic = factory.isDynamic; + factory.traits.isFinal = factory.isFinal; + factory.traits.isStatic = factory.isStatic; + factory.traits.name = factory.name; + factory = factory.traits; + factory.methods = factory.methods || []; + factory.accessors = factory.accessors || []; + factory.variables = factory.variables || []; + factory.constructor = factory.constructor || []; + + var obj : Object = describeTypeJSON(object, GET_CLASS); + obj = obj.traits; + obj.methods = obj.methods || []; + obj.accessors = obj.accessors || []; + obj.variables = obj.variables || []; + delete obj.bases; + delete obj.constructor; + delete obj.interfaces; + + obj.factory = factory; + + return obj; + } + + /** + * This method just calls getJson() and parses the result to XML. It is advised to not use this method unless you are sending the data + * to something that expects it in the standard flash.utils.describeType() format. + * @param object + * @return + */ + public static function getXml(object:Object):XML + { + return describeType(object, GET_CLASS); + } } -} \ No newline at end of file +} diff --git a/src/nexus/Enum.as b/src/nexus/Enum.as index b8558f1..13ca120 100644 --- a/src/nexus/Enum.as +++ b/src/nexus/Enum.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -16,7 +16,7 @@ import nexus.utils.reflection.Reflection; /** * Base class for enumerations. Used extensively throughout the system. - * @example + * @example public class MyEnum extends Enum { //This provides additional assurance that your Enum will be properly created. However, if @@ -30,239 +30,239 @@ public class MyEnum extends Enum */ public class Enum implements IEnum { - /** - * Holds an EnumSet of all the values of each Enum - */ - private static const s_enumRegistry : Dictionary = new Dictionary(); - - /** - * Internal method used to register a class in the registry and initialize all instance values - */ - protected static function initialize(enumType : Class) : void + /** + * Holds an EnumSet of all the values of each Enum + */ + private static const s_enumRegistry : Dictionary = new Dictionary(); + + /** + * Internal method used to register a class in the registry and initialize all instance values + */ + protected static function initialize(enumType : Class) : void { - if(s_enumRegistry[enumType] == null) - { - var typeArray : Array = new Array(); - var typeInfo : Object = AVMDescribeType.getJson(enumType); - var flag : uint = 1; - typeInfo.variables.sortOn("name"); - for(var x : int = 0; x < typeInfo.variables.length; ++x) - { - var fieldInfo : Object = typeInfo.variables[x]; - //account for namespaces - var enum : Enum = enumType[new QName(fieldInfo.uri == null ? "" : new Namespace("", fieldInfo.uri), fieldInfo.name)] as Enum; - if(enum != null) - { - if(fieldInfo.access == "readwrite") - { - throw new SyntaxError("All Enum values must be defined as constants"); - } - enum.m_name = fieldInfo.name; - enum.m_fullname = Reflection.getQualifiedClassName(enum) + "." + fieldInfo.name; - if(enum.m_value == int.MIN_VALUE) - { - enum.m_value = flag; - } - enum.m_isInitialized = true; - - flag <<= 1; - - typeArray.push(enum); - } - } - - s_enumRegistry[enumType] = EnumSet.fromArrayInternal(typeArray); - } + if(s_enumRegistry[enumType] == null) + { + var typeArray : Array = new Array(); + var typeInfo : Object = AVMDescribeType.getJson(enumType); + var flag : uint = 1; + typeInfo.variables.sortOn("name"); + for(var x : int = 0; x < typeInfo.variables.length; ++x) + { + var fieldInfo : Object = typeInfo.variables[x]; + //account for namespaces + var enum : Enum = enumType[new QName(fieldInfo.uri == null ? "" : new Namespace("", fieldInfo.uri), fieldInfo.name)] as Enum; + if(enum != null) + { + if(fieldInfo.access == "readwrite") + { + throw new SyntaxError("All Enum values must be defined as constants"); + } + enum.m_name = fieldInfo.name; + enum.m_fullname = Reflection.getQualifiedClassName(enum) + "." + fieldInfo.name; + if(enum.m_value == int.MIN_VALUE) + { + enum.m_value = flag; + } + enum.m_isInitialized = true; + + flag <<= 1; + + typeArray.push(enum); + } + } + + s_enumRegistry[enumType] = EnumSet.fromArrayInternal(typeArray); + } } - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - /** - * @private - */ - protected var m_value : int; - - private var m_name : String; - private var m_fullname : String; - - /** - * Internal field used by the Enum initializer - */ - private var m_isInitialized : Boolean; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function Enum(valueOverride: Number = NaN) - { - m_value = (!isNaN(valueOverride) && isFinite(valueOverride)) ? valueOverride : int.MIN_VALUE; - - //Class will not be available for Reflection until it has finished instantiating all its constants, so if we are - //able to get the class, then it has already been fully initialized and therefore this constructor was called - //from outside the class definition - if(getDefinitionByName(getQualifiedClassName(this)) != null) - { - throw new IllegalOperationError("Cannot create an instance of Enum " + this["constructor"]); - } - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - /** - * The name of this enum item - */ - public function get name():String - { - confirmInit(); - - return m_name; - } - - /** - * The class and name of this enum item - */ - public final function get fullname():String - { - confirmInit(); - - return m_fullname; - } - - /** - * The integer value of this enum item. Unless overridden in your enum subclass ctor, this - * can be used as a flag to perform bitwise operations. - */ - public function get value():int - { - confirmInit(); - - return m_value; - } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * @inheritDoc - */ - public final function equals(matchValue:Object):Boolean - { - confirmInit(); - - if(matchValue == null) - { - return false; - } - else if(matchValue is Enum) - { - return this == matchValue; - } - else if(matchValue is EnumSet) - { - return EnumSet(matchValue).equals(this); - } - else if(matchValue is Array || matchValue is Vector.<*>) - { - return matchValue.length == 1 && matchValue[0] == this; - } - return false; - } - - /** - * @inheritDoc - */ - public final function intersects(matchValue:Object):Boolean - { - confirmInit(); - - if(matchValue == null) - { - return false; - } - else if(matchValue is Enum) - { - return this == matchValue; - } - else if(matchValue is EnumSet) - { - return EnumSet(matchValue).intersects(this); - } - else if(matchValue is Array || matchValue is Vector.<*>) - { - for each(var val : * in matchValue) - { - if(val == this) - { - return true; - } - } - return false; - } - return false; - } - - public function toString():String - { - return this.name; - } - - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - /** - * Retrieve all the values of the provided enum class - * @param enumType The class to retrieve values from - * @return An EnumSet containing all the values of the provided enum - */ - public static function values(enumType:Class):EnumSet - { - initialize(enumType); - - return s_enumRegistry[enumType]; - } - - /** - * Given an enum type, return the enum matching the provided value. If none exists, reutrn null. - * @param enumType - * @param value A value, most likely a string, to parse to an enum - * @param isCaseSensitive If true, matching is not case sensitive - * @return An enum of the provided type matching the provided value, or null if none exists. - */ - public static function fromString(enumType:Class, value:Object, isCaseSensitive:Boolean=false):Enum + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + /** + * @private + */ + protected var m_value : int; + + private var m_name : String; + private var m_fullname : String; + + /** + * Internal field used by the Enum initializer + */ + private var m_isInitialized : Boolean; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function Enum(valueOverride: Number = NaN) + { + m_value = (!isNaN(valueOverride) && isFinite(valueOverride)) ? valueOverride : int.MIN_VALUE; + + //Class will not be available for Reflection until it has finished instantiating all its constants, so if we are + //able to get the class, then it has already been fully initialized and therefore this constructor was called + //from outside the class definition + if(getDefinitionByName(getQualifiedClassName(this)) != null) + { + throw new IllegalOperationError("Cannot create an instance of Enum " + this["constructor"]); + } + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + /** + * The name of this enum item + */ + public function get name():String + { + confirmInit(); + + return m_name; + } + + /** + * The class and name of this enum item + */ + public final function get fullname():String + { + confirmInit(); + + return m_fullname; + } + + /** + * The integer value of this enum item. Unless overridden in your enum subclass ctor, this + * can be used as a flag to perform bitwise operations. + */ + public function get value():int + { + confirmInit(); + + return m_value; + } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * @inheritDoc + */ + public final function equals(matchValue:Object):Boolean + { + confirmInit(); + + if(matchValue == null) + { + return false; + } + else if(matchValue is Enum) + { + return this == matchValue; + } + else if(matchValue is EnumSet) + { + return EnumSet(matchValue).equals(this); + } + else if(matchValue is Array || matchValue is Vector.<*>) + { + return matchValue.length == 1 && matchValue[0] == this; + } + return false; + } + + /** + * @inheritDoc + */ + public final function intersects(matchValue:Object):Boolean + { + confirmInit(); + + if(matchValue == null) + { + return false; + } + else if(matchValue is Enum) + { + return this == matchValue; + } + else if(matchValue is EnumSet) + { + return EnumSet(matchValue).intersects(this); + } + else if(matchValue is Array || matchValue is Vector.<*>) + { + for each(var val : * in matchValue) + { + if(val == this) + { + return true; + } + } + return false; + } + return false; + } + + public function toString():String + { + return this.name; + } + + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + /** + * Retrieve all the values of the provided enum class + * @param enumType The class to retrieve values from + * @return An EnumSet containing all the values of the provided enum + */ + public static function values(enumType:Class):EnumSet + { + initialize(enumType); + + return s_enumRegistry[enumType]; + } + + /** + * Given an enum type, return the enum matching the provided value. If none exists, reutrn null. + * @param enumType + * @param value A value, most likely a string, to parse to an enum + * @param isCaseSensitive If true, matching is not case sensitive + * @return An enum of the provided type matching the provided value, or null if none exists. + */ + public static function fromString(enumType:Class, value:Object, isCaseSensitive:Boolean=false):Enum { - initialize(enumType); - - var str : String = isCaseSensitive ? (value + "") : (value + "").toLowerCase(); - var values : Array = s_enumRegistry[enumType].values; + initialize(enumType); + + var str : String = isCaseSensitive ? (value + "") : (value + "").toLowerCase(); + var values : Array = s_enumRegistry[enumType].values; for(var x : int = 0; x < values.length; ++x) { - var enum : Enum = values[x]; - if((isCaseSensitive && enum.m_name == str) || (!isCaseSensitive && enum.m_name.toLowerCase() == str)) - { - return enum; - } + var enum : Enum = values[x]; + if((isCaseSensitive && enum.m_name == str) || (!isCaseSensitive && enum.m_name.toLowerCase() == str)) + { + return enum; + } } - - return null; + + return null; } - - //-------------------------------------- - // PRIVATE METHODS - //-------------------------------------- - - private function confirmInit():void - { - if(!m_isInitialized) - { - initialize(Reflection.getClass(this)); - } - } + + //-------------------------------------- + // PRIVATE METHODS + //-------------------------------------- + + private function confirmInit():void + { + if(!m_isInitialized) + { + initialize(Reflection.getClass(this)); + } + } +} } -} \ No newline at end of file diff --git a/src/nexus/EnumSet.as b/src/nexus/EnumSet.as index a8993cf..f19702c 100644 --- a/src/nexus/EnumSet.as +++ b/src/nexus/EnumSet.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -13,165 +13,165 @@ import flash.utils.*; */ public class EnumSet implements IEnum { - //-------------------------------------- - // PRIVATE VARIABLES - //-------------------------------------- - - /** - * @private - */ - protected var m_values:Array; - - //-------------------------------------- - // INITIALIZE - //-------------------------------------- - - /** - * Use static methods on EnumSet to instantiate - * @private - */ - public function EnumSet() - { - m_values = []; - } - - /** - * Create a new EnumSet from the enum values in the provided array - * @param values - * @throws ArgumentError If any of the values in the provided Array do not extend Enum - * @return - */ - static public function fromArray(values:Array):EnumSet - { - var result : EnumSet = new EnumSet(); - //check for enums, retain order, and don't allow duplicates - for(var x:int = 0; x < values.length; ++x) - { - var item:Object = values[x]; - if(!(item is Enum)) - { - throw new ArgumentError("Cannot create EnumSet. Value " + item + " is not an Enum"); - } - else if(result.m_values.indexOf(item) == -1) - { - result.m_values.push(item); - } - } - return result; - } - - /** - * Create a new EnumSet from the enums provided as arguments to this method - * @param ...args - * @return - */ - static public function fromArgs(...args):EnumSet - { - return EnumSet.fromArray(args); - } - - /** - * Internal create method that doesn't check or filter values - * @private - */ - static internal function fromArrayInternal(array:Array):EnumSet - { - var result : EnumSet = new EnumSet(); - result.m_values = array; - return result; - } + //-------------------------------------- + // PRIVATE VARIABLES + //-------------------------------------- + + /** + * @private + */ + protected var m_values:Array; + + //-------------------------------------- + // INITIALIZE + //-------------------------------------- + + /** + * Use static methods on EnumSet to instantiate + * @private + */ + public function EnumSet() + { + m_values = []; + } + + /** + * Create a new EnumSet from the enum values in the provided array + * @param values + * @throws ArgumentError If any of the values in the provided Array do not extend Enum + * @return + */ + static public function fromArray(values:Array):EnumSet + { + var result : EnumSet = new EnumSet(); + //check for enums, retain order, and don't allow duplicates + for(var x:int = 0; x < values.length; ++x) + { + var item:Object = values[x]; + if(!(item is Enum)) + { + throw new ArgumentError("Cannot create EnumSet. Value " + item + " is not an Enum"); + } + else if(result.m_values.indexOf(item) == -1) + { + result.m_values.push(item); + } + } + return result; + } + + /** + * Create a new EnumSet from the enums provided as arguments to this method + * @param ...args + * @return + */ + static public function fromArgs(...args):EnumSet + { + return EnumSet.fromArray(args); + } + + /** + * Internal create method that doesn't check or filter values + * @private + */ + static internal function fromArrayInternal(array:Array):EnumSet + { + var result : EnumSet = new EnumSet(); + result.m_values = array; + return result; + } /** * Return array directly for internal use where we're not worried about mutation * @private */ internal function get values():Array { return m_values; } - - //-------------------------------------- - // PUBLIC METHODS - //-------------------------------------- - - /** - * Get a clone of the Enum values in this EnumSet as an Array - */ - public function getValues():Array - { - return m_values.slice(); - } - - // - // IEnum - // - - /** - * @inheritDoc - */ - public function intersects(matchValue:Object):Boolean - { - if(matchValue == null || m_values.length == 0) - { - return false; - } - else if(matchValue is Enum) - { - return m_values.indexOf(matchValue) != -1; - } - else if(matchValue is EnumSet || matchValue is Array || matchValue is Vector.<*>) - { - var vals : Object = matchValue is EnumSet ? EnumSet(matchValue).m_values : matchValue; - //quick check for no values - if(vals.length == 0) - { - return false; - } - for(var x : int = 0; x < m_values.length; ++x) - { - //if even a single value matches, these intersect - if(vals.indexOf(m_values[x]) != -1) - { - return true; - } - } - } - return false; - } - - /** - * @inheritDoc - */ - public function equals(matchValue:Object):Boolean - { - if(matchValue == null || m_values.length == 0) - { - return false; - } - else if(matchValue is Enum) - { - //in order for a single Enum to be equal to this set there must be only one item - return m_values.length == 1 && m_values[0] == matchValue; - } - else if(matchValue is EnumSet || matchValue is Array || matchValue is Vector.<*>) - { - var vals : Object = matchValue is EnumSet ? EnumSet(matchValue).m_values : matchValue; - if(vals.length == m_values.length) - { - for(var x : int = 0; x < m_values.length; ++x) - { - if(vals.indexOf(m_values[x]) == -1) - { - return false; - } - } - return true; - } - } - return false; - } - - public function toString():String - { - return "[EnumSet:" + m_values.toString() + "]"; - } + + //-------------------------------------- + // PUBLIC METHODS + //-------------------------------------- + + /** + * Get a clone of the Enum values in this EnumSet as an Array + */ + public function getValues():Array + { + return m_values.slice(); + } + + // + // IEnum + // + + /** + * @inheritDoc + */ + public function intersects(matchValue:Object):Boolean + { + if(matchValue == null || m_values.length == 0) + { + return false; + } + else if(matchValue is Enum) + { + return m_values.indexOf(matchValue) != -1; + } + else if(matchValue is EnumSet || matchValue is Array || matchValue is Vector.<*>) + { + var vals : Object = matchValue is EnumSet ? EnumSet(matchValue).m_values : matchValue; + //quick check for no values + if(vals.length == 0) + { + return false; + } + for(var x : int = 0; x < m_values.length; ++x) + { + //if even a single value matches, these intersect + if(vals.indexOf(m_values[x]) != -1) + { + return true; + } + } + } + return false; + } + + /** + * @inheritDoc + */ + public function equals(matchValue:Object):Boolean + { + if(matchValue == null || m_values.length == 0) + { + return false; + } + else if(matchValue is Enum) + { + //in order for a single Enum to be equal to this set there must be only one item + return m_values.length == 1 && m_values[0] == matchValue; + } + else if(matchValue is EnumSet || matchValue is Array || matchValue is Vector.<*>) + { + var vals : Object = matchValue is EnumSet ? EnumSet(matchValue).m_values : matchValue; + if(vals.length == m_values.length) + { + for(var x : int = 0; x < m_values.length; ++x) + { + if(vals.indexOf(m_values[x]) == -1) + { + return false; + } + } + return true; + } + } + return false; + } + + public function toString():String + { + return "[EnumSet:" + m_values.toString() + "]"; + } } -} \ No newline at end of file +} diff --git a/src/nexus/IDisposable.as b/src/nexus/IDisposable.as index fd62501..771deae 100644 --- a/src/nexus/IDisposable.as +++ b/src/nexus/IDisposable.as @@ -1,21 +1,21 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package nexus { - + /** * Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with * the garbage collector. The consumer of an object can call this method when the object is no longer needed. */ public interface IDisposable { - /** - * Performs tasks associated with freeing, releasing, or resetting unmanaged resources. - */ - function dispose():void; + /** + * Performs tasks associated with freeing, releasing, or resetting unmanaged resources. + */ + function dispose():void; } -} \ No newline at end of file +} diff --git a/src/nexus/IEnum.as b/src/nexus/IEnum.as index 441a668..d0a0339 100644 --- a/src/nexus/IEnum.as +++ b/src/nexus/IEnum.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -11,19 +11,19 @@ package nexus */ public interface IEnum { - /** - * Returns true if the passed value is an exact match to this value - * @param value An object of type Enum, EnumSet, an Array of Enums, or a Vector of Enums - * @return True if the values ae an exact match - */ - function equals(value:Object):Boolean; - - /** - * Returns true if there are any matches between this value and the provided argument - * @param value An object of type Enum, EnumSet, an Array of Enums, or a Vector of Enums - * @return True if any values match - */ - function intersects(value:Object):Boolean; + /** + * Returns true if the passed value is an exact match to this value + * @param value An object of type Enum, EnumSet, an Array of Enums, or a Vector of Enums + * @return True if the values ae an exact match + */ + function equals(value:Object):Boolean; + + /** + * Returns true if there are any matches between this value and the provided argument + * @param value An object of type Enum, EnumSet, an Array of Enums, or a Vector of Enums + * @return True if any values match + */ + function intersects(value:Object):Boolean; } -} \ No newline at end of file +} diff --git a/src/nexus/errors/ClassNotFoundError.as b/src/nexus/errors/ClassNotFoundError.as index 4ad2801..7a20512 100644 --- a/src/nexus/errors/ClassNotFoundError.as +++ b/src/nexus/errors/ClassNotFoundError.as @@ -13,41 +13,41 @@ import flash.utils.*; */ public class ClassNotFoundError extends Error { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_qualifiedClassName : String; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function ClassNotFoundError(qualifiedName : String) - { - super("Cannot find definition for " + qualifiedName + ". Be sure the class is present in the registered application domains and is public."); - - m_qualifiedClassName = qualifiedName; - this.name = "ClassNotFoundError"; - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - public function get qualifiedClassName():String { return m_qualifiedClassName; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_qualifiedClassName : String; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function ClassNotFoundError(qualifiedName : String) + { + super("Cannot find definition for " + qualifiedName + ". Be sure the class is present in the registered application domains and is public."); + + m_qualifiedClassName = qualifiedName; + this.name = "ClassNotFoundError"; + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + public function get qualifiedClassName():String { return m_qualifiedClassName; } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- } -} \ No newline at end of file +} diff --git a/src/nexus/errors/NotImplementedError.as b/src/nexus/errors/NotImplementedError.as index 0f060fe..322f04d 100644 --- a/src/nexus/errors/NotImplementedError.as +++ b/src/nexus/errors/NotImplementedError.as @@ -15,15 +15,15 @@ import flash.utils.*; */ public class NotImplementedError extends IllegalOperationError { - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function NotImplementedError(id:int=0) - { - super("Not Implemented", id); - } + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function NotImplementedError(id:int=0) + { + super("Not Implemented", id); + } } -} \ No newline at end of file +} diff --git a/src/nexus/math/IPRNG.as b/src/nexus/math/IPRNG.as index 30e7dfd..860fcc7 100644 --- a/src/nexus/math/IPRNG.as +++ b/src/nexus/math/IPRNG.as @@ -1,21 +1,21 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package nexus.math { - + /** * ... */ public interface IPRNG { - function get currentState():uint; - - function get period():uint; - - function next():uint; + function get currentState():uint; + + function get period():uint; + + function next():uint; } -} \ No newline at end of file +} diff --git a/src/nexus/math/ISeededPRNG.as b/src/nexus/math/ISeededPRNG.as index c8af2af..9f1ea53 100644 --- a/src/nexus/math/ISeededPRNG.as +++ b/src/nexus/math/ISeededPRNG.as @@ -1,18 +1,18 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package nexus.math { - + /** * ... */ public interface ISeededPRNG extends IPRNG { - function get seed():uint; - function set seed(value:uint):void; + function get seed():uint; + function set seed(value:uint):void; } -} \ No newline at end of file +} diff --git a/src/nexus/math/LehmerGenerator.as b/src/nexus/math/LehmerGenerator.as index b8ad168..0f945e7 100644 --- a/src/nexus/math/LehmerGenerator.as +++ b/src/nexus/math/LehmerGenerator.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -14,35 +14,35 @@ import flash.utils.*; */ public final class LehmerGenerator implements ISeededPRNG { - private var m_seed:uint; - private var m_currentState:uint; - private var m_numbersGenerated:int; - - public function LehmerGenerator(seed:uint=1) - { - this.seed = seed; - } - - public final function get seed():uint { return m_seed; } - public final function set seed(value:uint):void - { - m_seed = value; - m_currentState = m_seed; - m_numbersGenerated = 0; - } - - public final function get currentState():uint { return m_currentState; } - - [Inline] - public function get period():uint { return 2147483647 /*int.MAX_VALUE*/; } - - public final function get numbersGenerated():int { return m_numbersGenerated; } - - public function next():uint - { - ++m_numbersGenerated; - return m_currentState = ((m_currentState * 16807) % 2147483647); - //return m_state = ((m_state * 279470273) % 4294967291); - } + private var m_seed:uint; + private var m_currentState:uint; + private var m_numbersGenerated:int; + + public function LehmerGenerator(seed:uint=1) + { + this.seed = seed; + } + + public final function get seed():uint { return m_seed; } + public final function set seed(value:uint):void + { + m_seed = value; + m_currentState = m_seed; + m_numbersGenerated = 0; + } + + public final function get currentState():uint { return m_currentState; } + + [Inline] + public function get period():uint { return 2147483647 /*int.MAX_VALUE*/; } + + public final function get numbersGenerated():int { return m_numbersGenerated; } + + public function next():uint + { + ++m_numbersGenerated; + return m_currentState = ((m_currentState * 16807) % 2147483647); + //return m_state = ((m_state * 279470273) % 4294967291); + } +} } -} \ No newline at end of file diff --git a/src/nexus/math/NativeRandomGenerator.as b/src/nexus/math/NativeRandomGenerator.as index 33579c1..0ec3c34 100644 --- a/src/nexus/math/NativeRandomGenerator.as +++ b/src/nexus/math/NativeRandomGenerator.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -13,21 +13,21 @@ import flash.utils.*; */ public final class NativeRandomGenerator implements IPRNG { - private var m_currentState:uint; - - public function NativeRandomGenerator() - { - - } - - [Inline] - public function get period():uint { return 2147483647 /*int.MAX_VALUE*/; } - - public final function get currentState():uint { return m_currentState; } - - public function next():uint - { - return m_currentState = Math.random() * 2147483647; - } + private var m_currentState:uint; + + public function NativeRandomGenerator() + { + + } + + [Inline] + public function get period():uint { return 2147483647 /*int.MAX_VALUE*/; } + + public final function get currentState():uint { return m_currentState; } + + public function next():uint + { + return m_currentState = Math.random() * 2147483647; + } +} } -} \ No newline at end of file diff --git a/src/nexus/math/Random.as b/src/nexus/math/Random.as index 153f01b..a241d26 100644 --- a/src/nexus/math/Random.as +++ b/src/nexus/math/Random.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -14,144 +14,144 @@ import flash.utils.*; */ public class Random { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - private static const s_random:Random = new Random(new NativeRandomGenerator()); - - public static function get instance():Random - { - return s_random; - } - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_generator:IPRNG; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function Random(generator:IPRNG) - { - m_generator = generator; - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * Generates a random floating point in the range [min, max) which is [0, 1) if neither - * argument is given. - * - * If max is NaN, Infinity, or -Infinity, a number in the range [min, 1) is returned - * If min is NaN, Infinity, or -Infinity, a number in the range [0, max) is returned - * @param min The lowest value to return, inclusive - * @param max The highest value to return, exclusive - * @return A number in the range [min, max) - */ - public function float(min:Number = NaN, max:Number = NaN):Number - { - min = isNaN(min) || !isFinite(min) ? 0 : min; - max = isNaN(max) || !isFinite(max) ? 1 : max; - var p:Number = m_generator.next() / m_generator.period; - return (p * (max - min)) + min; - } - - /** - * Generates a random integer in the range [min, max) - * @param min The lowest value to return, inclusive - * @param max The highest value to return, exclusive - * @return An int in the range [min, max) - */ - public function integer(min:int = 0, max:int = int.MAX_VALUE):int - { - return m_generator.next() % (max - min) + min; - } - - /** - * Generates a random unsigned integer in the range [min, max) - * @param min The lowest value to return, inclusive - * @param max The highest value to return, exclusive - * @return A uint in the range [min, max) - */ - public function unsignedInteger(min:uint = 0, max:uint = uint.MAX_VALUE):uint - { - return m_generator.next() % (max - min) + min; - } - - /** - * Returns a random true/false value, with a 50% chance of either - */ - public function boolean():Boolean - { - return(m_generator.next() / m_generator.period) < 0.5; - } - - /** - * Given a floating-point value, return either the value's floor or its ceiling - * chosen randomly according to whether the value is closer to the floor or - * the ceiling. - * @example randomRound(4.3) should return 4 70% of the time - * and 5 30% of the time. - */ - public function weightedRound(value:Number):int - { - var floor:int = Math.floor(value); - return(m_generator.next() / m_generator.period) > (value - floor) ? floor : floor + 1; - } - - /** - * Returns one of the items passed in at random. - * @param items A vararg list of objects to choose from. If a single argument is passed, it - * is assumed to be a Vector or Array (or otherwise have a length property and - * be able to be accessed with the index operators). - */ - public function choice(... items):Object - { - var choice:int; - if(items.length == 1) - { - choice = integer(0, items[0].length); - return items[0][choice]; - } - else - { - choice = integer(0, items.length); - return items[choice]; - } - } - - /** - * Destructively shuffles the container using the Fisher-Yates algorithm. - */ - public function shuffle(container:Object):void - { - for(var x:int = container.length - 1; x > 0; x--) - { - var j:int = integer(0, x + 1); - var tmp:* = container[x]; - container[x] = container[j]; - container[j] = tmp; - } - } - - public function toString(verbose:Boolean = false):String - { - return "[Random" + m_generator + "]"; - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + private static const s_random:Random = new Random(new NativeRandomGenerator()); + + public static function get instance():Random + { + return s_random; + } + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_generator:IPRNG; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function Random(generator:IPRNG) + { + m_generator = generator; + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * Generates a random floating point in the range [min, max) which is [0, 1) if neither + * argument is given. + * + * If max is NaN, Infinity, or -Infinity, a number in the range [min, 1) is returned + * If min is NaN, Infinity, or -Infinity, a number in the range [0, max) is returned + * @param min The lowest value to return, inclusive + * @param max The highest value to return, exclusive + * @return A number in the range [min, max) + */ + public function float(min:Number = NaN, max:Number = NaN):Number + { + min = isNaN(min) || !isFinite(min) ? 0 : min; + max = isNaN(max) || !isFinite(max) ? 1 : max; + var p:Number = m_generator.next() / m_generator.period; + return (p * (max - min)) + min; + } + + /** + * Generates a random integer in the range [min, max) + * @param min The lowest value to return, inclusive + * @param max The highest value to return, exclusive + * @return An int in the range [min, max) + */ + public function integer(min:int = 0, max:int = int.MAX_VALUE):int + { + return m_generator.next() % (max - min) + min; + } + + /** + * Generates a random unsigned integer in the range [min, max) + * @param min The lowest value to return, inclusive + * @param max The highest value to return, exclusive + * @return A uint in the range [min, max) + */ + public function unsignedInteger(min:uint = 0, max:uint = uint.MAX_VALUE):uint + { + return m_generator.next() % (max - min) + min; + } + + /** + * Returns a random true/false value, with a 50% chance of either + */ + public function boolean():Boolean + { + return(m_generator.next() / m_generator.period) < 0.5; + } + + /** + * Given a floating-point value, return either the value's floor or its ceiling + * chosen randomly according to whether the value is closer to the floor or + * the ceiling. + * @example randomRound(4.3) should return 4 70% of the time + * and 5 30% of the time. + */ + public function weightedRound(value:Number):int + { + var floor:int = Math.floor(value); + return(m_generator.next() / m_generator.period) > (value - floor) ? floor : floor + 1; + } + + /** + * Returns one of the items passed in at random. + * @param items A vararg list of objects to choose from. If a single argument is passed, it + * is assumed to be a Vector or Array (or otherwise have a length property and + * be able to be accessed with the index operators). + */ + public function choice(... items):Object + { + var choice:int; + if(items.length == 1) + { + choice = integer(0, items[0].length); + return items[0][choice]; + } + else + { + choice = integer(0, items.length); + return items[choice]; + } + } + + /** + * Destructively shuffles the container using the Fisher-Yates algorithm. + */ + public function shuffle(container:Object):void + { + for(var x:int = container.length - 1; x > 0; x--) + { + var j:int = integer(0, x + 1); + var tmp:* = container[x]; + container[x] = container[j]; + container[j] = tmp; + } + } + + public function toString(verbose:Boolean = false):String + { + return "[Random" + m_generator + "]"; + } - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- } -} \ No newline at end of file +} diff --git a/src/nexus/math/TinyMersenneTwisterGenerator.as b/src/nexus/math/TinyMersenneTwisterGenerator.as index 6d03c1a..617cda8 100644 --- a/src/nexus/math/TinyMersenneTwisterGenerator.as +++ b/src/nexus/math/TinyMersenneTwisterGenerator.as @@ -30,100 +30,100 @@ import flash.utils.*; public class TinyMersenneTwisterGenerator implements ISeededPRNG { // initialization constants (in the MT reference implementation - // they're specified by the user during initialization, but they don't change) - private static const MAT1:uint = 0x70707070; - private static const MAT2:uint = 0x07070707; - private static const TMAT:uint = 0x55555555; - - protected static const MIN_LOOP:int = 8; - protected static const PRE_LOOP:int = 8; + // they're specified by the user during initialization, but they don't change) + private static const MAT1:uint = 0x70707070; + private static const MAT2:uint = 0x07070707; + private static const TMAT:uint = 0x55555555; + + protected static const MIN_LOOP:int = 8; + protected static const PRE_LOOP:int = 8; - private var m_seed:uint; - private var m_currentState:uint; - private var m_numbersGenerated:int; - - public function TinyMersenneTwisterGenerator(seed:uint = 1) - { - this.seed = seed; - } - - public final function get seed():uint { return m_seed; } - public final function set seed(value:uint):void - { - m_seed = value; - m_currentState = m_seed; - m_numbersGenerated = 0; - + private var m_seed:uint; + private var m_currentState:uint; + private var m_numbersGenerated:int; + + public function TinyMersenneTwisterGenerator(seed:uint = 1) + { + this.seed = seed; + } + + public final function get seed():uint { return m_seed; } + public final function set seed(value:uint):void + { + m_seed = value; + m_currentState = m_seed; + m_numbersGenerated = 0; + stateVars[0] = m_seed; - stateVars[1] = MAT1; - stateVars[2] = MAT2; - stateVars[3] = TMAT; - - for(var i:int = 1; i < MIN_LOOP; i++) - { - stateVars[i & 3] ^= i + 1812433253 * (stateVars[(i - 1) & 3] ^ (stateVars[(i - 1) & 3] >>> 30)); - } - - for(var j:int = 0; j < PRE_LOOP; j++) - { - nextState(); - } - } - - public final function get currentState():uint { return m_currentState; } - - [Inline] - public function get period():uint { return 4294967295; } - - public final function get numbersGenerated():int - { - return m_numbersGenerated; - } - - public function next():uint - { - nextState(); - return temper(); - } - - // state variables - private const stateVars:Vector. = new Vector.(4, true); - - /** - * Advances internal state - */ - [Inline] - private final function nextState():void - { - var x:uint; - var y:uint; - - y = stateVars[3]; - x = (stateVars[0] & 0x7fffffff) ^ stateVars[1] ^ stateVars[2]; - x ^= (x << 1); - y ^= (y >>> 1) ^ x; - stateVars[0] = stateVars[1]; - stateVars[1] = stateVars[2]; - stateVars[2] = x ^ (y << 10); - stateVars[3] = y; - stateVars[1] ^= -(y & 1) & MAT1; - stateVars[2] ^= -(y & 1) & MAT2; - - m_numbersGenerated++; - } - - /** - * Outputs an unsigned int from the current internal stats - */ - [Inline] - private final function temper():uint - { - var t0:uint = stateVars[3]; - var t1:uint = stateVars[0] ^ (stateVars[2] >>> 8); - t0 ^= t1; - t0 ^= -(t1 & 1) & TMAT; - return t0; - } + stateVars[1] = MAT1; + stateVars[2] = MAT2; + stateVars[3] = TMAT; + + for(var i:int = 1; i < MIN_LOOP; i++) + { + stateVars[i & 3] ^= i + 1812433253 * (stateVars[(i - 1) & 3] ^ (stateVars[(i - 1) & 3] >>> 30)); + } + + for(var j:int = 0; j < PRE_LOOP; j++) + { + nextState(); + } + } + + public final function get currentState():uint { return m_currentState; } + + [Inline] + public function get period():uint { return 4294967295; } + + public final function get numbersGenerated():int + { + return m_numbersGenerated; + } + + public function next():uint + { + nextState(); + return temper(); + } + + // state variables + private const stateVars:Vector. = new Vector.(4, true); + + /** + * Advances internal state + */ + [Inline] + private final function nextState():void + { + var x:uint; + var y:uint; + + y = stateVars[3]; + x = (stateVars[0] & 0x7fffffff) ^ stateVars[1] ^ stateVars[2]; + x ^= (x << 1); + y ^= (y >>> 1) ^ x; + stateVars[0] = stateVars[1]; + stateVars[1] = stateVars[2]; + stateVars[2] = x ^ (y << 10); + stateVars[3] = y; + stateVars[1] ^= -(y & 1) & MAT1; + stateVars[2] ^= -(y & 1) & MAT2; + + m_numbersGenerated++; + } + + /** + * Outputs an unsigned int from the current internal stats + */ + [Inline] + private final function temper():uint + { + var t0:uint = stateVars[3]; + var t1:uint = stateVars[0] ^ (stateVars[2] >>> 8); + t0 ^= t1; + t0 ^= -(t1 & 1) & TMAT; + return t0; + } } -} \ No newline at end of file +} diff --git a/src/nexus/net/HttpRequest.as b/src/nexus/net/HttpRequest.as index 4d03924..897ec5c 100644 --- a/src/nexus/net/HttpRequest.as +++ b/src/nexus/net/HttpRequest.as @@ -16,251 +16,251 @@ import flash.utils.*; */ public class HttpRequest { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - /** - * The underlying URLStream for this request - * @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/URLStream.html - */ - private var m_stream:URLStream; - private var m_url:URLRequest; - - // - // transient data per send - // - - private var m_response : HttpResponse; - private var m_onCompleteCallback:Function; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function HttpRequest() - { - m_url = new URLRequest(); - m_url.method = URLRequestMethod.GET; - - m_stream = new URLStream(); - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - public function get url():String { return m_url.url; } - public function set url(value:String):void - { - m_url.url = value; - } - - public function get method():String { return m_url.method; } - public function set method(value:String):void - { - m_url.method = value; - } - - public function get body():Object { return m_url.data; } - public function set body(value:Object):void - { - m_url.data = value; - } - - public function get headers():Array { return m_url.requestHeaders; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - public function send(callback:Function/*HttpRequest*/):void - { - if(m_stream.connected) - { - throw new IllegalOperationError("Cannot send. HttpRequest already in progress."); - } - - m_onCompleteCallback = callback; - m_response = new HttpResponse(); - //TODO: Provide some mechanism to get progress of the response; then set the response body to the stream while it loads - //m_response.setBody(m_stream); - - // - // Add event listeners on each send(), so we can fully tear down when complete and avoid possible memory leaks - // - - //Dispatched when a load operation starts. - m_stream.addEventListener(Event.OPEN, stream_open); - - //Dispatched when data has loaded successfully. - m_stream.addEventListener(Event.COMPLETE, stream_complete); - - //Dispatched when data is received as the download operation progresses. - m_stream.addEventListener(ProgressEvent.PROGRESS, stream_progress); - - //Dispatched if a call to URLStream.load() attempts to access data over HTTP, and Flash Player - //or Adobe AIR is able to detect and return the status code for the request. - m_stream.addEventListener(HTTPStatusEvent.HTTP_STATUS, stream_status); - - //Dispatched if a call to the URLStream.load() method attempts to access data over HTTP and Adobe AIR - //is able to detect and return the status code for the request. - m_stream.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, stream_responseStatus); - - //Dispatched when an input/output error occurs that causes a load operation to fail. - m_stream.addEventListener(IOErrorEvent.IO_ERROR, stream_error); - - //Dispatched if a call to URLStream.load() attempts to load data from a server outside the security sandbox. - m_stream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, stream_error); - - try - { - m_stream.load(m_url); - } - //1) Local untrusted SWF files may not communicate with the Internet. This may be worked around - //by reclassifying this SWF file as local-with-networking or trusted. - //2) You are trying to connect to a commonly reserved port. For a complete list of blocked ports, - //see "Restricting Networking APIs" in the ActionScript 3.0 Developer's Guide. - catch(securityError:SecurityError) - { - complete(securityError.getStackTrace() || securityError.toString()); - } - //1) Flash Player or Adobe AIR cannot convert the URLRequest.data parameter from UTF8 to MBCS. This - //error is applicable if the URLRequest object passed to load() is set to perform a GET operation and - //if System.useCodePage is set to true. - //2) Flash Player or Adobe AIR cannot allocate memory for the POST data. This error is applicable if - //the URLRequest object passed to load is set to perform a POST operation. - catch(memoryError:MemoryError) - { - complete(memoryError.getStackTrace() || memoryError.toString()); - } - //URLRequest.requestHeader objects may not contain certain prohibited HTTP request headers. - //For more information, see the URLRequestHeader class description. - catch(argumentError:ArgumentError) - { - complete(argumentError.getStackTrace() || argumentError.toString()); - } - } - - public function cancel():void - { - if(m_stream.connected) - { - m_stream.close(); - } - } - - public function setBasicAuthentication(user:String, password:String):void - { - /* - if(m_authHeader == null) - { - m_authHeader = new URLRequestHeader("Authorization"); - m_request.requestHeaders.push(m_authHeader); - } - var auth : ByteArray = new ByteArray(); - auth.writeUTFBytes(user + ":" + password); - m_authHeader.value = "Basic " + Base64.encode(auth, false); - //*/ - } - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- - - private function stream_open(e:Event):void - { - trace(e); - } - - private function stream_status(e:HTTPStatusEvent):void - { - //only set if a valid status is returned & one is not already set (stream_responseStatus supercedes this method) - if(e.status != 0 && m_response.status == -1) - { - m_response.setStatus(e.status); - } - } - - private function stream_responseStatus(e:HTTPStatusEvent):void - { - m_response.setStatus(e.status); - m_response.setUrl(e.responseURL); - m_response.addHeaders(e.responseHeaders); - } - - private function stream_progress(e:ProgressEvent):void - { - m_response.setBytesLoaded(e.bytesLoaded); - m_response.setBytesTotal(e.bytesTotal); - } - - private function stream_complete(e:Event):void - { - complete(m_stream); - } - - private function stream_error(e:ErrorEvent):void - { - complete(e.text); - } - - private function complete(responseBody:Object):void - { - // - // set response body - // - - //set response body to a new ByteArray to break the reference to the stream - var bytes : ByteArray = new ByteArray(); - if(responseBody == m_stream || responseBody is IDataInput) - { - IDataInput(responseBody).readBytes(bytes); - } - else if(responseBody is String) - { - bytes.writeUTFBytes(String(responseBody)); - } - else - { - throw new ArgumentError("Invalid response body type"); - } - - //TODO: set loaded & total here? What about the case of errors. I think the idea is to make sure any visuals or logic - //that are waiting for bytesLoaded to equal bytesTotal to complete properly, but what about the error case? Don't we - //want to know that we're complete but the bytes don't match? - m_response.setBytesLoaded(bytes.length); - m_response.setBytesTotal(bytes.length); - - m_response.setBody(bytes); - - // - // clean up stream - // - - m_stream.removeEventListener(Event.OPEN, stream_open); - m_stream.removeEventListener(Event.COMPLETE, stream_complete); - m_stream.removeEventListener(ProgressEvent.PROGRESS, stream_progress); - m_stream.removeEventListener(HTTPStatusEvent.HTTP_STATUS, stream_status); - m_stream.removeEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, stream_responseStatus); - m_stream.removeEventListener(IOErrorEvent.IO_ERROR, stream_error); - m_stream.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, stream_error); - - //close stream after listeners have been removed so none are triggered - this.cancel(); - - // - // invoke callback - // - - m_onCompleteCallback(m_response); - m_onCompleteCallback = null; - m_response = null; - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + /** + * The underlying URLStream for this request + * @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/URLStream.html + */ + private var m_stream:URLStream; + private var m_url:URLRequest; + + // + // transient data per send + // + + private var m_response : HttpResponse; + private var m_onCompleteCallback:Function; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function HttpRequest() + { + m_url = new URLRequest(); + m_url.method = URLRequestMethod.GET; + + m_stream = new URLStream(); + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + public function get url():String { return m_url.url; } + public function set url(value:String):void + { + m_url.url = value; + } + + public function get method():String { return m_url.method; } + public function set method(value:String):void + { + m_url.method = value; + } + + public function get body():Object { return m_url.data; } + public function set body(value:Object):void + { + m_url.data = value; + } + + public function get headers():Array { return m_url.requestHeaders; } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + public function send(callback:Function/*HttpRequest*/):void + { + if(m_stream.connected) + { + throw new IllegalOperationError("Cannot send. HttpRequest already in progress."); + } + + m_onCompleteCallback = callback; + m_response = new HttpResponse(); + //TODO: Provide some mechanism to get progress of the response; then set the response body to the stream while it loads + //m_response.setBody(m_stream); + + // + // Add event listeners on each send(), so we can fully tear down when complete and avoid possible memory leaks + // + + //Dispatched when a load operation starts. + m_stream.addEventListener(Event.OPEN, stream_open); + + //Dispatched when data has loaded successfully. + m_stream.addEventListener(Event.COMPLETE, stream_complete); + + //Dispatched when data is received as the download operation progresses. + m_stream.addEventListener(ProgressEvent.PROGRESS, stream_progress); + + //Dispatched if a call to URLStream.load() attempts to access data over HTTP, and Flash Player + //or Adobe AIR is able to detect and return the status code for the request. + m_stream.addEventListener(HTTPStatusEvent.HTTP_STATUS, stream_status); + + //Dispatched if a call to the URLStream.load() method attempts to access data over HTTP and Adobe AIR + //is able to detect and return the status code for the request. + m_stream.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, stream_responseStatus); + + //Dispatched when an input/output error occurs that causes a load operation to fail. + m_stream.addEventListener(IOErrorEvent.IO_ERROR, stream_error); + + //Dispatched if a call to URLStream.load() attempts to load data from a server outside the security sandbox. + m_stream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, stream_error); + + try + { + m_stream.load(m_url); + } + //1) Local untrusted SWF files may not communicate with the Internet. This may be worked around + //by reclassifying this SWF file as local-with-networking or trusted. + //2) You are trying to connect to a commonly reserved port. For a complete list of blocked ports, + //see "Restricting Networking APIs" in the ActionScript 3.0 Developer's Guide. + catch(securityError:SecurityError) + { + complete(securityError.getStackTrace() || securityError.toString()); + } + //1) Flash Player or Adobe AIR cannot convert the URLRequest.data parameter from UTF8 to MBCS. This + //error is applicable if the URLRequest object passed to load() is set to perform a GET operation and + //if System.useCodePage is set to true. + //2) Flash Player or Adobe AIR cannot allocate memory for the POST data. This error is applicable if + //the URLRequest object passed to load is set to perform a POST operation. + catch(memoryError:MemoryError) + { + complete(memoryError.getStackTrace() || memoryError.toString()); + } + //URLRequest.requestHeader objects may not contain certain prohibited HTTP request headers. + //For more information, see the URLRequestHeader class description. + catch(argumentError:ArgumentError) + { + complete(argumentError.getStackTrace() || argumentError.toString()); + } + } + + public function cancel():void + { + if(m_stream.connected) + { + m_stream.close(); + } + } + + public function setBasicAuthentication(user:String, password:String):void + { + /* + if(m_authHeader == null) + { + m_authHeader = new URLRequestHeader("Authorization"); + m_request.requestHeaders.push(m_authHeader); + } + var auth : ByteArray = new ByteArray(); + auth.writeUTFBytes(user + ":" + password); + m_authHeader.value = "Basic " + Base64.encode(auth, false); + //*/ + } + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- + + private function stream_open(e:Event):void + { + trace(e); + } + + private function stream_status(e:HTTPStatusEvent):void + { + //only set if a valid status is returned & one is not already set (stream_responseStatus supercedes this method) + if(e.status != 0 && m_response.status == -1) + { + m_response.setStatus(e.status); + } + } + + private function stream_responseStatus(e:HTTPStatusEvent):void + { + m_response.setStatus(e.status); + m_response.setUrl(e.responseURL); + m_response.addHeaders(e.responseHeaders); + } + + private function stream_progress(e:ProgressEvent):void + { + m_response.setBytesLoaded(e.bytesLoaded); + m_response.setBytesTotal(e.bytesTotal); + } + + private function stream_complete(e:Event):void + { + complete(m_stream); + } + + private function stream_error(e:ErrorEvent):void + { + complete(e.text); + } + + private function complete(responseBody:Object):void + { + // + // set response body + // + + //set response body to a new ByteArray to break the reference to the stream + var bytes : ByteArray = new ByteArray(); + if(responseBody == m_stream || responseBody is IDataInput) + { + IDataInput(responseBody).readBytes(bytes); + } + else if(responseBody is String) + { + bytes.writeUTFBytes(String(responseBody)); + } + else + { + throw new ArgumentError("Invalid response body type"); + } + + //TODO: set loaded & total here? What about the case of errors. I think the idea is to make sure any visuals or logic + //that are waiting for bytesLoaded to equal bytesTotal to complete properly, but what about the error case? Don't we + //want to know that we're complete but the bytes don't match? + m_response.setBytesLoaded(bytes.length); + m_response.setBytesTotal(bytes.length); + + m_response.setBody(bytes); + + // + // clean up stream + // + + m_stream.removeEventListener(Event.OPEN, stream_open); + m_stream.removeEventListener(Event.COMPLETE, stream_complete); + m_stream.removeEventListener(ProgressEvent.PROGRESS, stream_progress); + m_stream.removeEventListener(HTTPStatusEvent.HTTP_STATUS, stream_status); + m_stream.removeEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, stream_responseStatus); + m_stream.removeEventListener(IOErrorEvent.IO_ERROR, stream_error); + m_stream.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, stream_error); + + //close stream after listeners have been removed so none are triggered + this.cancel(); + + // + // invoke callback + // + + m_onCompleteCallback(m_response); + m_onCompleteCallback = null; + m_response = null; + } } -} \ No newline at end of file +} diff --git a/src/nexus/net/HttpResponse.as b/src/nexus/net/HttpResponse.as index 3ad20e2..a08c55e 100644 --- a/src/nexus/net/HttpResponse.as +++ b/src/nexus/net/HttpResponse.as @@ -15,83 +15,83 @@ import flash.utils.*; */ public class HttpResponse { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_url : String; - private var m_status : int; - private var m_bytesLoaded : int; - private var m_bytesTotal : int; - private var m_headers : Vector.; - private var m_body : IDataInput; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function HttpResponse() - { - m_headers = new Vector.(); - m_status = -1; - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - public function get headers():Vector. { return m_headers; } - - public function get status():int { return m_status; } - internal function setStatus(value:int):void - { - m_status = value; - } - - public function get url():String { return m_url; } - internal function setUrl(value:String):void - { - m_url = value; - } - - public function get body():IDataInput { return m_body; } - internal function setBody(value:IDataInput):void - { - m_body = value; - } - - public function get bytesLoaded():int { return m_bytesLoaded; } - internal function setBytesLoaded(value:int):void - { - m_bytesLoaded = value; - } - - public function get bytesTotal():int { return m_bytesTotal; } - internal function setBytesTotal(value:int):void - { - m_bytesTotal = value; - } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - internal function addHeaders(array:Array):void - { - for each(var header : URLRequestHeader in array) - { - m_headers.push(header); - } - } - - public function toString(verbose:Boolean=false):String - { - return "[HttpResponse:" + m_status + "]"; - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_url : String; + private var m_status : int; + private var m_bytesLoaded : int; + private var m_bytesTotal : int; + private var m_headers : Vector.; + private var m_body : IDataInput; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function HttpResponse() + { + m_headers = new Vector.(); + m_status = -1; + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + public function get headers():Vector. { return m_headers; } + + public function get status():int { return m_status; } + internal function setStatus(value:int):void + { + m_status = value; + } + + public function get url():String { return m_url; } + internal function setUrl(value:String):void + { + m_url = value; + } + + public function get body():IDataInput { return m_body; } + internal function setBody(value:IDataInput):void + { + m_body = value; + } + + public function get bytesLoaded():int { return m_bytesLoaded; } + internal function setBytesLoaded(value:int):void + { + m_bytesLoaded = value; + } + + public function get bytesTotal():int { return m_bytesTotal; } + internal function setBytesTotal(value:int):void + { + m_bytesTotal = value; + } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + internal function addHeaders(array:Array):void + { + for each(var header : URLRequestHeader in array) + { + m_headers.push(header); + } + } + + public function toString(verbose:Boolean=false):String + { + return "[HttpResponse:" + m_status + "]"; + } } -} \ No newline at end of file +} diff --git a/src/nexus/nexuslib_internal.as b/src/nexus/nexuslib_internal.as index 71a8db7..676361f 100644 --- a/src/nexus/nexuslib_internal.as +++ b/src/nexus/nexuslib_internal.as @@ -1,9 +1,9 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package nexus { - public namespace nexuslib_internal = "nexus.nexuslib_internal"; -} \ No newline at end of file + public namespace nexuslib_internal = "nexus.nexuslib_internal"; +} diff --git a/src/nexus/security/crypto/HMAC.as b/src/nexus/security/crypto/HMAC.as index 2a681d0..c08828b 100644 --- a/src/nexus/security/crypto/HMAC.as +++ b/src/nexus/security/crypto/HMAC.as @@ -11,120 +11,120 @@ import nexus.utils.ByteUtils; /** * Implementation of hash-based message authentication code - * @see http://tools.ietf.org/html/rfc2104 + * @see http://tools.ietf.org/html/rfc2104 */ public class HMAC { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - private static const BLOCKSIZE_BYTES:int = 64; - - private static const HMAC_SHA1 : HMAC = new HMAC(new SHA1HashFunction()); - private static const HMAC_SHA256 : HMAC = new HMAC(new SHA256HashFunction()); - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_hashFunction : IHashFunction; - private var m_secretKey : ByteArray; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function HMAC(hashFunction:IHashFunction) - { - m_hashFunction = hashFunction; - } - - //-------------------------------------- - // GETTERS/SETTERS - //-------------------------------------- - - public function get secretKey():ByteArray { return m_secretKey; } - public function set secretKey(value:ByteArray):void - { - m_secretKey = value; - } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * Generate a message authentication code for the given message. If a key is provided, it will be used. If the - * key is null, the value set in secretKey will be used. If both are null, an exception is thrown. - * @param message The message from which to generate the authentication code. - * @param key The secret key to use. Optional if secretKey has been set. - * @throws ArgumentError If key is null and secretKey has not been set - * @return A ByteArray whose length is determined by the hash algorithm used. - */ - public function generate(message:ByteArray, secretKey:ByteArray=null):ByteArray - { - secretKey = secretKey || m_secretKey; - if(secretKey == null) - { - throw new ArgumentError("Cannot compute HMAC without secret key."); - } - - //write the key to a different ByteArray so we don't mutate it - var value:ByteArray = new ByteArray(); - if(secretKey.length > BLOCKSIZE_BYTES) - { - value.writeBytes(m_hashFunction.hash(secretKey)); - } - else - { - value.writeBytes(secretKey); - } - - while(value.length < BLOCKSIZE_BYTES) - { - value.writeByte(0); - } - - var innerPad:ByteArray = new ByteArray(); - var outerPad:ByteArray = new ByteArray(); - for(var x:int = 0; x < BLOCKSIZE_BYTES; ++x) - { - innerPad.writeByte(value[x] ^ 0x36); - outerPad.writeByte(value[x] ^ 0x5c); - } - - if(message != null) - { - innerPad.writeBytes(message); - } - outerPad.writeBytes(m_hashFunction.hash(innerPad)); - - value.clear(); - value = null; - innerPad.clear(); - innerPad = null; - - return m_hashFunction.hash(outerPad); - } - - //-------------------------------------- - // PRIVATE INSTANCE METHODS - //-------------------------------------- - - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - static public function sha1(message:ByteArray, key:ByteArray):ByteArray - { - return HMAC_SHA1.generate(message, key); - } - - static public function sha256(message:ByteArray, key:ByteArray):ByteArray - { - return HMAC_SHA256.generate(message, key); - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + private static const BLOCKSIZE_BYTES:int = 64; + + private static const HMAC_SHA1 : HMAC = new HMAC(new SHA1HashFunction()); + private static const HMAC_SHA256 : HMAC = new HMAC(new SHA256HashFunction()); + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_hashFunction : IHashFunction; + private var m_secretKey : ByteArray; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function HMAC(hashFunction:IHashFunction) + { + m_hashFunction = hashFunction; + } + + //-------------------------------------- + // GETTERS/SETTERS + //-------------------------------------- + + public function get secretKey():ByteArray { return m_secretKey; } + public function set secretKey(value:ByteArray):void + { + m_secretKey = value; + } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * Generate a message authentication code for the given message. If a key is provided, it will be used. If the + * key is null, the value set in secretKey will be used. If both are null, an exception is thrown. + * @param message The message from which to generate the authentication code. + * @param key The secret key to use. Optional if secretKey has been set. + * @throws ArgumentError If key is null and secretKey has not been set + * @return A ByteArray whose length is determined by the hash algorithm used. + */ + public function generate(message:ByteArray, secretKey:ByteArray=null):ByteArray + { + secretKey = secretKey || m_secretKey; + if(secretKey == null) + { + throw new ArgumentError("Cannot compute HMAC without secret key."); + } + + //write the key to a different ByteArray so we don't mutate it + var value:ByteArray = new ByteArray(); + if(secretKey.length > BLOCKSIZE_BYTES) + { + value.writeBytes(m_hashFunction.hash(secretKey)); + } + else + { + value.writeBytes(secretKey); + } + + while(value.length < BLOCKSIZE_BYTES) + { + value.writeByte(0); + } + + var innerPad:ByteArray = new ByteArray(); + var outerPad:ByteArray = new ByteArray(); + for(var x:int = 0; x < BLOCKSIZE_BYTES; ++x) + { + innerPad.writeByte(value[x] ^ 0x36); + outerPad.writeByte(value[x] ^ 0x5c); + } + + if(message != null) + { + innerPad.writeBytes(message); + } + outerPad.writeBytes(m_hashFunction.hash(innerPad)); + + value.clear(); + value = null; + innerPad.clear(); + innerPad = null; + + return m_hashFunction.hash(outerPad); + } + + //-------------------------------------- + // PRIVATE INSTANCE METHODS + //-------------------------------------- + + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + static public function sha1(message:ByteArray, key:ByteArray):ByteArray + { + return HMAC_SHA1.generate(message, key); + } + + static public function sha256(message:ByteArray, key:ByteArray):ByteArray + { + return HMAC_SHA256.generate(message, key); + } } -} \ No newline at end of file +} diff --git a/src/nexus/security/crypto/IHashFunction.as b/src/nexus/security/crypto/IHashFunction.as index 4108863..7caa710 100644 --- a/src/nexus/security/crypto/IHashFunction.as +++ b/src/nexus/security/crypto/IHashFunction.as @@ -12,12 +12,12 @@ import flash.utils.ByteArray; */ public interface IHashFunction { - /** - * Hash the provided bytes and returned the hashed value - * @param bytes The bytes to hash - * @return The hashed bytes - */ - function hash(bytes:ByteArray):ByteArray; + /** + * Hash the provided bytes and returned the hashed value + * @param bytes The bytes to hash + * @return The hashed bytes + */ + function hash(bytes:ByteArray):ByteArray; } -} \ No newline at end of file +} diff --git a/src/nexus/security/crypto/SHA1HashFunction.as b/src/nexus/security/crypto/SHA1HashFunction.as index 662fb41..75b0807 100644 --- a/src/nexus/security/crypto/SHA1HashFunction.as +++ b/src/nexus/security/crypto/SHA1HashFunction.as @@ -17,25 +17,25 @@ import nexus.utils.ByteUtils; */ public class SHA1HashFunction implements IHashFunction { - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * Hash the provided bytes and returned the hashed value - * @param bytes The bytes to hash - * @return The hashed bytes - */ - public function hash(bytes:ByteArray):ByteArray - { - return ByteUtils.hexToBytes(SHA1.hashBytes(bytes)); - } - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- - - + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * Hash the provided bytes and returned the hashed value + * @param bytes The bytes to hash + * @return The hashed bytes + */ + public function hash(bytes:ByteArray):ByteArray + { + return ByteUtils.hexToBytes(SHA1.hashBytes(bytes)); + } + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- + + } -} \ No newline at end of file +} diff --git a/src/nexus/security/crypto/SHA256HashFunction.as b/src/nexus/security/crypto/SHA256HashFunction.as index 04903d0..c6ac685 100644 --- a/src/nexus/security/crypto/SHA256HashFunction.as +++ b/src/nexus/security/crypto/SHA256HashFunction.as @@ -17,25 +17,25 @@ import nexus.utils.ByteUtils; */ public class SHA256HashFunction implements IHashFunction { - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * Hash the provided bytes and returned the hashed value - * @param bytes The bytes to hash - * @return The hashed bytes - */ - public function hash(bytes:ByteArray):ByteArray - { - //would be really nice if the blooddy lib just returned a damn byte array - return ByteUtils.hexToBytes(SHA256.hashBytes(bytes)); - } - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- - + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * Hash the provided bytes and returned the hashed value + * @param bytes The bytes to hash + * @return The hashed bytes + */ + public function hash(bytes:ByteArray):ByteArray + { + //would be really nice if the blooddy lib just returned a damn byte array + return ByteUtils.hexToBytes(SHA256.hashBytes(bytes)); + } + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- + } -} \ No newline at end of file +} diff --git a/src/nexus/utils/ByteUtils.as b/src/nexus/utils/ByteUtils.as index 46e0c64..3db036e 100644 --- a/src/nexus/utils/ByteUtils.as +++ b/src/nexus/utils/ByteUtils.as @@ -13,53 +13,53 @@ import flash.utils.*; */ public class ByteUtils { - /** - * Generates a ByteArray from a hex-formatted String. Note that the string cannot contain any delimeters such as : or - - * @param hexString A String composed of only the characters [a-fA-F0-9] - * @return A new ByteArray - */ - static public function hexToBytes(hexString:String):ByteArray - { - if(hexString.length % 2 == 1) - { - hexString = "0" + hexString; - } - var result:ByteArray = new ByteArray(); - for(var x:int = 0; x < hexString.length; x += 2) - { - result.writeByte(parseInt(hexString.substr(x, 2), 16)); - } - return result; - } - - /** - * Converts a ByteArray into a hex-formatted string representation - * @param stream The ByteArray to parse - * @return A lowercase hex-formatted string - */ - static public function bytesToHex(stream:ByteArray):String - { - stream.position = 0; - var sha1:String = ""; - while(stream.bytesAvailable) - { - var val:uint = stream.readUnsignedByte(); - sha1 += (val < 16 ? "0" : "") + val.toString(16); - } - return sha1; - } - - /** - * Write the provided string into a new ByteArray - * @param string - * @return A new ByteArray - */ - static public function createByteArrayFromString(string:String):ByteArray - { - var result:ByteArray = new ByteArray(); - result.writeUTFBytes(string); - return result; - } + /** + * Generates a ByteArray from a hex-formatted String. Note that the string cannot contain any delimeters such as : or - + * @param hexString A String composed of only the characters [a-fA-F0-9] + * @return A new ByteArray + */ + static public function hexToBytes(hexString:String):ByteArray + { + if(hexString.length % 2 == 1) + { + hexString = "0" + hexString; + } + var result:ByteArray = new ByteArray(); + for(var x:int = 0; x < hexString.length; x += 2) + { + result.writeByte(parseInt(hexString.substr(x, 2), 16)); + } + return result; + } + + /** + * Converts a ByteArray into a hex-formatted string representation + * @param stream The ByteArray to parse + * @return A lowercase hex-formatted string + */ + static public function bytesToHex(stream:ByteArray):String + { + stream.position = 0; + var sha1:String = ""; + while(stream.bytesAvailable) + { + var val:uint = stream.readUnsignedByte(); + sha1 += (val < 16 ? "0" : "") + val.toString(16); + } + return sha1; + } + + /** + * Write the provided string into a new ByteArray + * @param string + * @return A new ByteArray + */ + static public function createByteArrayFromString(string:String):ByteArray + { + var result:ByteArray = new ByteArray(); + result.writeUTFBytes(string); + return result; + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/ObjectUtils.as b/src/nexus/utils/ObjectUtils.as index ddfd4e4..eb40b20 100644 --- a/src/nexus/utils/ObjectUtils.as +++ b/src/nexus/utils/ObjectUtils.as @@ -17,55 +17,55 @@ import nexus.utils.reflection.*; */ public class ObjectUtils { - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - /** - * Creates a new instance of the given type from the native object provided. Any values that exist in the provided - * object but not in the instance are ignored/dropped; and any values that exist in the instance but not the provided object - * are never assigned and left at their default values. - * Requires that the instance being instantiated provides a constructor with no arguments. - * @param source A native object which contains the values to assign into the newly created instance. - * @param type The class type of the object to instantiate - * @return A newly instantiated typed object with fields assigned from the provided data object. - */ - static public function createTypedObjectFromNativeObject(type:Class, source:Object, applicationDomain:ApplicationDomain=null):Object - { - var result:Object; - - //TODO: consider adding error checking if the data and desired type do not match - - //doesn't matter what the desired type is if the source data is null - if(source == null) - { - result = null; - } - else if(type == Date) - { - result = new Date(source); - } - else if(Reflection.isScalar(type) || type == null) - { - //if the object we are trying to create is a scalar but the source is not, try to cast the source to the desired type - result = Reflection.isScalar(source) ? source : source as type; - } - else if(Reflection.isArrayType(type) || Reflection.isAssociativeArray(type)) - { - //assume we can just instantiate native types directly without going through an app domain - result = new type(); - assignTypedObjectFromNativeObject(result, source, applicationDomain); - } - else - { - //see if there is a fromNative(object):Object method on this class, and call it if so - var typeInfo : TypeInfo = Reflection.getTypeInfo(type, applicationDomain); - var methodInfo : MethodInfo = typeInfo.getMethodByName("fromNative"); - if( methodInfo != null && methodInfo.isStatic - && methodInfo.returnType != null - && methodInfo.parameters.length == 1 - && methodInfo.parameters[0].type == Object) - { + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + /** + * Creates a new instance of the given type from the native object provided. Any values that exist in the provided + * object but not in the instance are ignored/dropped; and any values that exist in the instance but not the provided object + * are never assigned and left at their default values. + * Requires that the instance being instantiated provides a constructor with no arguments. + * @param source A native object which contains the values to assign into the newly created instance. + * @param type The class type of the object to instantiate + * @return A newly instantiated typed object with fields assigned from the provided data object. + */ + static public function createTypedObjectFromNativeObject(type:Class, source:Object, applicationDomain:ApplicationDomain=null):Object + { + var result:Object; + + //TODO: consider adding error checking if the data and desired type do not match + + //doesn't matter what the desired type is if the source data is null + if(source == null) + { + result = null; + } + else if(type == Date) + { + result = new Date(source); + } + else if(Reflection.isScalar(type) || type == null) + { + //if the object we are trying to create is a scalar but the source is not, try to cast the source to the desired type + result = Reflection.isScalar(source) ? source : source as type; + } + else if(Reflection.isArrayType(type) || Reflection.isAssociativeArray(type)) + { + //assume we can just instantiate native types directly without going through an app domain + result = new type(); + assignTypedObjectFromNativeObject(result, source, applicationDomain); + } + else + { + //see if there is a fromNative(object):Object method on this class, and call it if so + var typeInfo : TypeInfo = Reflection.getTypeInfo(type, applicationDomain); + var methodInfo : MethodInfo = typeInfo.getMethodByName("fromNative"); + if( methodInfo != null && methodInfo.isStatic + && methodInfo.returnType != null + && methodInfo.parameters.length == 1 + && methodInfo.parameters[0].type == Object) + { try { result = methodInfo.invoke(type, source); @@ -74,169 +74,169 @@ public class ObjectUtils { trace(e); } - } - else - { - try - { - //TODO: Handle constuctors with arguments? - result = new (Reflection.getClass(type, applicationDomain))(); - } - catch(e:Error) - { - //probably because ctor requires arguments, if we add support for that then this can catch more interesting errors + } + else + { + try + { + //TODO: Handle constuctors with arguments? + result = new (Reflection.getClass(type, applicationDomain))(); + } + catch(e:Error) + { + //probably because ctor requires arguments, if we add support for that then this can catch more interesting errors trace(e); - } - } - - if(result != null) - { - assignTypedObjectFromNativeObject(result, source, applicationDomain); - } - } - return result; - } - - /** - * Assigns properties and fields of the provided instance object from values in the provided data object. This method does not - * instantiate a new instance of the typed object, otherwise it is functionally equivalent to createTypedObjectFromNativeObject() - * @param instance A typed object instance whose members we want to assign from the provided data - * @param source A native object which contains the values to assign into the newly created instance. - */ - static public function assignTypedObjectFromNativeObject(instance:Object, source:Object, applicationDomain:ApplicationDomain=null):void - { - //assigning primitives is pointless without pass by ref - if(source == null || instance == null || Reflection.isScalar(instance) || instance is Date) - { - return; - } - else if(Reflection.isArrayType(instance)) - { - //clear out the existing array if there is anything in it - if(instance != null && instance.length > 0) - { - instance.splice(0, instance.length); - } - - for(var x:int = 0; x < source.length; ++x) - { - if(x in source && source[x] !== undefined) - { - instance[x] = createTypedObjectFromNativeObject(Reflection.getVectorType(instance, applicationDomain) || Reflection.getClass(source[x], applicationDomain), source[x], applicationDomain); - } - } - } - //if the object is an associative array, iterate over all the keys in the source and assign them - else if(Reflection.isAssociativeArray(instance)) - { - //TODO: Need to clear out existing values, re-instantiate? - for(var key:String in source) - { - //TODO: Does it even make any sense to get the class of the source? - instance[key] = createTypedObjectFromNativeObject(Reflection.getClass(source[key], applicationDomain), source[key], applicationDomain); - } - } - else - { - var typeInfo:TypeInfo = Reflection.getTypeInfo(instance, applicationDomain); - if(typeInfo.isDynamic) - { - var fieldsInDataFoundInClass : Object = { }; - } - - for each(var member:AbstractMemberInfo in typeInfo.allMembers) - { - var field : AbstractFieldInfo = member as AbstractFieldInfo; - //only assign the field if it exists in the source data - if(field != null && !field.isStatic) - { - var qname : QName = field.qname; - var qnameString : String = qname.toString(); - if(qnameString in source) - { - if(fieldsInDataFoundInClass != null) - { - fieldsInDataFoundInClass[qnameString] = true; - } - - if(field.canWrite) - { - try - { - instance[qname] = createTypedObjectFromNativeObject(field.type, source[qnameString], applicationDomain); - } - catch(e:Error) - { - //TODO: is a catch-all here ok? + } + } + + if(result != null) + { + assignTypedObjectFromNativeObject(result, source, applicationDomain); + } + } + return result; + } + + /** + * Assigns properties and fields of the provided instance object from values in the provided data object. This method does not + * instantiate a new instance of the typed object, otherwise it is functionally equivalent to createTypedObjectFromNativeObject() + * @param instance A typed object instance whose members we want to assign from the provided data + * @param source A native object which contains the values to assign into the newly created instance. + */ + static public function assignTypedObjectFromNativeObject(instance:Object, source:Object, applicationDomain:ApplicationDomain=null):void + { + //assigning primitives is pointless without pass by ref + if(source == null || instance == null || Reflection.isScalar(instance) || instance is Date) + { + return; + } + else if(Reflection.isArrayType(instance)) + { + //clear out the existing array if there is anything in it + if(instance != null && instance.length > 0) + { + instance.splice(0, instance.length); + } + + for(var x:int = 0; x < source.length; ++x) + { + if(x in source && source[x] !== undefined) + { + instance[x] = createTypedObjectFromNativeObject(Reflection.getVectorType(instance, applicationDomain) || Reflection.getClass(source[x], applicationDomain), source[x], applicationDomain); + } + } + } + //if the object is an associative array, iterate over all the keys in the source and assign them + else if(Reflection.isAssociativeArray(instance)) + { + //TODO: Need to clear out existing values, re-instantiate? + for(var key:String in source) + { + //TODO: Does it even make any sense to get the class of the source? + instance[key] = createTypedObjectFromNativeObject(Reflection.getClass(source[key], applicationDomain), source[key], applicationDomain); + } + } + else + { + var typeInfo:TypeInfo = Reflection.getTypeInfo(instance, applicationDomain); + if(typeInfo.isDynamic) + { + var fieldsInDataFoundInClass : Object = { }; + } + + for each(var member:AbstractMemberInfo in typeInfo.allMembers) + { + var field : AbstractFieldInfo = member as AbstractFieldInfo; + //only assign the field if it exists in the source data + if(field != null && !field.isStatic) + { + var qname : QName = field.qname; + var qnameString : String = qname.toString(); + if(qnameString in source) + { + if(fieldsInDataFoundInClass != null) + { + fieldsInDataFoundInClass[qnameString] = true; + } + + if(field.canWrite) + { + try + { + instance[qname] = createTypedObjectFromNativeObject(field.type, source[qnameString], applicationDomain); + } + catch(e:Error) + { + //TODO: is a catch-all here ok? trace(e); - } - } - else - { - assignTypedObjectFromNativeObject(instance[qname], source[qnameString], applicationDomain); - } - } - } - } - - if(typeInfo.isDynamic) - { - for(var dynamicKey:String in source) - { - if(!(dynamicKey in fieldsInDataFoundInClass)) - { - //TODO: Does it even make any sense to get the class of the source? - instance[dynamicKey] = createTypedObjectFromNativeObject(Reflection.getClass(source[dynamicKey], applicationDomain), source[dynamicKey], applicationDomain); - } - } - fieldsInDataFoundInClass = null; - } - } - } - - /** - * Reflects through the two objects provided and determines if objectA shares the same signature as objectB. - * @example - * var objectA : Object = { - * "name": "Object A", - * "value": 50, - * "good": true - * }; - * - * var objectB : Object = { - * "name": "Object B" - * }; - * - * ObjectUtils.objectIsLike(objectA, objectB) ==> true - * ObjectUtils.objectIsLike(objectB, objectA) ==> false - * - * - * var objectA : Object = { - * "name": "Object A", - * "value": 50, - * "good": true - * }; - * - * public interface IFoo - * { - * function get name():String; - * function get value():int; - * } - * - * ObjectUtils.objectIsLike(objectA, IFoo) ==> true - * - * @param objectA - * @param objectB - * @return - */ - static public function objectIsLike(instance:Object, instanceOrClassOrInterface:Object):Boolean - { - throw new NotImplementedError(); - } + } + } + else + { + assignTypedObjectFromNativeObject(instance[qname], source[qnameString], applicationDomain); + } + } + } + } + + if(typeInfo.isDynamic) + { + for(var dynamicKey:String in source) + { + if(!(dynamicKey in fieldsInDataFoundInClass)) + { + //TODO: Does it even make any sense to get the class of the source? + instance[dynamicKey] = createTypedObjectFromNativeObject(Reflection.getClass(source[dynamicKey], applicationDomain), source[dynamicKey], applicationDomain); + } + } + fieldsInDataFoundInClass = null; + } + } + } + + /** + * Reflects through the two objects provided and determines if objectA shares the same signature as objectB. + * @example + * var objectA : Object = { + * "name": "Object A", + * "value": 50, + * "good": true + * }; + * + * var objectB : Object = { + * "name": "Object B" + * }; + * + * ObjectUtils.objectIsLike(objectA, objectB) ==> true + * ObjectUtils.objectIsLike(objectB, objectA) ==> false + * + * + * var objectA : Object = { + * "name": "Object A", + * "value": 50, + * "good": true + * }; + * + * public interface IFoo + * { + * function get name():String; + * function get value():int; + * } + * + * ObjectUtils.objectIsLike(objectA, IFoo) ==> true + * + * @param objectA + * @param objectB + * @return + */ + static public function objectIsLike(instance:Object, instanceOrClassOrInterface:Object):Boolean + { + throw new NotImplementedError(); + } - //-------------------------------------- - // PRIVATE CLASS METHODS - //-------------------------------------- + //-------------------------------------- + // PRIVATE CLASS METHODS + //-------------------------------------- } -} \ No newline at end of file +} diff --git a/src/nexus/utils/Parse.as b/src/nexus/utils/Parse.as index a518f97..39b4732 100644 --- a/src/nexus/utils/Parse.as +++ b/src/nexus/utils/Parse.as @@ -15,207 +15,207 @@ import flash.utils.Dictionary; */ public class Parse { - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - /** - * Parse the given value as a Number. If the parsed Number is NaN or Infinity then defaultValue is returned instead. - * @param source - * @param defaultValue The default value to use if the parsed Number is NaN or Infinity - * @return - */ - public static function number(source:Object, defaultValue:Number):Number - { - var result:Number = parseFloat(source + ""); - return isNaN(result) || !isFinite(result) ? defaultValue : result; - } - - /** - * Parse the given value as an int. If the parsed value is NaN or Infinity then defaultValue is returned instead. - * @param source - * @param defaultValue - * @return - */ - public static function integer(source:Object, defaultValue:int, radix:int = 10):int - { - //malachi: parse int returns a number which we use to check for NaN before setting to default value, if - //result was of type int than NaN would result in 0 and we wouldn't be able to check and assign default value - var result:Number = parseInt(source + "", radix); - return isNaN(result) || !isFinite(result) ? defaultValue : result; - } - - /** - * Parses a string value, the default value is used if the source is null - * @return - */ - public static function string(source:Object, defaultValue:String):String - { - return(source !== null ? String(source + "") : defaultValue); - } - - /** - * Parses the given value as a Point, assuming a string input in the format "x,y" - * @param source - * @param defaultX The x value to use if the parsed value is NaN or Infinity - * @param defaultY The y value to use if the parsed value is NaN or Infinity - * @return - */ - public static function point(source:Object, defaultX:int, defaultY:int):Point - { - var array:Array = String(source + "").split(","); - return new Point(Parse.number(array[0], defaultX), Parse.number(array[1], defaultY)); - } - - /** - * Case-insensitive. If defaultValue is false, this converts "true", "t", "1", "yes", and "y" to a true boolean and all - * other values return false. If defaultValue is true, this converts "false", "f", "0", "no", and "n" to a false boolean - * and all other values return true. - * @param source A value to convert to Boolean - * @param alsoMatch If provided, will return true if the source matches this value (case-insensitive) - * @return - */ - public static function boolean(source:Object, defaultValue:Boolean, alsoMatch:String = null):Boolean - { - var match:String = alsoMatch != null ? (alsoMatch + "").toLowerCase() : null; - var check:String = (source + "").toLowerCase(); - - if(defaultValue) - { - switch(check) - { - case "false": - case "f": - case "0": - case "no": - case "n": - case match: - return false; - default: - return true; - } - } - - switch(check) - { - case "true": - case "t": - case "1": - case "yes": - case "y": - case match: - return true; - default: - return false; - } - } - - /* - public static function enum(source:*, enumClass:Class, caseSensitive:Boolean=false):Enum - { - return Enum.fromString(enumClass, value, caseSensitive); - } - */ - - /** - * Parses the given value as a Dictionary using the provided delimiters to split entries and key/value pairs. If - * there are errors in the parsing or the source object cannot be parsed correctly, null is returned - * @param source - * @param entryDelimiter A string delimiter for each key/value entry for the dictionary - * @param keyValueDelimiter A string delimiter between each key/value pair - * @return A Dictionary or null if the source cannot be parsed - * @example - * var str1 : String = "key1:value1|key2:value2|key3:value3|key4:value4"; - * var str2 : String = "key1,value1 key2,value2 key3,value3 key4,value4"; - * var dict1 : Dictionary = Parse.dictionary(str1, "|", ":"); - * var dict2 : Dictionary = Parse.dictionary(str2, " ", ","); - * - */ - public static function dictionary(source:Object, entryDelimiter:String, keyValueDelimiter:String):Dictionary - { - var result:Dictionary = new Dictionary(); - //if nothing can be parsed from the source, then we return null instead of an empty dictionary - var valuesFound:Boolean = false; - - var entries:Array = (source + "").split(entryDelimiter); - for(var x:int = 0; x < entries.length; ++x) - { - entries[x] = String(entries[x]).split(keyValueDelimiter); - //make sure that upon splitting this entry into key/value that it has two fields and the key isn't null - if(entries[x].length == 2 && entries[x][0] != null) - { - result[entries[x][0]] = entries[x][1]; - valuesFound = true; - } - } - - return valuesFound ? result : null; - } - - /** - * Parses a string in ISO 8601 format and returns a Date object with the corresponding date - * @param a_string a string formatted in a valid W3C subset of ISO 8601 - * @return - */ - public static function iso8601Date(a_string:String, defaultValue:Date = null):Date - { - if(a_string == null || a_string == "") - { - return defaultValue; - } - - var regexp:RegExp = /^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?)?((?:([+-])(\d{2})(?::(\d{2}))?)|Z)?$/; - var match:Array = a_string.match(regexp); - - //trace(a_string); - - if(match == null) - { - return new Date(0, 0); - } - - //remove full-match from resulting array - match.shift(); - - //trace(match); - - //months are 0-based in the Date constructor for some reason - if(match[1]) - { - match[1]--; - } - - var result:Date = new Date(match[0] || 1970, match[1] || 0, match[2] || 1, match[3] || 0, match[4] || 0, match[5] || 0, match[6] || 0); - - //account for timezone - var timezoneOffset:int = 0; - //if there was something provided for timezone - if(match[7]) - { - if(match[7] != "Z") - { - var hours:int = parseInt(match[9]) || 0; - var minutes:int = parseInt(match[10]) || 0; - timezoneOffset = (hours * 60) + minutes; - if(match[8] == '+') - { - timezoneOffset *= -1; - } - } - //cancel out this system's timezone offset - timezoneOffset -= result.getTimezoneOffset(); - } - - //BUG: This causes a problem the the US during the spring time change when clocks advance an hour. That hour of time has - //not actually elapsed, so any time-related functions (eg, time elapsed to change state of an object) will fail - if(timezoneOffset != 0) - { - result.setTime(result.getTime() + (timezoneOffset * 60 * 1000)); - } - - //trace(DateUtil.toISOString(result)); - return result; - } + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + /** + * Parse the given value as a Number. If the parsed Number is NaN or Infinity then defaultValue is returned instead. + * @param source + * @param defaultValue The default value to use if the parsed Number is NaN or Infinity + * @return + */ + public static function number(source:Object, defaultValue:Number):Number + { + var result:Number = parseFloat(source + ""); + return isNaN(result) || !isFinite(result) ? defaultValue : result; + } + + /** + * Parse the given value as an int. If the parsed value is NaN or Infinity then defaultValue is returned instead. + * @param source + * @param defaultValue + * @return + */ + public static function integer(source:Object, defaultValue:int, radix:int = 10):int + { + //malachi: parse int returns a number which we use to check for NaN before setting to default value, if + //result was of type int than NaN would result in 0 and we wouldn't be able to check and assign default value + var result:Number = parseInt(source + "", radix); + return isNaN(result) || !isFinite(result) ? defaultValue : result; + } + + /** + * Parses a string value, the default value is used if the source is null + * @return + */ + public static function string(source:Object, defaultValue:String):String + { + return(source !== null ? String(source + "") : defaultValue); + } + + /** + * Parses the given value as a Point, assuming a string input in the format "x,y" + * @param source + * @param defaultX The x value to use if the parsed value is NaN or Infinity + * @param defaultY The y value to use if the parsed value is NaN or Infinity + * @return + */ + public static function point(source:Object, defaultX:int, defaultY:int):Point + { + var array:Array = String(source + "").split(","); + return new Point(Parse.number(array[0], defaultX), Parse.number(array[1], defaultY)); + } + + /** + * Case-insensitive. If defaultValue is false, this converts "true", "t", "1", "yes", and "y" to a true boolean and all + * other values return false. If defaultValue is true, this converts "false", "f", "0", "no", and "n" to a false boolean + * and all other values return true. + * @param source A value to convert to Boolean + * @param alsoMatch If provided, will return true if the source matches this value (case-insensitive) + * @return + */ + public static function boolean(source:Object, defaultValue:Boolean, alsoMatch:String = null):Boolean + { + var match:String = alsoMatch != null ? (alsoMatch + "").toLowerCase() : null; + var check:String = (source + "").toLowerCase(); + + if(defaultValue) + { + switch(check) + { + case "false": + case "f": + case "0": + case "no": + case "n": + case match: + return false; + default: + return true; + } + } + + switch(check) + { + case "true": + case "t": + case "1": + case "yes": + case "y": + case match: + return true; + default: + return false; + } + } + + /* + public static function enum(source:*, enumClass:Class, caseSensitive:Boolean=false):Enum + { + return Enum.fromString(enumClass, value, caseSensitive); + } + */ + + /** + * Parses the given value as a Dictionary using the provided delimiters to split entries and key/value pairs. If + * there are errors in the parsing or the source object cannot be parsed correctly, null is returned + * @param source + * @param entryDelimiter A string delimiter for each key/value entry for the dictionary + * @param keyValueDelimiter A string delimiter between each key/value pair + * @return A Dictionary or null if the source cannot be parsed + * @example + * var str1 : String = "key1:value1|key2:value2|key3:value3|key4:value4"; + * var str2 : String = "key1,value1 key2,value2 key3,value3 key4,value4"; + * var dict1 : Dictionary = Parse.dictionary(str1, "|", ":"); + * var dict2 : Dictionary = Parse.dictionary(str2, " ", ","); + * + */ + public static function dictionary(source:Object, entryDelimiter:String, keyValueDelimiter:String):Dictionary + { + var result:Dictionary = new Dictionary(); + //if nothing can be parsed from the source, then we return null instead of an empty dictionary + var valuesFound:Boolean = false; + + var entries:Array = (source + "").split(entryDelimiter); + for(var x:int = 0; x < entries.length; ++x) + { + entries[x] = String(entries[x]).split(keyValueDelimiter); + //make sure that upon splitting this entry into key/value that it has two fields and the key isn't null + if(entries[x].length == 2 && entries[x][0] != null) + { + result[entries[x][0]] = entries[x][1]; + valuesFound = true; + } + } + + return valuesFound ? result : null; + } + + /** + * Parses a string in ISO 8601 format and returns a Date object with the corresponding date + * @param a_string a string formatted in a valid W3C subset of ISO 8601 + * @return + */ + public static function iso8601Date(a_string:String, defaultValue:Date = null):Date + { + if(a_string == null || a_string == "") + { + return defaultValue; + } + + var regexp:RegExp = /^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?)?((?:([+-])(\d{2})(?::(\d{2}))?)|Z)?$/; + var match:Array = a_string.match(regexp); + + //trace(a_string); + + if(match == null) + { + return new Date(0, 0); + } + + //remove full-match from resulting array + match.shift(); + + //trace(match); + + //months are 0-based in the Date constructor for some reason + if(match[1]) + { + match[1]--; + } + + var result:Date = new Date(match[0] || 1970, match[1] || 0, match[2] || 1, match[3] || 0, match[4] || 0, match[5] || 0, match[6] || 0); + + //account for timezone + var timezoneOffset:int = 0; + //if there was something provided for timezone + if(match[7]) + { + if(match[7] != "Z") + { + var hours:int = parseInt(match[9]) || 0; + var minutes:int = parseInt(match[10]) || 0; + timezoneOffset = (hours * 60) + minutes; + if(match[8] == '+') + { + timezoneOffset *= -1; + } + } + //cancel out this system's timezone offset + timezoneOffset -= result.getTimezoneOffset(); + } + + //BUG: This causes a problem the the US during the spring time change when clocks advance an hour. That hour of time has + //not actually elapsed, so any time-related functions (eg, time elapsed to change state of an object) will fail + if(timezoneOffset != 0) + { + result.setTime(result.getTime() + (timezoneOffset * 60 * 1000)); + } + + //trace(DateUtil.toISOString(result)); + return result; + } } } diff --git a/src/nexus/utils/reflection/AbstractFieldInfo.as b/src/nexus/utils/reflection/AbstractFieldInfo.as index 6dadc72..85f2ef5 100644 --- a/src/nexus/utils/reflection/AbstractFieldInfo.as +++ b/src/nexus/utils/reflection/AbstractFieldInfo.as @@ -16,121 +16,121 @@ import nexus.errors.NotImplementedError; */ public class AbstractFieldInfo extends AbstractMemberInfo { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - /** - * @private - */ - protected var m_type:Class; - /** - * @private - */ - protected var m_typeName : String; - - /** - * @private - */ - protected var m_canRead : Boolean; - /** - * @private - */ - protected var m_canWrite : Boolean; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function AbstractFieldInfo(name:String, isStatic:Boolean, type:Class, declaringType:Class, reflectedTypeInfo:TypeInfo, read:Boolean, write:Boolean) - { - super(name, isStatic, declaringType, reflectedTypeInfo); - - m_type = type; - - m_canRead = read; - m_canWrite = write; - - if(m_canRead == false && m_canWrite == false) - { - throw new ArgumentError("Cannot create AbstractFieldInfo, both canRead and canWrite are set to false"); - } - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - public function get type():Class { return m_type; } - - public function get canRead():Boolean { return m_canRead; } - - public function get canWrite():Boolean { return m_canWrite; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * Retrieves this field off of the provided object - * @param instance An instance of an object that contains this field - * @return The value of this field retrieved from the provided instance - * @throws IllegalOperationError If this field is write-only - * @throws ArgumentError If the provided instance object is not in the proper class hierarchy to contain this field - */ - public function getValue(instance:Object):Object - { - if(!m_canRead) - { - throw new IllegalOperationError("Cannot read " + this.toString() + " on " + Reflection.getQualifiedClassName(m_declaringType) + ", it is write-only."); - } - - if(m_declaringType != null && !(instance is m_declaringType)) - { - throw new ArgumentError("Cannot read " + this.toString() + ", declared on " + Reflection.getQualifiedClassName(m_declaringType) + ", from an object of type " + Reflection.getQualifiedClassName(instance) + "."); - } - - return instance[m_qname]; - } - - /** - * Assigns this field on the provided object - * @param instance An instance of an object that contains this field - * @throws IllegalOperationError If this field is read-only - * @throws ArgumentError If the provided instance object is not in the proper class hierarchy to contain this field - */ - public function setValue(instance:Object, value:Object):void - { - if(!m_canWrite) - { - throw new IllegalOperationError("Cannot write " + this.toString() + " on " + Reflection.getQualifiedClassName(m_declaringType) + ", it is read-only."); - } - - if(m_declaringType != null && !(instance is m_declaringType)) - { - throw new ArgumentError("Cannot write " + this.toString() + ", declared on " + Reflection.getQualifiedClassName(m_declaringType) + ", to an object of type " + Reflection.getQualifiedClassName(instance) + "."); - } - - if(value != null && !(value is m_type)) - { - throw new ArgumentError("Cannot assign " + this.toString() + " a value of type " + Reflection.getQualifiedClassName(value)); - } - - instance[m_qname] = value; - } - - public function toString():String - { - throw new NotImplementedError(); - } - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + /** + * @private + */ + protected var m_type:Class; + /** + * @private + */ + protected var m_typeName : String; + + /** + * @private + */ + protected var m_canRead : Boolean; + /** + * @private + */ + protected var m_canWrite : Boolean; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function AbstractFieldInfo(name:String, isStatic:Boolean, type:Class, declaringType:Class, reflectedTypeInfo:TypeInfo, read:Boolean, write:Boolean) + { + super(name, isStatic, declaringType, reflectedTypeInfo); + + m_type = type; + + m_canRead = read; + m_canWrite = write; + + if(m_canRead == false && m_canWrite == false) + { + throw new ArgumentError("Cannot create AbstractFieldInfo, both canRead and canWrite are set to false"); + } + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + public function get type():Class { return m_type; } + + public function get canRead():Boolean { return m_canRead; } + + public function get canWrite():Boolean { return m_canWrite; } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * Retrieves this field off of the provided object + * @param instance An instance of an object that contains this field + * @return The value of this field retrieved from the provided instance + * @throws IllegalOperationError If this field is write-only + * @throws ArgumentError If the provided instance object is not in the proper class hierarchy to contain this field + */ + public function getValue(instance:Object):Object + { + if(!m_canRead) + { + throw new IllegalOperationError("Cannot read " + this.toString() + " on " + Reflection.getQualifiedClassName(m_declaringType) + ", it is write-only."); + } + + if(m_declaringType != null && !(instance is m_declaringType)) + { + throw new ArgumentError("Cannot read " + this.toString() + ", declared on " + Reflection.getQualifiedClassName(m_declaringType) + ", from an object of type " + Reflection.getQualifiedClassName(instance) + "."); + } + + return instance[m_qname]; + } + + /** + * Assigns this field on the provided object + * @param instance An instance of an object that contains this field + * @throws IllegalOperationError If this field is read-only + * @throws ArgumentError If the provided instance object is not in the proper class hierarchy to contain this field + */ + public function setValue(instance:Object, value:Object):void + { + if(!m_canWrite) + { + throw new IllegalOperationError("Cannot write " + this.toString() + " on " + Reflection.getQualifiedClassName(m_declaringType) + ", it is read-only."); + } + + if(m_declaringType != null && !(instance is m_declaringType)) + { + throw new ArgumentError("Cannot write " + this.toString() + ", declared on " + Reflection.getQualifiedClassName(m_declaringType) + ", to an object of type " + Reflection.getQualifiedClassName(instance) + "."); + } + + if(value != null && !(value is m_type)) + { + throw new ArgumentError("Cannot assign " + this.toString() + " a value of type " + Reflection.getQualifiedClassName(value)); + } + + instance[m_qname] = value; + } + + public function toString():String + { + throw new NotImplementedError(); + } + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/AbstractMemberInfo.as b/src/nexus/utils/reflection/AbstractMemberInfo.as index db2ef2d..e4cae6d 100644 --- a/src/nexus/utils/reflection/AbstractMemberInfo.as +++ b/src/nexus/utils/reflection/AbstractMemberInfo.as @@ -13,89 +13,89 @@ import flash.utils.*; */ public class AbstractMemberInfo extends AbstractMetadataRecipient { - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - /** - * @private - */ - protected var m_declaringType:Class; - /** - * @private - */ - protected var m_reflectedFrom : TypeInfo; - - /** - * @private - */ - protected var m_isStatic : Boolean; - - /** - * @private - */ - protected var m_namespace : Namespace; - /** - * @private - */ - protected var m_qname : QName; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function AbstractMemberInfo(name:String, isStatic:Boolean, declaringType:Class, reflectedTypeInfo:TypeInfo) - { - super(name); - - m_isStatic = isStatic; - - m_declaringType = declaringType; - m_reflectedFrom = reflectedTypeInfo; - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - /** - * The class which declares this member - */ - public function get declaringType():Class { return m_declaringType; } - - /** - * The TypeInfo that was created to derive this member info - */ - public function get reflectedFrom():TypeInfo { return m_reflectedFrom; } - - public function get isStatic():Boolean { return m_isStatic; } - - /** - * The namespace of this member, if one exists. - */ - public function get namespace():Namespace { return m_namespace; } - - /** - * The QName of this member. Use this for access instead of name - */ - public function get qname():QName { return m_qname; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - //-------------------------------------- - // INTERNAL INSTANCE METHODS - //-------------------------------------- - - /** - * @private - */ - internal function assignNamespace(ns:Namespace):void - { - m_namespace = ns; - m_qname = new QName(m_namespace == null ? "" : m_namespace, m_name); - } + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + /** + * @private + */ + protected var m_declaringType:Class; + /** + * @private + */ + protected var m_reflectedFrom : TypeInfo; + + /** + * @private + */ + protected var m_isStatic : Boolean; + + /** + * @private + */ + protected var m_namespace : Namespace; + /** + * @private + */ + protected var m_qname : QName; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function AbstractMemberInfo(name:String, isStatic:Boolean, declaringType:Class, reflectedTypeInfo:TypeInfo) + { + super(name); + + m_isStatic = isStatic; + + m_declaringType = declaringType; + m_reflectedFrom = reflectedTypeInfo; + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + /** + * The class which declares this member + */ + public function get declaringType():Class { return m_declaringType; } + + /** + * The TypeInfo that was created to derive this member info + */ + public function get reflectedFrom():TypeInfo { return m_reflectedFrom; } + + public function get isStatic():Boolean { return m_isStatic; } + + /** + * The namespace of this member, if one exists. + */ + public function get namespace():Namespace { return m_namespace; } + + /** + * The QName of this member. Use this for access instead of name + */ + public function get qname():QName { return m_qname; } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + //-------------------------------------- + // INTERNAL INSTANCE METHODS + //-------------------------------------- + + /** + * @private + */ + internal function assignNamespace(ns:Namespace):void + { + m_namespace = ns; + m_qname = new QName(m_namespace == null ? "" : m_namespace, m_name); + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/AbstractMetadataRecipient.as b/src/nexus/utils/reflection/AbstractMetadataRecipient.as index 3e77f85..f07f019 100644 --- a/src/nexus/utils/reflection/AbstractMetadataRecipient.as +++ b/src/nexus/utils/reflection/AbstractMetadataRecipient.as @@ -15,122 +15,122 @@ import nexus.nexuslib_internal; */ public class AbstractMetadataRecipient { - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - /** - * @private - */ - protected var m_name:String; - - /** - * @private - */ - protected var m_metadata:Vector.; - - /** - * @private - */ - protected var m_metadataByName:Dictionary; - - /** - * @private - * As defined in the debug-only metadata tag __go_to_definition_help - */ - protected var m_position:int; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function AbstractMetadataRecipient(name:String) - { - m_name = name; - - m_metadata = new Vector.(); - m_metadataByName = new Dictionary(); - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - /** - * The name of this member - */ - public function get name():String { return m_name; } - - /** - * Any metadata attached to this member - */ - public function get metadata():Vector. { return m_metadata; } - - /** - * The value of the "__go_to_definition_help" metadata tag - */ - public function get position():int { return m_position; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * Retrieves the MetadataInfo, if any, with the given name - * @param name The name of the metadata tag - * @return - */ - public function getMetadataByName(name:String):MetadataInfo - { - return m_metadataByName[name]; - } - - /** - * Retrieves the MetadataInfo of a specific subclass. Be sure to register the class with Reflection.registerMetadataClass first - * @param type A class which extends MetadataInfo - * @return - */ - public function getMetadataByClass(type:Class):MetadataInfo - { - return m_metadataByName[type]; - } - - //-------------------------------------- - // INTERNAL INSTANCE METHODS - //-------------------------------------- - - /** - * @private - */ - internal function setPosition(value:int):void - { - m_position = value; - } - - /** - * @private - */ - internal function addMetadata(meta:MetadataInfo):void - { - use namespace nexuslib_internal; - - m_metadata.push(meta); - m_metadataByName[meta.metadataName] = meta; - - //if the metadata class has been registered, index it by that type as well - var type:Class = Reflection.getMetadataClass(meta); - if(type != null) - { - if(m_metadataByName[type] != null) - { - throw new Error("Metadata tag of type \"" + type + "\" defined twice on the same member"); - } - else - { - m_metadataByName[type] = meta; - } - } - } + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + /** + * @private + */ + protected var m_name:String; + + /** + * @private + */ + protected var m_metadata:Vector.; + + /** + * @private + */ + protected var m_metadataByName:Dictionary; + + /** + * @private + * As defined in the debug-only metadata tag __go_to_definition_help + */ + protected var m_position:int; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function AbstractMetadataRecipient(name:String) + { + m_name = name; + + m_metadata = new Vector.(); + m_metadataByName = new Dictionary(); + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + /** + * The name of this member + */ + public function get name():String { return m_name; } + + /** + * Any metadata attached to this member + */ + public function get metadata():Vector. { return m_metadata; } + + /** + * The value of the "__go_to_definition_help" metadata tag + */ + public function get position():int { return m_position; } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * Retrieves the MetadataInfo, if any, with the given name + * @param name The name of the metadata tag + * @return + */ + public function getMetadataByName(name:String):MetadataInfo + { + return m_metadataByName[name]; + } + + /** + * Retrieves the MetadataInfo of a specific subclass. Be sure to register the class with Reflection.registerMetadataClass first + * @param type A class which extends MetadataInfo + * @return + */ + public function getMetadataByClass(type:Class):MetadataInfo + { + return m_metadataByName[type]; + } + + //-------------------------------------- + // INTERNAL INSTANCE METHODS + //-------------------------------------- + + /** + * @private + */ + internal function setPosition(value:int):void + { + m_position = value; + } + + /** + * @private + */ + internal function addMetadata(meta:MetadataInfo):void + { + use namespace nexuslib_internal; + + m_metadata.push(meta); + m_metadataByName[meta.metadataName] = meta; + + //if the metadata class has been registered, index it by that type as well + var type:Class = Reflection.getMetadataClass(meta); + if(type != null) + { + if(m_metadataByName[type] != null) + { + throw new Error("Metadata tag of type \"" + type + "\" defined twice on the same member"); + } + else + { + m_metadataByName[type] = meta; + } + } + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/FieldInfo.as b/src/nexus/utils/reflection/FieldInfo.as index 394c509..2016768 100644 --- a/src/nexus/utils/reflection/FieldInfo.as +++ b/src/nexus/utils/reflection/FieldInfo.as @@ -11,41 +11,41 @@ package nexus.utils.reflection */ public final class FieldInfo extends AbstractFieldInfo { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function FieldInfo(name:String, isStatic:Boolean, type:Class, declaringType:Class, reflectedTypeInfo:TypeInfo, write:Boolean) - { - super(name, isStatic, type, declaringType, reflectedTypeInfo, true, write); - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - public function get isConstant():Boolean { return !m_canWrite; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - override public function toString():String - { - if(m_typeName == null) - { - m_typeName = Reflection.getUnqualifiedClassName(m_type); - } - return "[" + (m_isStatic ? "Static" : "") + (m_canWrite ? "Variable" : "Constant") + "|" + m_name + ":" + m_typeName + "]"; - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function FieldInfo(name:String, isStatic:Boolean, type:Class, declaringType:Class, reflectedTypeInfo:TypeInfo, write:Boolean) + { + super(name, isStatic, type, declaringType, reflectedTypeInfo, true, write); + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + public function get isConstant():Boolean { return !m_canWrite; } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + override public function toString():String + { + if(m_typeName == null) + { + m_typeName = Reflection.getUnqualifiedClassName(m_type); + } + return "[" + (m_isStatic ? "Static" : "") + (m_canWrite ? "Variable" : "Constant") + "|" + m_name + ":" + m_typeName + "]"; + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/ITypeInfoCreator.as b/src/nexus/utils/reflection/ITypeInfoCreator.as index 7daedb1..c5bf9fc 100644 --- a/src/nexus/utils/reflection/ITypeInfoCreator.as +++ b/src/nexus/utils/reflection/ITypeInfoCreator.as @@ -7,14 +7,14 @@ package nexus.utils.reflection { import flash.system.ApplicationDomain; - + /** * An internal interface used for XML and JSON TypeInfo creators * @private */ public interface ITypeInfoCreator { - function create(type:Class, applicationDomain:ApplicationDomain):TypeInfo; + function create(type:Class, applicationDomain:ApplicationDomain):TypeInfo; } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/MetadataInfo.as b/src/nexus/utils/reflection/MetadataInfo.as index 701f758..a8dcf83 100644 --- a/src/nexus/utils/reflection/MetadataInfo.as +++ b/src/nexus/utils/reflection/MetadataInfo.as @@ -20,54 +20,54 @@ import flash.utils.*; */ public class MetadataInfo { - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - /** - * @private - */ - protected var m_metadataName : String; - /** - * @private - */ - protected var m_metadataKeyValuePairs : Dictionary; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function MetadataInfo(name:String, keyValueCollection:Dictionary) - { - m_metadataName = name; - m_metadataKeyValuePairs = keyValueCollection; - } + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + /** + * @private + */ + protected var m_metadataName : String; + /** + * @private + */ + protected var m_metadataKeyValuePairs : Dictionary; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function MetadataInfo(name:String, keyValueCollection:Dictionary) + { + m_metadataName = name; + m_metadataKeyValuePairs = keyValueCollection; + } - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - public final function get metadataName():String { return m_metadataName; } - - public final function get metadataKeyValuePairs():Dictionary { return m_metadataKeyValuePairs; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - public final function getValue(key:String):String - { - return m_metadataKeyValuePairs[key]; - } - - public function toString():String - { - return "[Metadata|" + m_metadataName + "]"; - } - - //-------------------------------------- - // INTERNAL INSTANCE METHODS - //-------------------------------------- + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + public final function get metadataName():String { return m_metadataName; } + + public final function get metadataKeyValuePairs():Dictionary { return m_metadataKeyValuePairs; } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + public final function getValue(key:String):String + { + return m_metadataKeyValuePairs[key]; + } + + public function toString():String + { + return "[Metadata|" + m_metadataName + "]"; + } + + //-------------------------------------- + // INTERNAL INSTANCE METHODS + //-------------------------------------- } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/MethodInfo.as b/src/nexus/utils/reflection/MethodInfo.as index 0cf32b9..98e62c1 100644 --- a/src/nexus/utils/reflection/MethodInfo.as +++ b/src/nexus/utils/reflection/MethodInfo.as @@ -14,136 +14,136 @@ import flash.utils.*; */ public final class MethodInfo extends AbstractMemberInfo { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_returnType:Class; - private var m_returnTypeName : String; - - private var m_parameters : Vector.; - private var m_requiredParametersCount : int; - - ///@see toString - private var m_parametersString : String; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function MethodInfo(name:String, isStatic:Boolean, returnType:Class, declaringType:Class, reflectedTypeInfo:TypeInfo, paramCount:int) - { - super(name, isStatic, declaringType, reflectedTypeInfo); - - m_returnType = returnType; - m_parameters = new Vector.(paramCount, true); - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - /** - * The return type of this method. If the return type is void, this will return null - */ - public function get returnType():Class { return m_returnType; } - - /** - * The parameters this method takes, indexed by their order in the method signature - */ - public function get parameters():Vector. { return m_parameters; } - - /** - * The number of method parameters that are required - */ - public function get requiredParametersCount():int { return m_requiredParametersCount; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * Invokes the method on the provided instance using the specified parameters. - * @param scope - * @param ...params - * @return Returns the result of the method invocation or null if the return type is void - */ - public function invoke(scope:Object, ...params):Object - { - //TODO: Decide if this is necessary or if we can let errors fall through and throw when apply() is called - if((!m_isStatic && !(scope is m_declaringType)) || (m_isStatic && scope != m_declaringType)) - { - throw new ArgumentError("Cannot invoke " + this.toString() + ", declared on " + Reflection.getQualifiedClassName(m_declaringType) + ", on an object of type " + Reflection.getQualifiedClassName(scope) + "."); - } - //TODO: Decide if this is necessary or if we can let errors fall through and throw when apply() is called - /* - for(var x : int = 0; x < m_parameters.length; ++x) - { - var paramInfo : MethodParameterInfo = m_parameters[x]; - if(x >= params.length) - { - if(!paramInfo.isOptional) - { - throw new ArgumentError("Cannot invoke " + this.toString() + " with " + params.length + " arguments."); - } - } - else if(!(params[x] is paramInfo.type)) - { - throw new ArgumentError("Cannot invoke " + this.toString() + " with an argument of type " + Reflection.getQualifiedClassName(params[x]) + " at position " + x + "."); - } - } - //*/ - - if(m_returnType != null) - { - return scope[m_qname].apply(scope, params); - } - else - { - scope[m_qname].apply(scope, params); - return null; - } - } - - public function toString():String - { - if(m_returnTypeName == null) - { - m_returnTypeName = (m_returnType == null ? "void" : Reflection.getUnqualifiedClassName(m_returnType)); - } - - if(m_parametersString == null) - { - m_parametersString = ""; - for each(var param : MethodParameterInfo in m_parameters) - { - m_parametersString += param.toString() + (param.isOptional ? "?" : "") + ","; - } - m_parametersString = m_parametersString.substr(0, m_parametersString.length - 1); - } - - return "[" + (m_isStatic ? "Static" : "") + "Method|" + m_name + "(" + m_parametersString + "):" + m_returnTypeName + "]"; - } - - //-------------------------------------- - // INTERNAL INSTANCE METHODS - //-------------------------------------- - - /** - * @private - */ - internal function addMethodParameter(param:MethodParameterInfo):void - { - m_parameters[param.position] = param; - if(!param.isOptional) - { - m_requiredParametersCount++; - } - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_returnType:Class; + private var m_returnTypeName : String; + + private var m_parameters : Vector.; + private var m_requiredParametersCount : int; + + ///@see toString + private var m_parametersString : String; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function MethodInfo(name:String, isStatic:Boolean, returnType:Class, declaringType:Class, reflectedTypeInfo:TypeInfo, paramCount:int) + { + super(name, isStatic, declaringType, reflectedTypeInfo); + + m_returnType = returnType; + m_parameters = new Vector.(paramCount, true); + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + /** + * The return type of this method. If the return type is void, this will return null + */ + public function get returnType():Class { return m_returnType; } + + /** + * The parameters this method takes, indexed by their order in the method signature + */ + public function get parameters():Vector. { return m_parameters; } + + /** + * The number of method parameters that are required + */ + public function get requiredParametersCount():int { return m_requiredParametersCount; } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * Invokes the method on the provided instance using the specified parameters. + * @param scope + * @param ...params + * @return Returns the result of the method invocation or null if the return type is void + */ + public function invoke(scope:Object, ...params):Object + { + //TODO: Decide if this is necessary or if we can let errors fall through and throw when apply() is called + if((!m_isStatic && !(scope is m_declaringType)) || (m_isStatic && scope != m_declaringType)) + { + throw new ArgumentError("Cannot invoke " + this.toString() + ", declared on " + Reflection.getQualifiedClassName(m_declaringType) + ", on an object of type " + Reflection.getQualifiedClassName(scope) + "."); + } + //TODO: Decide if this is necessary or if we can let errors fall through and throw when apply() is called + /* + for(var x : int = 0; x < m_parameters.length; ++x) + { + var paramInfo : MethodParameterInfo = m_parameters[x]; + if(x >= params.length) + { + if(!paramInfo.isOptional) + { + throw new ArgumentError("Cannot invoke " + this.toString() + " with " + params.length + " arguments."); + } + } + else if(!(params[x] is paramInfo.type)) + { + throw new ArgumentError("Cannot invoke " + this.toString() + " with an argument of type " + Reflection.getQualifiedClassName(params[x]) + " at position " + x + "."); + } + } + //*/ + + if(m_returnType != null) + { + return scope[m_qname].apply(scope, params); + } + else + { + scope[m_qname].apply(scope, params); + return null; + } + } + + public function toString():String + { + if(m_returnTypeName == null) + { + m_returnTypeName = (m_returnType == null ? "void" : Reflection.getUnqualifiedClassName(m_returnType)); + } + + if(m_parametersString == null) + { + m_parametersString = ""; + for each(var param : MethodParameterInfo in m_parameters) + { + m_parametersString += param.toString() + (param.isOptional ? "?" : "") + ","; + } + m_parametersString = m_parametersString.substr(0, m_parametersString.length - 1); + } + + return "[" + (m_isStatic ? "Static" : "") + "Method|" + m_name + "(" + m_parametersString + "):" + m_returnTypeName + "]"; + } + + //-------------------------------------- + // INTERNAL INSTANCE METHODS + //-------------------------------------- + + /** + * @private + */ + internal function addMethodParameter(param:MethodParameterInfo):void + { + m_parameters[param.position] = param; + if(!param.isOptional) + { + m_requiredParametersCount++; + } + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/MethodParameterInfo.as b/src/nexus/utils/reflection/MethodParameterInfo.as index 1a6026b..16e4696 100644 --- a/src/nexus/utils/reflection/MethodParameterInfo.as +++ b/src/nexus/utils/reflection/MethodParameterInfo.as @@ -11,61 +11,61 @@ package nexus.utils.reflection */ public class MethodParameterInfo { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_type : Class; - private var m_typeName : String; - private var m_isOptional : Boolean; - private var m_position : int; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function MethodParameterInfo(type:Class, pos:int, isOptional:Boolean) - { - m_type = type; - m_position = pos; - m_isOptional = isOptional; - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - /** - * The type of this parameter. If the paramater is untyped, this will return null - */ - public function get type():Class { return m_type; } - - /** - * If the argument is optional to the method, that is, a default value is provided if the argument is not - */ - public function get isOptional():Boolean { return m_isOptional; } - - /** - * The zero-based position of the parameter in the parameter list - */ - public function get position():int { return m_position; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - public function toString():String - { - if(m_typeName == null) - { - m_typeName = Reflection.getUnqualifiedClassName(m_type); - } - return m_typeName; - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_type : Class; + private var m_typeName : String; + private var m_isOptional : Boolean; + private var m_position : int; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function MethodParameterInfo(type:Class, pos:int, isOptional:Boolean) + { + m_type = type; + m_position = pos; + m_isOptional = isOptional; + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + /** + * The type of this parameter. If the paramater is untyped, this will return null + */ + public function get type():Class { return m_type; } + + /** + * If the argument is optional to the method, that is, a default value is provided if the argument is not + */ + public function get isOptional():Boolean { return m_isOptional; } + + /** + * The zero-based position of the parameter in the parameter list + */ + public function get position():int { return m_position; } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + public function toString():String + { + if(m_typeName == null) + { + m_typeName = Reflection.getUnqualifiedClassName(m_type); + } + return m_typeName; + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/PropertyInfo.as b/src/nexus/utils/reflection/PropertyInfo.as index 3d6eb00..d02691a 100644 --- a/src/nexus/utils/reflection/PropertyInfo.as +++ b/src/nexus/utils/reflection/PropertyInfo.as @@ -13,39 +13,39 @@ import flash.utils.*; */ public final class PropertyInfo extends AbstractFieldInfo { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function PropertyInfo(name:String, isStatic:Boolean, type:Class, declaringType:Class, reflectedTypeInfo:TypeInfo, read:Boolean, write:Boolean) - { - super(name, isStatic, type, declaringType, reflectedTypeInfo, read, write); - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - override public function toString():String - { - if(m_typeName == null) - { - m_typeName = Reflection.getUnqualifiedClassName(m_type); - } - return "[" + (m_isStatic ? "Static" : "") + (m_canRead && m_canWrite ? "ReadWrite" : (m_canRead ? "ReadOnly" : "WriteOnly")) + "Property|" + m_name + ":" + m_typeName + "]"; - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function PropertyInfo(name:String, isStatic:Boolean, type:Class, declaringType:Class, reflectedTypeInfo:TypeInfo, read:Boolean, write:Boolean) + { + super(name, isStatic, type, declaringType, reflectedTypeInfo, read, write); + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + override public function toString():String + { + if(m_typeName == null) + { + m_typeName = Reflection.getUnqualifiedClassName(m_type); + } + return "[" + (m_isStatic ? "Static" : "") + (m_canRead && m_canWrite ? "ReadWrite" : (m_canRead ? "ReadOnly" : "WriteOnly")) + "Property|" + m_name + ":" + m_typeName + "]"; + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/Reflection.as b/src/nexus/utils/reflection/Reflection.as index 6053700..b4bec25 100644 --- a/src/nexus/utils/reflection/Reflection.as +++ b/src/nexus/utils/reflection/Reflection.as @@ -20,639 +20,639 @@ import nexus.utils.Parse; */ public final class Reflection { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //TODO: Probably need to do some checking here to make sure this is the domain we want - /** - * Reference this instead of ApplicationDomain.currentDomain as ApplicationDomain.currentDomain creates a new - * instance with each call. - */ - static public const SYSTEM_DOMAIN : ApplicationDomain = ApplicationDomain.currentDomain; - /** - * "__AS3__.vec::Vector" - */ - //call flash.utils.getQualifiedClassName(Vector) instead of hardcoding the string just in case Adobe ever changes the class or package - static private const VECTOR_PREFIX:String = flash.utils.getQualifiedClassName(Vector); - /** - * "__AS3__.vec::Vector.<*>" - */ - static private const UNTYPEDVECTOR_QUALIFIEDCLASSNAME:String = flash.utils.getQualifiedClassName(Vector.<*>); - /** - * "Vector.<*>" - */ - static private const UNTYPEDVECTOR_UNQUALIFIEDCLASSNAME:String = "Vector.<*>"; - - /** - * Used in applicationDomainsAreEqual to check for equality - */ - static private const EQUALITYTEST_DOMAINMEMORY:ByteArray = new ByteArray(); - - /** - * Cache all TypeInfo information so parsing in the describeType() call only happens once - */ - static private const CACHED_TYPEINFO:Dictionary = new Dictionary(true); - /** - * Cache all namespaces by their URI - */ - static private const CACHED_NAMESPACES:Dictionary = new Dictionary(); - - /** - * ApplicationDomains can be registered so they don't always have to be provided to Reflection methods - */ - static private const REGISTERED_APPDOMAINS : Vector. = new Vector.(); - - /** - * @private - * store strongly-typed classes that represent metadata on members - */ - static internal const REGISTERED_METADATA_CLASSES:Dictionary = new Dictionary(); - /** - * @private - */ - static internal const REGISTERED_METADATA_NAMES:Dictionary = new Dictionary(); - - //-------------------------------------- - // CLASS VARIABLES - //-------------------------------------- - - /** - * A flag for determining the allowed sources of type information. If the creators allowed by this flag are - * not present at runtime an exception is thrown. - * This is an advanced option. - * @default TYPEINFOCREATOR_NEW - * @see TYPEINFOCREATOR_NEW - * @see TYPEINFOCREATOR_OLD - */ - static nexuslib_internal var allowedTypeInfoCreators : int = nexuslib_internal::TYPEINFOCREATOR_NEW;// | nexuslib_internal::TYPEINFOCREATOR_OLD; - /** - * Used as a bitwise flag on allowedTypeInfoCreators to allow avmplus.describeTypeJson - * @see allowedTypeInfoCreators - * @see TYPEINFOCREATOR_OLD - */ - static nexuslib_internal const TYPEINFOCREATOR_NEW : int = 1; - /** - * Used as a bitwise flag on allowedTypeInfoCreators to allow flash.utils.describeType - * @see allowedTypeInfoCreators - * @see TYPEINFOCREATOR_NEW - */ - static nexuslib_internal const TYPEINFOCREATOR_OLD : int = 2; - - static private var s_typeInfoCreator : ITypeInfoCreator; - - //-------------------------------------- - // CLASS INITIAlIZER - //-------------------------------------- - - { - CACHED_TYPEINFO[SYSTEM_DOMAIN] = new Dictionary(); - EQUALITYTEST_DOMAINMEMORY.length = ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH; - } - - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - /** - * Returns a Class of the given object instance or the provided object itself if it is already a Class. - * @param object An object instance or Class - * @param applicationDomain The application domain in which to look for the class. ApplicationDomain.current is used if none is provided. - * @return The class for the given object, or null if none can be found - * @throws ClassNotFoundError If the class cannot be found in the provided ApplicationDomain (or the system ApplicationDomain if none is provided) - */ - public static function getClass(object:Object, applicationDomain:ApplicationDomain = null):Class - { - return object == null ? null : getClassByName(flash.utils.getQualifiedClassName(object), applicationDomain); - } - - /** - * Returns a class when provided a string formatted as a fully-qualified class name. If no application domain is provided, the system domain is used. - * @param qualifiedName A valid qualified class name. - * @param applicationDomain The application domain in which to look for the class. ApplicationDomain.current is used if none is provided. - * @return The class, or null if none can be found - * @throws ClassNotFoundError If the class cannot be found in the provided ApplicationDomain (or the system ApplicationDomain if none is provided) - */ - public static function getClassByName(qualifiedName:String, applicationDomain:ApplicationDomain = null):Class - { - if(qualifiedName == null || qualifiedName == "void" || qualifiedName == "undefined" || qualifiedName == "null") - { - return null; - } - else if(qualifiedName == "*" || qualifiedName == "Object") - { - return Object; - } - //looking up the class for an untyped vector currently does not work - else if(qualifiedName == UNTYPEDVECTOR_QUALIFIEDCLASSNAME || qualifiedName == UNTYPEDVECTOR_UNQUALIFIEDCLASSNAME) - { - return Class(Vector.<*>); - } - - if(applicationDomain == null) - { - applicationDomain = getApplicationDomainOfClassName(qualifiedName); - } - else - { - //walk up parent app domains to get the top-most reference - while(applicationDomain.parentDomain != null && applicationDomain.parentDomain.hasDefinition(qualifiedName)) - { - applicationDomain = applicationDomain.parentDomain; - } - } - - try - { - var result : Class = applicationDomain.getDefinition(qualifiedName) as Class; - if(result == null) - { - throw new ClassNotFoundError(qualifiedName); - } - return result; - } - catch(e:ReferenceError) - { - throw new ClassNotFoundError(qualifiedName); - } - return null; - } - - /** - * Gets the super/parent class of the provided object, with the caveat that getSuperClass(Object) == null - * @param object The object whose super class you want to find - * @param applicationDomain The application domain in which to look. ApplicationDomain.current is used if none is provided. - * @return The super class of the provided object or null if none can be found. - */ - public static function getSuperClass(object:Object, applicationDomain:ApplicationDomain = null):Class - { - if(object != null) - { - var superClassName:String = getQualifiedSuperclassName(object); - //superClassName will be null when the provided object argument is a native Object - if(superClassName != null) - { - return getClassByName(superClassName, applicationDomain); - } - } - return null; - } - - /** - * Finds the ApplicationDomain the given object blongs to. Any desired ApplicationDomains must be registered first with Reflection.registerApplicationDomain() - * @param object The object instance or Class to lookup - * @return The ApplicationDomain of the provided Object - * @throws Error If the object is present in several ApplicationDomains - */ - static public function getApplicationDomain(object:Object):ApplicationDomain - { - return getApplicationDomainOfClassName(flash.utils.getQualifiedClassName(object)); - } - - /** - * Finds the ApplicationDomain the given Class name blongs to. Any desired ApplicationDomains must be registered first with Reflection.registerApplicationDomain() - * @param qualifiedName The class name to lookup - * @return The ApplicationDomain of the provided Object - * @throws Error If the object is present in several ApplicationDomains - */ - static public function getApplicationDomainOfClassName(qualifiedName:String):ApplicationDomain - { - if( qualifiedName == null - || qualifiedName == "void" - || qualifiedName == "undefined" - || qualifiedName == "null" - || qualifiedName == "*" - || qualifiedName == "Object" - || qualifiedName == UNTYPEDVECTOR_QUALIFIEDCLASSNAME - || qualifiedName == UNTYPEDVECTOR_UNQUALIFIEDCLASSNAME) - { - return SYSTEM_DOMAIN; - } - - var applicationDomain : ApplicationDomain; - for each(var registeredAppDomain : ApplicationDomain in REGISTERED_APPDOMAINS) - { - if(registeredAppDomain.hasDefinition(qualifiedName)) - { - //if an app domain with this definition was already found, throw an error because we don't know which reference is desired - if(applicationDomain != null) - { - throw new Error("The desired class \"" + qualifiedName + "\" is found in two different registered ApplicationDomains."); - } - applicationDomain = registeredAppDomain; - } - } - return applicationDomain || SYSTEM_DOMAIN; - } - - /** - * Return the object type of the provided vector. If the provided vector is untyped (Vector.<*>), Object is returned. - * If the object is not a vector, null is returned. - * @param vector The vector instance or Class for which to determine its type - * @param applicationDomain The application domain in which to look. ApplicationDomain.current is used if none is provided. - * @return The type of the vector or Object if no type is present in the value provided - */ - public static function getVectorType(vector:Object, applicationDomain:ApplicationDomain = null):Class - { - var typeName:String = flash.utils.getQualifiedClassName(vector); - - if(typeName == UNTYPEDVECTOR_QUALIFIEDCLASSNAME) - { - return Object; - } - - if(typeName.substr(0, VECTOR_PREFIX.length) == VECTOR_PREFIX) - { - //parse out class between "__AS3__.vec::Vector.<" and ">" - return getClassByName(typeName.substring(VECTOR_PREFIX.length + 2, typeName.length - 1), applicationDomain); - } - - return null; - } - - /** - * Returns the fully qualified class name of an object. Convenience method that wraps flash.utils.getQualifiedClassName - * @param value The object for which a fully qualified class name is desired. - * @return A string containing the fully qualified class name. - */ - public static function getQualifiedClassName(value:Object):String - { - return flash.utils.getQualifiedClassName(value); - } - - /** - * Given a Class, object instance, or a fully qualified class name, this will return the class name without the package names attached. - * @example - * getUnqualifiedClassName(SomeClass) => "SomeClass" - * getUnqualifiedClassName(instanceOfSomeClass) => "SomeClass" - * getUnqualifiedClassName("com.example.as3::SomeClass") => "SomeClass" - * getUnqualifiedClassName("[class SomeClass]") => "SomeClass" - * getUnqualifiedClassName("foobar baz") => "String" - * - * @param object An object instance, a Class, or a String representing a class name - * @return - */ - public static function getUnqualifiedClassName(object:Object):String - { - var str:String; - //special handling of strings - if(object is String - //allow allow formatted class names to be provided - && (String(object).substr(0, 7) == "[class " || String(object).indexOf("::") != -1)) - { - str = String(object); - } - else if(object is Class) - { - str = object + ""; - } - else - { - str = flash.utils.getQualifiedClassName(object); - } - - //parse out class when in format "package.package.package::ClassName" - str = str.substring(str.lastIndexOf(":") + 1); - - //parse out class when in format "[class ClassName]" - var closingBracketIndex:int = str.lastIndexOf("]"); - if(closingBracketIndex != -1) - { - str = str.substring(str.lastIndexOf(" ") + 1, closingBracketIndex); - } - - return str; - } - - /** - * Useful if you have the Class object but not an instance of the Class. Returns false if the provided arguments are the same class. - * To check if a class implements an interface, get the TypeInfo of the class and check implementedInterfaces. - * @param potentialSubclass - * @param potentialSuperClass - * @param applicationDomain The application domain in which to look for these classes, ApplicationDomain.current is used if none is provided - * @return - */ - public static function classExtendsClass(potentialSubclass:Class, potentialSuperClass:Class, applicationDomain:ApplicationDomain = null):Boolean - { - //if the two classes are the same instance, one does not extend the other - if(potentialSubclass == null || potentialSuperClass == null || potentialSubclass == potentialSuperClass) - { - return false; - } - - //everything extends Object - if(potentialSuperClass == Object) - { - return true; - } - - while(potentialSubclass != Object) - { - try - { - potentialSubclass = getSuperClass(potentialSubclass, applicationDomain); - if(potentialSubclass == potentialSuperClass) - { - return true; - } - } - catch(e:ClassNotFoundError) - { - return false; - } - } - - return false; - } - - /** - * Checks it two application domains point to the same reference. - * Due to the implementation details of this method, it may cause issues in Flash versions > 11.2 due to new licensing restrictions - * Adobe is putting in place. - * see the announcement: http://blogs.adobe.com/flashplayer/2011/09/updates-from-the-lab.html - * see license information: http://www.adobe.com/devnet/flashplayer/articles/premium-features.html - * @param applicationDomainOne One of the ApplicationDomains to check for equality - * @param applicationDomainTwo One of the ApplicationDomains to check for equality - * @return True if the two provided application domains point to the same reference - */ - public static function areApplicationDomainsEqual(applicationDomainOne:ApplicationDomain, applicationDomainTwo:ApplicationDomain):Boolean - { - if(applicationDomainOne == null || applicationDomainTwo == null) - { - return false; - } - - if(applicationDomainOne == applicationDomainTwo) - { - return true; - } - - //Testing ApplicationDomains for equality is difficult since all methods that return ApplicationDomains return new instances - //for more information, see: http://hg.mozilla.org/tamarin-redux/file/tip/shell/DomainClass.cpp - - //The approach in use here is to assign a ByteArray to the domainMemory of both application domains and then compare them - //to one another. We can't just compare the domainMemory getters to one another directly without first assigning them because - //by default all application domains share a refernce to the same domainMemory, so they would always be equal. By first setting - //domainMemory, we change that reference for all equal app domains. - - var domainMemoryOne:ByteArray = applicationDomainOne.domainMemory; - - //assign a different ByteArray to domainMemory of the first app domain - applicationDomainOne.domainMemory = EQUALITYTEST_DOMAINMEMORY; - - //see if the second app domain is pointing to the same reference - var result:Boolean = applicationDomainOne.domainMemory == applicationDomainTwo.domainMemory; - - //restore the domain memory - applicationDomainOne.domainMemory = domainMemoryOne; - - return result; - } - - /** - * Registering an ApplicationDomain will result in it being checked for class references in any Reflection methods that take - * an ApplicationDomain as a parameter. - * @param applicationDomain - */ - static public function registerApplicationDomain(applicationDomain:ApplicationDomain):void - { - if(applicationDomain != null) - { - for each(var registeredDomain : ApplicationDomain in REGISTERED_APPDOMAINS) - { - if(Reflection.areApplicationDomainsEqual(applicationDomain, registeredDomain)) - { - return; - } - } - REGISTERED_APPDOMAINS.push(applicationDomain); - } - } - - /** - * Remove the provided ApplicationDomain from any reflection lookups. - * @param applicationDomain - */ - static public function unregisterApplicationDomain(applicationDomain:ApplicationDomain):void - { - if(applicationDomain != null) - { - for(var x : int = REGISTERED_APPDOMAINS.length - 1; x >= 0; --x) - { - var registeredDomain : ApplicationDomain = REGISTERED_APPDOMAINS[x]; - if(Reflection.areApplicationDomainsEqual(applicationDomain, registeredDomain)) - { - REGISTERED_APPDOMAINS.splice(x, 1); - delete CACHED_TYPEINFO[registeredDomain]; - return; - } - } - } - } - - /** - * Reflects into the given object and returns a TypeInfo object - * @param object The object or class to reflect - * @param applicationDomain The ApplicationDomain in which to reflect. If the provided object instance is in a different - * application domain than the one provided, the application domain's version of the class will be reflected. - * @return A TypeInfo that represents the given object or class - */ - public static function getTypeInfo(object:Object, applicationDomain:ApplicationDomain = null):TypeInfo - { - if(object == null) - { - return null; - } - - //get proper application domain instance to lookup in the dictionary - if(applicationDomain == null) - { - applicationDomain = getApplicationDomain(object); - } - - //see if the application domain already exists in the cache - var appDomainExists : Boolean = false; - for(var key : Object in CACHED_TYPEINFO) - { - if(Reflection.areApplicationDomainsEqual((key as ApplicationDomain), applicationDomain)) - { - applicationDomain = (key as ApplicationDomain); - appDomainExists = true; - break; - } - } - - if(!appDomainExists) - { - CACHED_TYPEINFO[applicationDomain] = new Dictionary(); - } - - var type:Class = getClass(object, applicationDomain); - var reflectedType:TypeInfo = CACHED_TYPEINFO[applicationDomain][type]; - if(reflectedType == null) - { - reflectedType = getTypeInfoInternal(type, applicationDomain); - //create and cache TypeInfo for the provided object if it is not present in the cache - CACHED_TYPEINFO[applicationDomain][type] = reflectedType; - } - return reflectedType; - } - - /** - * Check if the provided object is a scalar value or a Class of a scalar type. Where scalar is defined as one of - * int, uint, Number, Boolean, and String. - * @param value The object to test - * @return True if the provided object is a scalar value or a Class of a scalar type. - */ - public static function isScalar(value:Object):Boolean - { - return value is int || value == int - || value is uint || value == uint - || value is Number || value == Number - || value is String || value == String - || value is Boolean || value == Boolean; - } - - /** - * Check if the provided object is an instance of an Array or Vector or the class Array or a Vector Class - * @param value The object to test - * @return True if the provided object is an Array or Vector - */ - public static function isArrayType(value:Object):Boolean - { - return value is Array || value == Array || isVector(value); - } - - /** - * Check if the provided object is an instance of a Vector or a Vector Class - * @param value The object to test - * @return True if the provided object is a Vector - */ - public static function isVector(value:Object):Boolean - { - return (value is Class ? flash.utils.getQualifiedClassName(value).indexOf(VECTOR_PREFIX) != -1 : - value is Vector.<*> - || value is Vector. - || value is Vector. - || value is Vector.); - } - - /** - * Check if the provided object is a Dictionary or native Object - * @param value The object to test - * @return True if the provided object is a Dictionary or native Object - */ - public static function isAssociativeArray(value:Object):Boolean - { - if(value is Dictionary || value == Dictionary || value == Object) - { - return true; - } - - try - { - return getClass(value, SYSTEM_DOMAIN) == Object; - } - catch(e:ClassNotFoundError) - { - } - return false; - } - - /** - * Provide a class which extends MetadataInfo, and reflected TypeInfo will parse any - * matching metadata into an instance of the class provided instead of just MetadataInfo. - * @param type A class which must be a subclass of MetadataInfo - * @see MetadataInfo - */ - public static function registerMetadataClass(type:Class):void - { - if(!classExtendsClass(type, MetadataInfo)) - { - throw new ArgumentError("Cannot register metadata class \"" + type + "\", it does not extend " + MetadataInfo); - } - var name : String = Reflection.getQualifiedClassName(type); - REGISTERED_METADATA_CLASSES[name] = type; - REGISTERED_METADATA_NAMES[name] = Reflection.getUnqualifiedClassName(name); - } - - /** - * Provide a list of classes that extend Metadata and reflected TypeInfo will parse any matching metadata into - * and instance of the strongly-typed class provided. - * @param types A vector of classes, each of which must be a subclass of Metadata - */ - public static function registerMetadataClasses(types:Vector.):void - { - for each(var type:Class in types) - { - Reflection.registerMetadataClass(type); - } - } - - //-------------------------------------- - // INTERNAL CLASS METHODS - //-------------------------------------- - - /** - * Returns a TypeInfo without doing a cache lookup or any alteration of the application domain or object provided. - * - * @private - */ - static internal function getTypeInfoInternal(type:Class, applicationDomain:ApplicationDomain):TypeInfo - { - //get the typeinfo creator - if(s_typeInfoCreator == null) - { - use namespace nexuslib_internal; - if(AVMDescribeType.isAvailable && (allowedTypeInfoCreators & TYPEINFOCREATOR_NEW) == TYPEINFOCREATOR_NEW) - { - s_typeInfoCreator = new TypeInfoCreatorJson(); - } - else if((allowedTypeInfoCreators & TYPEINFOCREATOR_OLD) == TYPEINFOCREATOR_OLD) - { - s_typeInfoCreator = new TypeInfoCreatorXml(); - } - else - { - throw new IllegalOperationError("Cannot get type information for object, Flash 10.1 or higher is required. For more information, see the docs for Reflection.allowedTypeInfoCreators"); - } - } - return s_typeInfoCreator.create(type, applicationDomain); - } - - /** - * Returns the Metadata Class registered for the given instance. Faster than a getClass() lookup and - * ensures there are no ApplicationDomain-related issues. - * - * @private - */ - static internal function getMetadataClass(instance:MetadataInfo):Class - { - return REGISTERED_METADATA_CLASSES[Reflection.getQualifiedClassName(instance)]; - } - - /** - * Retrieves the cached Namespace for the given namespace URI - * - * @private - */ - static internal function getNamespace(namespaceUri:String):Namespace - { - var ns : Namespace; - if(namespaceUri != null) - { - ns = CACHED_NAMESPACES[namespaceUri]; - if(ns == null) - { - ns = new Namespace(namespaceUri); - CACHED_NAMESPACES[namespaceUri] = ns; - } - } - return ns; - } - - //-------------------------------------- - // PRIVATE CLASS METHODS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //TODO: Probably need to do some checking here to make sure this is the domain we want + /** + * Reference this instead of ApplicationDomain.currentDomain as ApplicationDomain.currentDomain creates a new + * instance with each call. + */ + static public const SYSTEM_DOMAIN : ApplicationDomain = ApplicationDomain.currentDomain; + /** + * "__AS3__.vec::Vector" + */ + //call flash.utils.getQualifiedClassName(Vector) instead of hardcoding the string just in case Adobe ever changes the class or package + static private const VECTOR_PREFIX:String = flash.utils.getQualifiedClassName(Vector); + /** + * "__AS3__.vec::Vector.<*>" + */ + static private const UNTYPEDVECTOR_QUALIFIEDCLASSNAME:String = flash.utils.getQualifiedClassName(Vector.<*>); + /** + * "Vector.<*>" + */ + static private const UNTYPEDVECTOR_UNQUALIFIEDCLASSNAME:String = "Vector.<*>"; + + /** + * Used in applicationDomainsAreEqual to check for equality + */ + static private const EQUALITYTEST_DOMAINMEMORY:ByteArray = new ByteArray(); + + /** + * Cache all TypeInfo information so parsing in the describeType() call only happens once + */ + static private const CACHED_TYPEINFO:Dictionary = new Dictionary(true); + /** + * Cache all namespaces by their URI + */ + static private const CACHED_NAMESPACES:Dictionary = new Dictionary(); + + /** + * ApplicationDomains can be registered so they don't always have to be provided to Reflection methods + */ + static private const REGISTERED_APPDOMAINS : Vector. = new Vector.(); + + /** + * @private + * store strongly-typed classes that represent metadata on members + */ + static internal const REGISTERED_METADATA_CLASSES:Dictionary = new Dictionary(); + /** + * @private + */ + static internal const REGISTERED_METADATA_NAMES:Dictionary = new Dictionary(); + + //-------------------------------------- + // CLASS VARIABLES + //-------------------------------------- + + /** + * A flag for determining the allowed sources of type information. If the creators allowed by this flag are + * not present at runtime an exception is thrown. + * This is an advanced option. + * @default TYPEINFOCREATOR_NEW + * @see TYPEINFOCREATOR_NEW + * @see TYPEINFOCREATOR_OLD + */ + static nexuslib_internal var allowedTypeInfoCreators : int = nexuslib_internal::TYPEINFOCREATOR_NEW;// | nexuslib_internal::TYPEINFOCREATOR_OLD; + /** + * Used as a bitwise flag on allowedTypeInfoCreators to allow avmplus.describeTypeJson + * @see allowedTypeInfoCreators + * @see TYPEINFOCREATOR_OLD + */ + static nexuslib_internal const TYPEINFOCREATOR_NEW : int = 1; + /** + * Used as a bitwise flag on allowedTypeInfoCreators to allow flash.utils.describeType + * @see allowedTypeInfoCreators + * @see TYPEINFOCREATOR_NEW + */ + static nexuslib_internal const TYPEINFOCREATOR_OLD : int = 2; + + static private var s_typeInfoCreator : ITypeInfoCreator; + + //-------------------------------------- + // CLASS INITIAlIZER + //-------------------------------------- + + { + CACHED_TYPEINFO[SYSTEM_DOMAIN] = new Dictionary(); + EQUALITYTEST_DOMAINMEMORY.length = ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH; + } + + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + /** + * Returns a Class of the given object instance or the provided object itself if it is already a Class. + * @param object An object instance or Class + * @param applicationDomain The application domain in which to look for the class. ApplicationDomain.current is used if none is provided. + * @return The class for the given object, or null if none can be found + * @throws ClassNotFoundError If the class cannot be found in the provided ApplicationDomain (or the system ApplicationDomain if none is provided) + */ + public static function getClass(object:Object, applicationDomain:ApplicationDomain = null):Class + { + return object == null ? null : getClassByName(flash.utils.getQualifiedClassName(object), applicationDomain); + } + + /** + * Returns a class when provided a string formatted as a fully-qualified class name. If no application domain is provided, the system domain is used. + * @param qualifiedName A valid qualified class name. + * @param applicationDomain The application domain in which to look for the class. ApplicationDomain.current is used if none is provided. + * @return The class, or null if none can be found + * @throws ClassNotFoundError If the class cannot be found in the provided ApplicationDomain (or the system ApplicationDomain if none is provided) + */ + public static function getClassByName(qualifiedName:String, applicationDomain:ApplicationDomain = null):Class + { + if(qualifiedName == null || qualifiedName == "void" || qualifiedName == "undefined" || qualifiedName == "null") + { + return null; + } + else if(qualifiedName == "*" || qualifiedName == "Object") + { + return Object; + } + //looking up the class for an untyped vector currently does not work + else if(qualifiedName == UNTYPEDVECTOR_QUALIFIEDCLASSNAME || qualifiedName == UNTYPEDVECTOR_UNQUALIFIEDCLASSNAME) + { + return Class(Vector.<*>); + } + + if(applicationDomain == null) + { + applicationDomain = getApplicationDomainOfClassName(qualifiedName); + } + else + { + //walk up parent app domains to get the top-most reference + while(applicationDomain.parentDomain != null && applicationDomain.parentDomain.hasDefinition(qualifiedName)) + { + applicationDomain = applicationDomain.parentDomain; + } + } + + try + { + var result : Class = applicationDomain.getDefinition(qualifiedName) as Class; + if(result == null) + { + throw new ClassNotFoundError(qualifiedName); + } + return result; + } + catch(e:ReferenceError) + { + throw new ClassNotFoundError(qualifiedName); + } + return null; + } + + /** + * Gets the super/parent class of the provided object, with the caveat that getSuperClass(Object) == null + * @param object The object whose super class you want to find + * @param applicationDomain The application domain in which to look. ApplicationDomain.current is used if none is provided. + * @return The super class of the provided object or null if none can be found. + */ + public static function getSuperClass(object:Object, applicationDomain:ApplicationDomain = null):Class + { + if(object != null) + { + var superClassName:String = getQualifiedSuperclassName(object); + //superClassName will be null when the provided object argument is a native Object + if(superClassName != null) + { + return getClassByName(superClassName, applicationDomain); + } + } + return null; + } + + /** + * Finds the ApplicationDomain the given object blongs to. Any desired ApplicationDomains must be registered first with Reflection.registerApplicationDomain() + * @param object The object instance or Class to lookup + * @return The ApplicationDomain of the provided Object + * @throws Error If the object is present in several ApplicationDomains + */ + static public function getApplicationDomain(object:Object):ApplicationDomain + { + return getApplicationDomainOfClassName(flash.utils.getQualifiedClassName(object)); + } + + /** + * Finds the ApplicationDomain the given Class name blongs to. Any desired ApplicationDomains must be registered first with Reflection.registerApplicationDomain() + * @param qualifiedName The class name to lookup + * @return The ApplicationDomain of the provided Object + * @throws Error If the object is present in several ApplicationDomains + */ + static public function getApplicationDomainOfClassName(qualifiedName:String):ApplicationDomain + { + if( qualifiedName == null + || qualifiedName == "void" + || qualifiedName == "undefined" + || qualifiedName == "null" + || qualifiedName == "*" + || qualifiedName == "Object" + || qualifiedName == UNTYPEDVECTOR_QUALIFIEDCLASSNAME + || qualifiedName == UNTYPEDVECTOR_UNQUALIFIEDCLASSNAME) + { + return SYSTEM_DOMAIN; + } + + var applicationDomain : ApplicationDomain; + for each(var registeredAppDomain : ApplicationDomain in REGISTERED_APPDOMAINS) + { + if(registeredAppDomain.hasDefinition(qualifiedName)) + { + //if an app domain with this definition was already found, throw an error because we don't know which reference is desired + if(applicationDomain != null) + { + throw new Error("The desired class \"" + qualifiedName + "\" is found in two different registered ApplicationDomains."); + } + applicationDomain = registeredAppDomain; + } + } + return applicationDomain || SYSTEM_DOMAIN; + } + + /** + * Return the object type of the provided vector. If the provided vector is untyped (Vector.<*>), Object is returned. + * If the object is not a vector, null is returned. + * @param vector The vector instance or Class for which to determine its type + * @param applicationDomain The application domain in which to look. ApplicationDomain.current is used if none is provided. + * @return The type of the vector or Object if no type is present in the value provided + */ + public static function getVectorType(vector:Object, applicationDomain:ApplicationDomain = null):Class + { + var typeName:String = flash.utils.getQualifiedClassName(vector); + + if(typeName == UNTYPEDVECTOR_QUALIFIEDCLASSNAME) + { + return Object; + } + + if(typeName.substr(0, VECTOR_PREFIX.length) == VECTOR_PREFIX) + { + //parse out class between "__AS3__.vec::Vector.<" and ">" + return getClassByName(typeName.substring(VECTOR_PREFIX.length + 2, typeName.length - 1), applicationDomain); + } + + return null; + } + + /** + * Returns the fully qualified class name of an object. Convenience method that wraps flash.utils.getQualifiedClassName + * @param value The object for which a fully qualified class name is desired. + * @return A string containing the fully qualified class name. + */ + public static function getQualifiedClassName(value:Object):String + { + return flash.utils.getQualifiedClassName(value); + } + + /** + * Given a Class, object instance, or a fully qualified class name, this will return the class name without the package names attached. + * @example + * getUnqualifiedClassName(SomeClass) => "SomeClass" + * getUnqualifiedClassName(instanceOfSomeClass) => "SomeClass" + * getUnqualifiedClassName("com.example.as3::SomeClass") => "SomeClass" + * getUnqualifiedClassName("[class SomeClass]") => "SomeClass" + * getUnqualifiedClassName("foobar baz") => "String" + * + * @param object An object instance, a Class, or a String representing a class name + * @return + */ + public static function getUnqualifiedClassName(object:Object):String + { + var str:String; + //special handling of strings + if(object is String + //allow allow formatted class names to be provided + && (String(object).substr(0, 7) == "[class " || String(object).indexOf("::") != -1)) + { + str = String(object); + } + else if(object is Class) + { + str = object + ""; + } + else + { + str = flash.utils.getQualifiedClassName(object); + } + + //parse out class when in format "package.package.package::ClassName" + str = str.substring(str.lastIndexOf(":") + 1); + + //parse out class when in format "[class ClassName]" + var closingBracketIndex:int = str.lastIndexOf("]"); + if(closingBracketIndex != -1) + { + str = str.substring(str.lastIndexOf(" ") + 1, closingBracketIndex); + } + + return str; + } + + /** + * Useful if you have the Class object but not an instance of the Class. Returns false if the provided arguments are the same class. + * To check if a class implements an interface, get the TypeInfo of the class and check implementedInterfaces. + * @param potentialSubclass + * @param potentialSuperClass + * @param applicationDomain The application domain in which to look for these classes, ApplicationDomain.current is used if none is provided + * @return + */ + public static function classExtendsClass(potentialSubclass:Class, potentialSuperClass:Class, applicationDomain:ApplicationDomain = null):Boolean + { + //if the two classes are the same instance, one does not extend the other + if(potentialSubclass == null || potentialSuperClass == null || potentialSubclass == potentialSuperClass) + { + return false; + } + + //everything extends Object + if(potentialSuperClass == Object) + { + return true; + } + + while(potentialSubclass != Object) + { + try + { + potentialSubclass = getSuperClass(potentialSubclass, applicationDomain); + if(potentialSubclass == potentialSuperClass) + { + return true; + } + } + catch(e:ClassNotFoundError) + { + return false; + } + } + + return false; + } + + /** + * Checks it two application domains point to the same reference. + * Due to the implementation details of this method, it may cause issues in Flash versions > 11.2 due to new licensing restrictions + * Adobe is putting in place. + * see the announcement: http://blogs.adobe.com/flashplayer/2011/09/updates-from-the-lab.html + * see license information: http://www.adobe.com/devnet/flashplayer/articles/premium-features.html + * @param applicationDomainOne One of the ApplicationDomains to check for equality + * @param applicationDomainTwo One of the ApplicationDomains to check for equality + * @return True if the two provided application domains point to the same reference + */ + public static function areApplicationDomainsEqual(applicationDomainOne:ApplicationDomain, applicationDomainTwo:ApplicationDomain):Boolean + { + if(applicationDomainOne == null || applicationDomainTwo == null) + { + return false; + } + + if(applicationDomainOne == applicationDomainTwo) + { + return true; + } + + //Testing ApplicationDomains for equality is difficult since all methods that return ApplicationDomains return new instances + //for more information, see: http://hg.mozilla.org/tamarin-redux/file/tip/shell/DomainClass.cpp + + //The approach in use here is to assign a ByteArray to the domainMemory of both application domains and then compare them + //to one another. We can't just compare the domainMemory getters to one another directly without first assigning them because + //by default all application domains share a refernce to the same domainMemory, so they would always be equal. By first setting + //domainMemory, we change that reference for all equal app domains. + + var domainMemoryOne:ByteArray = applicationDomainOne.domainMemory; + + //assign a different ByteArray to domainMemory of the first app domain + applicationDomainOne.domainMemory = EQUALITYTEST_DOMAINMEMORY; + + //see if the second app domain is pointing to the same reference + var result:Boolean = applicationDomainOne.domainMemory == applicationDomainTwo.domainMemory; + + //restore the domain memory + applicationDomainOne.domainMemory = domainMemoryOne; + + return result; + } + + /** + * Registering an ApplicationDomain will result in it being checked for class references in any Reflection methods that take + * an ApplicationDomain as a parameter. + * @param applicationDomain + */ + static public function registerApplicationDomain(applicationDomain:ApplicationDomain):void + { + if(applicationDomain != null) + { + for each(var registeredDomain : ApplicationDomain in REGISTERED_APPDOMAINS) + { + if(Reflection.areApplicationDomainsEqual(applicationDomain, registeredDomain)) + { + return; + } + } + REGISTERED_APPDOMAINS.push(applicationDomain); + } + } + + /** + * Remove the provided ApplicationDomain from any reflection lookups. + * @param applicationDomain + */ + static public function unregisterApplicationDomain(applicationDomain:ApplicationDomain):void + { + if(applicationDomain != null) + { + for(var x : int = REGISTERED_APPDOMAINS.length - 1; x >= 0; --x) + { + var registeredDomain : ApplicationDomain = REGISTERED_APPDOMAINS[x]; + if(Reflection.areApplicationDomainsEqual(applicationDomain, registeredDomain)) + { + REGISTERED_APPDOMAINS.splice(x, 1); + delete CACHED_TYPEINFO[registeredDomain]; + return; + } + } + } + } + + /** + * Reflects into the given object and returns a TypeInfo object + * @param object The object or class to reflect + * @param applicationDomain The ApplicationDomain in which to reflect. If the provided object instance is in a different + * application domain than the one provided, the application domain's version of the class will be reflected. + * @return A TypeInfo that represents the given object or class + */ + public static function getTypeInfo(object:Object, applicationDomain:ApplicationDomain = null):TypeInfo + { + if(object == null) + { + return null; + } + + //get proper application domain instance to lookup in the dictionary + if(applicationDomain == null) + { + applicationDomain = getApplicationDomain(object); + } + + //see if the application domain already exists in the cache + var appDomainExists : Boolean = false; + for(var key : Object in CACHED_TYPEINFO) + { + if(Reflection.areApplicationDomainsEqual((key as ApplicationDomain), applicationDomain)) + { + applicationDomain = (key as ApplicationDomain); + appDomainExists = true; + break; + } + } + + if(!appDomainExists) + { + CACHED_TYPEINFO[applicationDomain] = new Dictionary(); + } + + var type:Class = getClass(object, applicationDomain); + var reflectedType:TypeInfo = CACHED_TYPEINFO[applicationDomain][type]; + if(reflectedType == null) + { + reflectedType = getTypeInfoInternal(type, applicationDomain); + //create and cache TypeInfo for the provided object if it is not present in the cache + CACHED_TYPEINFO[applicationDomain][type] = reflectedType; + } + return reflectedType; + } + + /** + * Check if the provided object is a scalar value or a Class of a scalar type. Where scalar is defined as one of + * int, uint, Number, Boolean, and String. + * @param value The object to test + * @return True if the provided object is a scalar value or a Class of a scalar type. + */ + public static function isScalar(value:Object):Boolean + { + return value is int || value == int + || value is uint || value == uint + || value is Number || value == Number + || value is String || value == String + || value is Boolean || value == Boolean; + } + + /** + * Check if the provided object is an instance of an Array or Vector or the class Array or a Vector Class + * @param value The object to test + * @return True if the provided object is an Array or Vector + */ + public static function isArrayType(value:Object):Boolean + { + return value is Array || value == Array || isVector(value); + } + + /** + * Check if the provided object is an instance of a Vector or a Vector Class + * @param value The object to test + * @return True if the provided object is a Vector + */ + public static function isVector(value:Object):Boolean + { + return (value is Class ? flash.utils.getQualifiedClassName(value).indexOf(VECTOR_PREFIX) != -1 : + value is Vector.<*> + || value is Vector. + || value is Vector. + || value is Vector.); + } + + /** + * Check if the provided object is a Dictionary or native Object + * @param value The object to test + * @return True if the provided object is a Dictionary or native Object + */ + public static function isAssociativeArray(value:Object):Boolean + { + if(value is Dictionary || value == Dictionary || value == Object) + { + return true; + } + + try + { + return getClass(value, SYSTEM_DOMAIN) == Object; + } + catch(e:ClassNotFoundError) + { + } + return false; + } + + /** + * Provide a class which extends MetadataInfo, and reflected TypeInfo will parse any + * matching metadata into an instance of the class provided instead of just MetadataInfo. + * @param type A class which must be a subclass of MetadataInfo + * @see MetadataInfo + */ + public static function registerMetadataClass(type:Class):void + { + if(!classExtendsClass(type, MetadataInfo)) + { + throw new ArgumentError("Cannot register metadata class \"" + type + "\", it does not extend " + MetadataInfo); + } + var name : String = Reflection.getQualifiedClassName(type); + REGISTERED_METADATA_CLASSES[name] = type; + REGISTERED_METADATA_NAMES[name] = Reflection.getUnqualifiedClassName(name); + } + + /** + * Provide a list of classes that extend Metadata and reflected TypeInfo will parse any matching metadata into + * and instance of the strongly-typed class provided. + * @param types A vector of classes, each of which must be a subclass of Metadata + */ + public static function registerMetadataClasses(types:Vector.):void + { + for each(var type:Class in types) + { + Reflection.registerMetadataClass(type); + } + } + + //-------------------------------------- + // INTERNAL CLASS METHODS + //-------------------------------------- + + /** + * Returns a TypeInfo without doing a cache lookup or any alteration of the application domain or object provided. + * + * @private + */ + static internal function getTypeInfoInternal(type:Class, applicationDomain:ApplicationDomain):TypeInfo + { + //get the typeinfo creator + if(s_typeInfoCreator == null) + { + use namespace nexuslib_internal; + if(AVMDescribeType.isAvailable && (allowedTypeInfoCreators & TYPEINFOCREATOR_NEW) == TYPEINFOCREATOR_NEW) + { + s_typeInfoCreator = new TypeInfoCreatorJson(); + } + else if((allowedTypeInfoCreators & TYPEINFOCREATOR_OLD) == TYPEINFOCREATOR_OLD) + { + s_typeInfoCreator = new TypeInfoCreatorXml(); + } + else + { + throw new IllegalOperationError("Cannot get type information for object, Flash 10.1 or higher is required. For more information, see the docs for Reflection.allowedTypeInfoCreators"); + } + } + return s_typeInfoCreator.create(type, applicationDomain); + } + + /** + * Returns the Metadata Class registered for the given instance. Faster than a getClass() lookup and + * ensures there are no ApplicationDomain-related issues. + * + * @private + */ + static internal function getMetadataClass(instance:MetadataInfo):Class + { + return REGISTERED_METADATA_CLASSES[Reflection.getQualifiedClassName(instance)]; + } + + /** + * Retrieves the cached Namespace for the given namespace URI + * + * @private + */ + static internal function getNamespace(namespaceUri:String):Namespace + { + var ns : Namespace; + if(namespaceUri != null) + { + ns = CACHED_NAMESPACES[namespaceUri]; + if(ns == null) + { + ns = new Namespace(namespaceUri); + CACHED_NAMESPACES[namespaceUri] = ns; + } + } + return ns; + } + + //-------------------------------------- + // PRIVATE CLASS METHODS + //-------------------------------------- +} } -} \ No newline at end of file diff --git a/src/nexus/utils/reflection/TypeInfo.as b/src/nexus/utils/reflection/TypeInfo.as index 280cda7..4b01de8 100644 --- a/src/nexus/utils/reflection/TypeInfo.as +++ b/src/nexus/utils/reflection/TypeInfo.as @@ -14,270 +14,270 @@ import flash.utils.*; */ public final class TypeInfo extends AbstractMetadataRecipient { - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_type:Class; - - private var m_isDynamic : Boolean; - private var m_isFinal : Boolean; - - private var m_applicationDomain : ApplicationDomain; - - private var m_inheritedInterfaces : Vector.; - private var m_extendedClasses : Vector.; - - private var m_constructor : MethodInfo; - - private var m_methods : Vector.; - private var m_methodsIndex : int; - - private var m_properties : Vector.; - private var m_propertiesIndex : int; - - private var m_fields : Vector.; - private var m_fieldsIndex : int; - - private var m_allMembers : Vector.; - private var m_allMembersSortedByName : Vector.; - private var m_allMembersSortedByPosition : Vector.; - - private var m_allMembersByName : Dictionary; - private var m_allMemberNames : Vector.; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function TypeInfo(name:String, appDomain:ApplicationDomain, type:Class, methodCount:int, propertyCount:int, fieldCount:int) - { - super(name); - - m_type = type; - - m_applicationDomain = appDomain; - - m_allMembers = new Vector.(); - m_allMemberNames = new Vector.(); - m_allMembersByName = new Dictionary(); - - m_inheritedInterfaces = new Vector.(); - m_extendedClasses = new Vector.(); - - m_methods = new Vector.(methodCount, true); - m_properties = new Vector.(propertyCount, true); - m_fields = new Vector.(fieldCount, true); - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - public function get type():Class { return m_type; } - - public function get isDynamic():Boolean { return m_isDynamic; } - - public function get isFinal():Boolean { return m_isFinal; } - - public function get implementedInterfaces():Vector. { return m_inheritedInterfaces; } - - public function get extendedClasses():Vector. { return m_extendedClasses; } - - public function get methods():Vector. { return m_methods; } - - public function get properties():Vector. { return m_properties; } - - public function get fields():Vector. { return m_fields; } - - public function get constructor():MethodInfo { return m_constructor; } - - /** - * The application domain this object is a part of - */ - public function get applicationDomain():ApplicationDomain { return m_applicationDomain; } - - public function get allMembers():Vector. { return m_allMembers; } - - /** - * Returns members, sorted according to their internal position in the reflected TypeInfo - */ - public function get allMembersSortedByPosition():Vector. - { - if(m_allMembersSortedByPosition == null) - { - m_allMembersSortedByPosition = m_allMembers.sort(positionSort); - } - return m_allMembersSortedByPosition; - } - - /** - * Returns members, sorted according to their name - */ - public function get allMembersSortedByName():Vector. - { - if(m_allMembersSortedByName == null) - { - m_allMembersSortedByName = m_allMembers.sort(nameSort); - } - return m_allMembersSortedByName; - } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - public function toString(verbose:Boolean = false):String - { - return "[" + m_name + "]"; - } - - public function getMemberByName(name:String):AbstractMemberInfo - { - return m_allMembersByName[name]; - } - - public function getMethodByName(name:String):MethodInfo - { - return m_allMembersByName[name] as MethodInfo; - } - - public function getPropertyByName(name:String):PropertyInfo - { - return m_allMembersByName[name] as PropertyInfo; - } - - public function getFieldByName(name:String):FieldInfo - { - return m_allMembersByName[name] as FieldInfo; - } - - /** - * Warning! This is a very costly sort that needs to get the TypeInfo for the entire inheritance chain. Sorts members according - * to the type that declares them - */ - public function sortMembersByDeclaringType():void - { - //malachi: really need to figure out a way to streamline this method - var superTypes : Vector. = new Vector.(); - for each(var superClass : Class in m_extendedClasses) - { - superTypes.push(Reflection.getTypeInfo(superClass, m_applicationDomain)); - } - superTypes.push(this); - - var fieldsChecked : Dictionary = new Dictionary(true); - var fieldsInOrder : Vector. = new Vector.(); - for each(var superType : TypeInfo in superTypes) - { - var superclassFields : Vector. = new Vector.(); - for each(var field : FieldInfo in superType.fields) - { - if(fieldsChecked[field.name] != true) - { - for each(var memberField : FieldInfo in m_fields) - { - if(memberField.name == field.name) - { - superclassFields.push(memberField); - fieldsChecked[memberField.name] = true; - break; - } - } - } - } - fieldsInOrder = fieldsInOrder.concat(superclassFields.sort(positionSort)); - } - m_fields = fieldsInOrder; - - m_methods.sort(declaringTypeSort); - m_properties.sort(declaringTypeSort); - } - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- - - private function declaringTypeSort(l:AbstractMemberInfo, r:AbstractMemberInfo):Number - { - if(l.declaringType == r.declaringType) - { - return positionSort(l, r); - } - else if(l.reflectedFrom.extendedClasses.indexOf(l.declaringType) < r.reflectedFrom.extendedClasses.indexOf(r.declaringType)) - { - return -1; - } - else - { - return 1; - } - } - - private function positionSort(l:AbstractMemberInfo, r:AbstractMemberInfo):Number - { - return l.position < r.position ? -1 : (r.position < l.position ? 1 : nameSort(l, r)); - } - - private function nameSort(l:AbstractMemberInfo, r:AbstractMemberInfo):Number - { - return l.name < r.name ? -1 : (r.name < l.name ? 1 : 0); - } - - //-------------------------------------- - // INTERNAL INSTANCE METHODS - //-------------------------------------- - - /** - * @private - */ - internal function setIsDynamic(value:Boolean):void - { - m_isDynamic = value; - } - - /** - * @private - */ - internal function setIsFinal(value:Boolean):void - { - m_isFinal = value; - } - - /** - * @private - */ - internal function setConstructor(constructor:MethodInfo):void - { - m_constructor = constructor; - } - - /** - * @private - */ - internal function addMember(member:AbstractMemberInfo):void - { - if(member is PropertyInfo) - { - m_properties[m_propertiesIndex++] = PropertyInfo(member); - } - else if(member is FieldInfo) - { - m_fields[m_fieldsIndex++] = FieldInfo(member); - } - else if(member is MethodInfo) - { - m_methods[m_methodsIndex++] = MethodInfo(member); - } - else - { - throw new ArgumentError("Cannot add unknown member type \"" + member + "\" to this TypeInfo."); - } - - m_allMembers.push(member); - m_allMemberNames.push(member.name); - m_allMembersByName[member.name] = member; - } + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_type:Class; + + private var m_isDynamic : Boolean; + private var m_isFinal : Boolean; + + private var m_applicationDomain : ApplicationDomain; + + private var m_inheritedInterfaces : Vector.; + private var m_extendedClasses : Vector.; + + private var m_constructor : MethodInfo; + + private var m_methods : Vector.; + private var m_methodsIndex : int; + + private var m_properties : Vector.; + private var m_propertiesIndex : int; + + private var m_fields : Vector.; + private var m_fieldsIndex : int; + + private var m_allMembers : Vector.; + private var m_allMembersSortedByName : Vector.; + private var m_allMembersSortedByPosition : Vector.; + + private var m_allMembersByName : Dictionary; + private var m_allMemberNames : Vector.; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function TypeInfo(name:String, appDomain:ApplicationDomain, type:Class, methodCount:int, propertyCount:int, fieldCount:int) + { + super(name); + + m_type = type; + + m_applicationDomain = appDomain; + + m_allMembers = new Vector.(); + m_allMemberNames = new Vector.(); + m_allMembersByName = new Dictionary(); + + m_inheritedInterfaces = new Vector.(); + m_extendedClasses = new Vector.(); + + m_methods = new Vector.(methodCount, true); + m_properties = new Vector.(propertyCount, true); + m_fields = new Vector.(fieldCount, true); + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + public function get type():Class { return m_type; } + + public function get isDynamic():Boolean { return m_isDynamic; } + + public function get isFinal():Boolean { return m_isFinal; } + + public function get implementedInterfaces():Vector. { return m_inheritedInterfaces; } + + public function get extendedClasses():Vector. { return m_extendedClasses; } + + public function get methods():Vector. { return m_methods; } + + public function get properties():Vector. { return m_properties; } + + public function get fields():Vector. { return m_fields; } + + public function get constructor():MethodInfo { return m_constructor; } + + /** + * The application domain this object is a part of + */ + public function get applicationDomain():ApplicationDomain { return m_applicationDomain; } + + public function get allMembers():Vector. { return m_allMembers; } + + /** + * Returns members, sorted according to their internal position in the reflected TypeInfo + */ + public function get allMembersSortedByPosition():Vector. + { + if(m_allMembersSortedByPosition == null) + { + m_allMembersSortedByPosition = m_allMembers.sort(positionSort); + } + return m_allMembersSortedByPosition; + } + + /** + * Returns members, sorted according to their name + */ + public function get allMembersSortedByName():Vector. + { + if(m_allMembersSortedByName == null) + { + m_allMembersSortedByName = m_allMembers.sort(nameSort); + } + return m_allMembersSortedByName; + } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + public function toString(verbose:Boolean = false):String + { + return "[" + m_name + "]"; + } + + public function getMemberByName(name:String):AbstractMemberInfo + { + return m_allMembersByName[name]; + } + + public function getMethodByName(name:String):MethodInfo + { + return m_allMembersByName[name] as MethodInfo; + } + + public function getPropertyByName(name:String):PropertyInfo + { + return m_allMembersByName[name] as PropertyInfo; + } + + public function getFieldByName(name:String):FieldInfo + { + return m_allMembersByName[name] as FieldInfo; + } + + /** + * Warning! This is a very costly sort that needs to get the TypeInfo for the entire inheritance chain. Sorts members according + * to the type that declares them + */ + public function sortMembersByDeclaringType():void + { + //malachi: really need to figure out a way to streamline this method + var superTypes : Vector. = new Vector.(); + for each(var superClass : Class in m_extendedClasses) + { + superTypes.push(Reflection.getTypeInfo(superClass, m_applicationDomain)); + } + superTypes.push(this); + + var fieldsChecked : Dictionary = new Dictionary(true); + var fieldsInOrder : Vector. = new Vector.(); + for each(var superType : TypeInfo in superTypes) + { + var superclassFields : Vector. = new Vector.(); + for each(var field : FieldInfo in superType.fields) + { + if(fieldsChecked[field.name] != true) + { + for each(var memberField : FieldInfo in m_fields) + { + if(memberField.name == field.name) + { + superclassFields.push(memberField); + fieldsChecked[memberField.name] = true; + break; + } + } + } + } + fieldsInOrder = fieldsInOrder.concat(superclassFields.sort(positionSort)); + } + m_fields = fieldsInOrder; + + m_methods.sort(declaringTypeSort); + m_properties.sort(declaringTypeSort); + } + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- + + private function declaringTypeSort(l:AbstractMemberInfo, r:AbstractMemberInfo):Number + { + if(l.declaringType == r.declaringType) + { + return positionSort(l, r); + } + else if(l.reflectedFrom.extendedClasses.indexOf(l.declaringType) < r.reflectedFrom.extendedClasses.indexOf(r.declaringType)) + { + return -1; + } + else + { + return 1; + } + } + + private function positionSort(l:AbstractMemberInfo, r:AbstractMemberInfo):Number + { + return l.position < r.position ? -1 : (r.position < l.position ? 1 : nameSort(l, r)); + } + + private function nameSort(l:AbstractMemberInfo, r:AbstractMemberInfo):Number + { + return l.name < r.name ? -1 : (r.name < l.name ? 1 : 0); + } + + //-------------------------------------- + // INTERNAL INSTANCE METHODS + //-------------------------------------- + + /** + * @private + */ + internal function setIsDynamic(value:Boolean):void + { + m_isDynamic = value; + } + + /** + * @private + */ + internal function setIsFinal(value:Boolean):void + { + m_isFinal = value; + } + + /** + * @private + */ + internal function setConstructor(constructor:MethodInfo):void + { + m_constructor = constructor; + } + + /** + * @private + */ + internal function addMember(member:AbstractMemberInfo):void + { + if(member is PropertyInfo) + { + m_properties[m_propertiesIndex++] = PropertyInfo(member); + } + else if(member is FieldInfo) + { + m_fields[m_fieldsIndex++] = FieldInfo(member); + } + else if(member is MethodInfo) + { + m_methods[m_methodsIndex++] = MethodInfo(member); + } + else + { + throw new ArgumentError("Cannot add unknown member type \"" + member + "\" to this TypeInfo."); + } + + m_allMembers.push(member); + m_allMemberNames.push(member.name); + m_allMembersByName[member.name] = member; + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/TypeInfoCreatorJson.as b/src/nexus/utils/reflection/TypeInfoCreatorJson.as index aa747da..318c182 100644 --- a/src/nexus/utils/reflection/TypeInfoCreatorJson.as +++ b/src/nexus/utils/reflection/TypeInfoCreatorJson.as @@ -21,178 +21,178 @@ import nexus.utils.Parse; */ internal class TypeInfoCreatorJson implements ITypeInfoCreator { - //-------------------------------------- - // PUBLIC STATIC METHODS - //-------------------------------------- - - public function create(type:Class, applicationDomain:ApplicationDomain):TypeInfo - { - var json : Object = AVMDescribeType.getJson(type); - var x : int; - - var reflectedType:TypeInfo = new TypeInfo(json.factory.name, applicationDomain, type, - json.methods.length + json.factory.methods.length, - json.accessors.length + json.factory.accessors.length, - json.variables.length + json.factory.variables.length); - - reflectedType.setIsDynamic(json.factory.isDynamic); - reflectedType.setIsFinal(json.factory.isFinal); - - addMetadata(reflectedType, json.factory); - - //add constructor - reflectedType.setConstructor(parseConstructorInfo(json.factory.constructor, reflectedType, applicationDomain)); - - //add fields - addMembers(parseFieldInfo, json.variables, reflectedType, applicationDomain, true); - addMembers(parseFieldInfo, json.factory.variables, reflectedType, applicationDomain, false); - - //add methods - addMembers(parseMethodInfo, json.methods, reflectedType, applicationDomain, true); - addMembers(parseMethodInfo, json.factory.methods, reflectedType, applicationDomain, false); - - //add properties - addMembers(parsePropertyInfo, json.accessors, reflectedType, applicationDomain, true); - addMembers(parsePropertyInfo, json.factory.accessors, reflectedType, applicationDomain, false); - - for(x = 0; x < json.factory.bases.length; ++x) - { - reflectedType.extendedClasses.push(Reflection.getClassByName(json.factory.bases[x], applicationDomain)); - } - - for(x = 0; x < json.factory.interfaces.length; ++x) - { - reflectedType.implementedInterfaces.push(Reflection.getClassByName(json.factory.interfaces[x], applicationDomain)); - } - - json = null; - - return reflectedType; - } - - //-------------------------------------- - // PRIVATE CLASS METHODS - //-------------------------------------- - - private static function addMembers(method:Function, members:Array, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean):void - { - for each(var member:Object in members) - { - var memberInfo:AbstractMemberInfo = method(member, typeInfo, appDomain, isStatic); - if(memberInfo != null) - { - addMetadata(memberInfo, member); - memberInfo.assignNamespace(Reflection.getNamespace(member.uri)); - typeInfo.addMember(memberInfo); - } - } - } - - static private function parsePropertyInfo(object:Object, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean):PropertyInfo - { - var property:PropertyInfo; - var name:String = object.name; - if(name == "prototype") - { - typeInfo.properties.fixed = false; - typeInfo.properties.length--; - typeInfo.properties.fixed = true; - } - else - { - var access:String = object.access; - var canRead : Boolean = access == "readonly" || access == "readwrite"; - var canWrite : Boolean = access == "writeonly" || access == "readwrite"; - property = new PropertyInfo(name, isStatic, Reflection.getClassByName(object.type, appDomain), Reflection.getClassByName(object.declaredBy, appDomain), - typeInfo, canRead, canWrite); - } - return property; - } - - static private function parseFieldInfo(object:Object, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean):FieldInfo - { - //TODO: support adding "declaredBy" field. It will require recursing through all superclass TypeInfos looking for the first appearance - return new FieldInfo(object.name, isStatic, Reflection.getClassByName(object.type, appDomain), null, typeInfo, object.access == "readwrite"); - } - - static private function parseMethodInfo(object:Object, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean):MethodInfo - { - var method:MethodInfo = new MethodInfo(object.name, isStatic, Reflection.getClassByName(object.returnType, appDomain), Reflection.getClassByName(object.declaredBy, appDomain), typeInfo, object.parameters.length); - for(var x : int = 0; x < object.parameters.length; ++x) - { - var param:Object = object.parameters[x]; - method.addMethodParameter(new MethodParameterInfo(Reflection.getClassByName(param.type, appDomain), x, param.optional)); - } - return method; - } - - static private function parseConstructorInfo(params:Array, typeInfo:TypeInfo, appDomain:ApplicationDomain):MethodInfo - { - var method:MethodInfo = new MethodInfo("_ctor", true, null, typeInfo.type, typeInfo, params.length); - for(var x : int = 0; x < params.length; ++x) - { - var param:Object = params[x]; - method.addMethodParameter(new MethodParameterInfo(Reflection.getClassByName(param.type, appDomain), x, param.optional)); - } - return method; - } - - static private function addMetadata(member:AbstractMetadataRecipient, sourceObject:Object):void - { - var metadataArray:Array = sourceObject.metadata; - /* - { - "name": "MetadataName", - "value": [ - {"key":"param","value":"value"}, - {"key":"param2","value":"value2"} - ] - } - //*/ - //add metadata - for each(var metadataObject:Object in metadataArray) - { - var metadataName : String = metadataObject.name; - //this is a default matadata tag added by the compiler in a debug build - if(metadataName == "__go_to_definition_help") - { - member.setPosition(parseInt(metadataObject.value[0].value)); - } - else if(metadataName == "__go_to_ctor_definition_help") - { - //just drop this - } - else - { - var metadata:MetadataInfo = null; - var metadataDict : Dictionary = new Dictionary(); - for each(var keyValuePair:Object in metadataObject.value) - { - metadataDict[keyValuePair["key"]] = keyValuePair["value"]; - } - - //see if there is a registered strongly-typed class for this metadata - for(var qualifiedName:String in Reflection.REGISTERED_METADATA_CLASSES) - { - var unqualifiedName : String = Reflection.REGISTERED_METADATA_NAMES[qualifiedName]; - //implementers of metadata should omit the "Metadata" suffix, it is added here - if(metadataName == unqualifiedName || metadataName + "Metadata" == unqualifiedName) - { - metadata = new Reflection.REGISTERED_METADATA_CLASSES[qualifiedName](metadataName, metadataDict); - break; - } - } - - //if no special metadatainfo exists, use the default class - if(metadata == null) - { - metadata = new MetadataInfo(metadataName, metadataDict); - } - - member.addMetadata(metadata); - } - } - } + //-------------------------------------- + // PUBLIC STATIC METHODS + //-------------------------------------- + + public function create(type:Class, applicationDomain:ApplicationDomain):TypeInfo + { + var json : Object = AVMDescribeType.getJson(type); + var x : int; + + var reflectedType:TypeInfo = new TypeInfo(json.factory.name, applicationDomain, type, + json.methods.length + json.factory.methods.length, + json.accessors.length + json.factory.accessors.length, + json.variables.length + json.factory.variables.length); + + reflectedType.setIsDynamic(json.factory.isDynamic); + reflectedType.setIsFinal(json.factory.isFinal); + + addMetadata(reflectedType, json.factory); + + //add constructor + reflectedType.setConstructor(parseConstructorInfo(json.factory.constructor, reflectedType, applicationDomain)); + + //add fields + addMembers(parseFieldInfo, json.variables, reflectedType, applicationDomain, true); + addMembers(parseFieldInfo, json.factory.variables, reflectedType, applicationDomain, false); + + //add methods + addMembers(parseMethodInfo, json.methods, reflectedType, applicationDomain, true); + addMembers(parseMethodInfo, json.factory.methods, reflectedType, applicationDomain, false); + + //add properties + addMembers(parsePropertyInfo, json.accessors, reflectedType, applicationDomain, true); + addMembers(parsePropertyInfo, json.factory.accessors, reflectedType, applicationDomain, false); + + for(x = 0; x < json.factory.bases.length; ++x) + { + reflectedType.extendedClasses.push(Reflection.getClassByName(json.factory.bases[x], applicationDomain)); + } + + for(x = 0; x < json.factory.interfaces.length; ++x) + { + reflectedType.implementedInterfaces.push(Reflection.getClassByName(json.factory.interfaces[x], applicationDomain)); + } + + json = null; + + return reflectedType; + } + + //-------------------------------------- + // PRIVATE CLASS METHODS + //-------------------------------------- + + private static function addMembers(method:Function, members:Array, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean):void + { + for each(var member:Object in members) + { + var memberInfo:AbstractMemberInfo = method(member, typeInfo, appDomain, isStatic); + if(memberInfo != null) + { + addMetadata(memberInfo, member); + memberInfo.assignNamespace(Reflection.getNamespace(member.uri)); + typeInfo.addMember(memberInfo); + } + } + } + + static private function parsePropertyInfo(object:Object, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean):PropertyInfo + { + var property:PropertyInfo; + var name:String = object.name; + if(name == "prototype") + { + typeInfo.properties.fixed = false; + typeInfo.properties.length--; + typeInfo.properties.fixed = true; + } + else + { + var access:String = object.access; + var canRead : Boolean = access == "readonly" || access == "readwrite"; + var canWrite : Boolean = access == "writeonly" || access == "readwrite"; + property = new PropertyInfo(name, isStatic, Reflection.getClassByName(object.type, appDomain), Reflection.getClassByName(object.declaredBy, appDomain), + typeInfo, canRead, canWrite); + } + return property; + } + + static private function parseFieldInfo(object:Object, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean):FieldInfo + { + //TODO: support adding "declaredBy" field. It will require recursing through all superclass TypeInfos looking for the first appearance + return new FieldInfo(object.name, isStatic, Reflection.getClassByName(object.type, appDomain), null, typeInfo, object.access == "readwrite"); + } + + static private function parseMethodInfo(object:Object, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean):MethodInfo + { + var method:MethodInfo = new MethodInfo(object.name, isStatic, Reflection.getClassByName(object.returnType, appDomain), Reflection.getClassByName(object.declaredBy, appDomain), typeInfo, object.parameters.length); + for(var x : int = 0; x < object.parameters.length; ++x) + { + var param:Object = object.parameters[x]; + method.addMethodParameter(new MethodParameterInfo(Reflection.getClassByName(param.type, appDomain), x, param.optional)); + } + return method; + } + + static private function parseConstructorInfo(params:Array, typeInfo:TypeInfo, appDomain:ApplicationDomain):MethodInfo + { + var method:MethodInfo = new MethodInfo("_ctor", true, null, typeInfo.type, typeInfo, params.length); + for(var x : int = 0; x < params.length; ++x) + { + var param:Object = params[x]; + method.addMethodParameter(new MethodParameterInfo(Reflection.getClassByName(param.type, appDomain), x, param.optional)); + } + return method; + } + + static private function addMetadata(member:AbstractMetadataRecipient, sourceObject:Object):void + { + var metadataArray:Array = sourceObject.metadata; + /* + { + "name": "MetadataName", + "value": [ + {"key":"param","value":"value"}, + {"key":"param2","value":"value2"} + ] + } + //*/ + //add metadata + for each(var metadataObject:Object in metadataArray) + { + var metadataName : String = metadataObject.name; + //this is a default matadata tag added by the compiler in a debug build + if(metadataName == "__go_to_definition_help") + { + member.setPosition(parseInt(metadataObject.value[0].value)); + } + else if(metadataName == "__go_to_ctor_definition_help") + { + //just drop this + } + else + { + var metadata:MetadataInfo = null; + var metadataDict : Dictionary = new Dictionary(); + for each(var keyValuePair:Object in metadataObject.value) + { + metadataDict[keyValuePair["key"]] = keyValuePair["value"]; + } + + //see if there is a registered strongly-typed class for this metadata + for(var qualifiedName:String in Reflection.REGISTERED_METADATA_CLASSES) + { + var unqualifiedName : String = Reflection.REGISTERED_METADATA_NAMES[qualifiedName]; + //implementers of metadata should omit the "Metadata" suffix, it is added here + if(metadataName == unqualifiedName || metadataName + "Metadata" == unqualifiedName) + { + metadata = new Reflection.REGISTERED_METADATA_CLASSES[qualifiedName](metadataName, metadataDict); + break; + } + } + + //if no special metadatainfo exists, use the default class + if(metadata == null) + { + metadata = new MetadataInfo(metadataName, metadataDict); + } + + member.addMetadata(metadata); + } + } + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/reflection/TypeInfoCreatorXml.as b/src/nexus/utils/reflection/TypeInfoCreatorXml.as index 8e41b77..6f4fbbc 100644 --- a/src/nexus/utils/reflection/TypeInfoCreatorXml.as +++ b/src/nexus/utils/reflection/TypeInfoCreatorXml.as @@ -19,209 +19,209 @@ import nexus.utils.Parse; */ internal class TypeInfoCreatorXml implements ITypeInfoCreator { - //-------------------------------------- - // PUBLIC METHODS - //-------------------------------------- - - public function create(type:Class, applicationDomain:ApplicationDomain):TypeInfo - { - var xml:XML = describeType(type); - - var reflectedType:TypeInfo = new TypeInfo(xml.@name, applicationDomain, type, - xml.method.length() + xml.factory.method.length(), - xml.accessor.length() + xml.factory.accessor.length(), - xml.variable.length() + xml.constant.length() + xml.factory.variable.length() + xml.factory.constant.length()); - - if(xml.factory[0] != null) - { - addMetadata(reflectedType, xml.factory[0]); - } - - //add constructor - reflectedType.setConstructor(parseConstructorInfo(xml.factory.constructor[0], reflectedType, applicationDomain, true, false)); - - //add fields - //s = getTimer(); - addMembers(parseFieldInfo, xml.constant, reflectedType, applicationDomain, true, true); - addMembers(parseFieldInfo, xml.variable, reflectedType, applicationDomain, true, false); - addMembers(parseFieldInfo, xml.factory.constant, reflectedType, applicationDomain, false, true); - addMembers(parseFieldInfo, xml.factory.variable, reflectedType, applicationDomain, false, false); - - //add methods - addMembers(parseMethodInfo, xml.method, reflectedType, applicationDomain, true, false); - addMembers(parseMethodInfo, xml.factory.method, reflectedType, applicationDomain, false, false); - - //add properties - addMembers(parsePropertyInfo, xml.accessor, reflectedType, applicationDomain, true, false); - addMembers(parsePropertyInfo, xml.factory.accessor, reflectedType, applicationDomain, false, false); - //trace(getTimer() - s); - - for each(var extendedClassXml:XML in xml.factory.extendsClass) - { - reflectedType.extendedClasses.push(Reflection.getClassByName(extendedClassXml.@type, applicationDomain)); - } - //trace(reflectedType.extendedClasses); - - for each(var implementedInterfacesXml:XML in xml.factory.implementsInterface) - { - reflectedType.implementedInterfaces.push(Reflection.getClassByName(implementedInterfacesXml.@type, applicationDomain)); - } - //trace(reflectedType.implementedInterfaces); - - var object:Object; - //isDynamic info is incorrect if doing a describeType of a Class instead of an instance - if(reflectedType.constructor.requiredParametersCount == 0) - { - //try to instantiate so we can do a describe type of the instance - try - { - object = new type(); - } - catch(e:Error) - { - - } - } - - //if the object provided was an instance or we were able to create one above - if(object != null) - { - if("disposeXML" in System) - { - System["disposeXML"](xml); - } - //get the xml info for the instance - xml = describeType(object); - reflectedType.setIsDynamic(Parse.boolean(xml.@isDynamic, false)); - reflectedType.setIsFinal(Parse.boolean(xml.@isFinal, false)); - } - - - - if("disposeXML" in System) - { - System["disposeXML"](xml); - } - xml = null; - - return reflectedType; - } - - //-------------------------------------- - // PRIVATE CLASS METHODS - //-------------------------------------- - - private static function addMembers(method:Function, xmlList:XMLList, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):void - { - for each(var xmlItem:XML in xmlList) - { - var member:AbstractMemberInfo = method(xmlItem, typeInfo, appDomain, isStatic, isConstant); - if(member != null) - { - addMetadata(member, xmlItem); - member.assignNamespace(Reflection.getNamespace(xmlItem.@uri)); - //add member to typeinfo - typeInfo.addMember(member); - - //trace(member); - } - } - } - - static private function addMetadata(member:AbstractMetadataRecipient, xmlItem:XML):void - { - //add metadata - for each(var metadataXml:XML in xmlItem.metadata) - { - //this is a default matadata tag added by the compiler in a debug build - if(metadataXml.@name == "__go_to_definition_help") - { - member.setPosition(parseInt(metadataXml.arg[0].@value)); - } - else - { - var metadata:MetadataInfo = null; - var metadataName : String = metadataXml.@name; - var metadataDict : Dictionary = new Dictionary(); - for each(var argXml:XML in metadataXml.arg) - { - metadataDict[String(argXml.@key)] = String(argXml.@value); - } - - //see if there is a registered strongly-typed class for this metadata - for(var qualifiedName:String in Reflection.REGISTERED_METADATA_CLASSES) - { - var unqualifiedName : String = Reflection.REGISTERED_METADATA_NAMES[qualifiedName]; - //implementers of metadata should omit the "Metadata" suffix, it is added here - if(metadataName == unqualifiedName || metadataName + "Metadata" == unqualifiedName) - { - metadata = new Reflection.REGISTERED_METADATA_CLASSES[qualifiedName](metadataName, metadataDict); - break; - } - } - - //if no special metadatainfo exists, use the default class - if(metadata == null) - { - metadata = new MetadataInfo(metadataName, metadataDict); - } - - member.addMetadata(metadata); - } - } - } - - static private function parseFieldInfo(xmlItem:XML, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):FieldInfo - { - //TODO: add declaring type info. it will require recursing through all superclass typeinfos - return new FieldInfo(xmlItem.@name, isStatic, Reflection.getClassByName(xmlItem.@type, appDomain), null, typeInfo, !isConstant); - } - - static private function parseMethodInfo(xmlItem:XML, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):MethodInfo - { - var method:MethodInfo = new MethodInfo(xmlItem.@name, isStatic, Reflection.getClassByName(xmlItem.@returnType, appDomain), Reflection.getClassByName(xmlItem.@declaredBy, appDomain), typeInfo, xmlItem.parameter.length()); - for each(var paramXml:XML in xmlItem.parameter) - { - method.addMethodParameter(new MethodParameterInfo(Reflection.getClassByName(paramXml.@type, appDomain), Parse.integer(paramXml.@index, 1) - 1, Parse.boolean(paramXml.@optional, false))); - } - return method; - } - - static private function parseConstructorInfo(xmlItem:XML, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):MethodInfo - { - var method:MethodInfo; - if(xmlItem != null) - { - method = new MethodInfo("_ctor", isStatic, null, typeInfo.type, typeInfo, xmlItem.parameter.length()); - for each(var paramXml:XML in xmlItem.parameter) - { - method.addMethodParameter(new MethodParameterInfo(Reflection.getClassByName(paramXml.@type, appDomain), Parse.integer(paramXml.@index, 1) - 1, Parse.boolean(paramXml.@optional, false))); - } - } - else - { - method = new MethodInfo("_ctor", isStatic, null, typeInfo.type, typeInfo, 0); - } - return method; - } - - static private function parsePropertyInfo(xmlItem:XML, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):PropertyInfo - { - var property:PropertyInfo; - var name:String = xmlItem.@name; - if(name != "prototype") - { - var access:String = String(xmlItem.@access).toLowerCase(); - property = new PropertyInfo(name, isStatic, Reflection.getClassByName(xmlItem.@type, appDomain), Reflection.getClassByName(xmlItem.@declaredBy, appDomain), typeInfo, access == "readonly" || access == "readwrite", access == "writeonly" || access == "readwrite"); - } - else - { - typeInfo.properties.fixed = false; - typeInfo.properties.length--; - typeInfo.properties.fixed = true; - } - return property; - } + //-------------------------------------- + // PUBLIC METHODS + //-------------------------------------- + + public function create(type:Class, applicationDomain:ApplicationDomain):TypeInfo + { + var xml:XML = describeType(type); + + var reflectedType:TypeInfo = new TypeInfo(xml.@name, applicationDomain, type, + xml.method.length() + xml.factory.method.length(), + xml.accessor.length() + xml.factory.accessor.length(), + xml.variable.length() + xml.constant.length() + xml.factory.variable.length() + xml.factory.constant.length()); + + if(xml.factory[0] != null) + { + addMetadata(reflectedType, xml.factory[0]); + } + + //add constructor + reflectedType.setConstructor(parseConstructorInfo(xml.factory.constructor[0], reflectedType, applicationDomain, true, false)); + + //add fields + //s = getTimer(); + addMembers(parseFieldInfo, xml.constant, reflectedType, applicationDomain, true, true); + addMembers(parseFieldInfo, xml.variable, reflectedType, applicationDomain, true, false); + addMembers(parseFieldInfo, xml.factory.constant, reflectedType, applicationDomain, false, true); + addMembers(parseFieldInfo, xml.factory.variable, reflectedType, applicationDomain, false, false); + + //add methods + addMembers(parseMethodInfo, xml.method, reflectedType, applicationDomain, true, false); + addMembers(parseMethodInfo, xml.factory.method, reflectedType, applicationDomain, false, false); + + //add properties + addMembers(parsePropertyInfo, xml.accessor, reflectedType, applicationDomain, true, false); + addMembers(parsePropertyInfo, xml.factory.accessor, reflectedType, applicationDomain, false, false); + //trace(getTimer() - s); + + for each(var extendedClassXml:XML in xml.factory.extendsClass) + { + reflectedType.extendedClasses.push(Reflection.getClassByName(extendedClassXml.@type, applicationDomain)); + } + //trace(reflectedType.extendedClasses); + + for each(var implementedInterfacesXml:XML in xml.factory.implementsInterface) + { + reflectedType.implementedInterfaces.push(Reflection.getClassByName(implementedInterfacesXml.@type, applicationDomain)); + } + //trace(reflectedType.implementedInterfaces); + + var object:Object; + //isDynamic info is incorrect if doing a describeType of a Class instead of an instance + if(reflectedType.constructor.requiredParametersCount == 0) + { + //try to instantiate so we can do a describe type of the instance + try + { + object = new type(); + } + catch(e:Error) + { + + } + } + + //if the object provided was an instance or we were able to create one above + if(object != null) + { + if("disposeXML" in System) + { + System["disposeXML"](xml); + } + //get the xml info for the instance + xml = describeType(object); + reflectedType.setIsDynamic(Parse.boolean(xml.@isDynamic, false)); + reflectedType.setIsFinal(Parse.boolean(xml.@isFinal, false)); + } + + + + if("disposeXML" in System) + { + System["disposeXML"](xml); + } + xml = null; + + return reflectedType; + } + + //-------------------------------------- + // PRIVATE CLASS METHODS + //-------------------------------------- + + private static function addMembers(method:Function, xmlList:XMLList, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):void + { + for each(var xmlItem:XML in xmlList) + { + var member:AbstractMemberInfo = method(xmlItem, typeInfo, appDomain, isStatic, isConstant); + if(member != null) + { + addMetadata(member, xmlItem); + member.assignNamespace(Reflection.getNamespace(xmlItem.@uri)); + //add member to typeinfo + typeInfo.addMember(member); + + //trace(member); + } + } + } + + static private function addMetadata(member:AbstractMetadataRecipient, xmlItem:XML):void + { + //add metadata + for each(var metadataXml:XML in xmlItem.metadata) + { + //this is a default matadata tag added by the compiler in a debug build + if(metadataXml.@name == "__go_to_definition_help") + { + member.setPosition(parseInt(metadataXml.arg[0].@value)); + } + else + { + var metadata:MetadataInfo = null; + var metadataName : String = metadataXml.@name; + var metadataDict : Dictionary = new Dictionary(); + for each(var argXml:XML in metadataXml.arg) + { + metadataDict[String(argXml.@key)] = String(argXml.@value); + } + + //see if there is a registered strongly-typed class for this metadata + for(var qualifiedName:String in Reflection.REGISTERED_METADATA_CLASSES) + { + var unqualifiedName : String = Reflection.REGISTERED_METADATA_NAMES[qualifiedName]; + //implementers of metadata should omit the "Metadata" suffix, it is added here + if(metadataName == unqualifiedName || metadataName + "Metadata" == unqualifiedName) + { + metadata = new Reflection.REGISTERED_METADATA_CLASSES[qualifiedName](metadataName, metadataDict); + break; + } + } + + //if no special metadatainfo exists, use the default class + if(metadata == null) + { + metadata = new MetadataInfo(metadataName, metadataDict); + } + + member.addMetadata(metadata); + } + } + } + + static private function parseFieldInfo(xmlItem:XML, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):FieldInfo + { + //TODO: add declaring type info. it will require recursing through all superclass typeinfos + return new FieldInfo(xmlItem.@name, isStatic, Reflection.getClassByName(xmlItem.@type, appDomain), null, typeInfo, !isConstant); + } + + static private function parseMethodInfo(xmlItem:XML, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):MethodInfo + { + var method:MethodInfo = new MethodInfo(xmlItem.@name, isStatic, Reflection.getClassByName(xmlItem.@returnType, appDomain), Reflection.getClassByName(xmlItem.@declaredBy, appDomain), typeInfo, xmlItem.parameter.length()); + for each(var paramXml:XML in xmlItem.parameter) + { + method.addMethodParameter(new MethodParameterInfo(Reflection.getClassByName(paramXml.@type, appDomain), Parse.integer(paramXml.@index, 1) - 1, Parse.boolean(paramXml.@optional, false))); + } + return method; + } + + static private function parseConstructorInfo(xmlItem:XML, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):MethodInfo + { + var method:MethodInfo; + if(xmlItem != null) + { + method = new MethodInfo("_ctor", isStatic, null, typeInfo.type, typeInfo, xmlItem.parameter.length()); + for each(var paramXml:XML in xmlItem.parameter) + { + method.addMethodParameter(new MethodParameterInfo(Reflection.getClassByName(paramXml.@type, appDomain), Parse.integer(paramXml.@index, 1) - 1, Parse.boolean(paramXml.@optional, false))); + } + } + else + { + method = new MethodInfo("_ctor", isStatic, null, typeInfo.type, typeInfo, 0); + } + return method; + } + + static private function parsePropertyInfo(xmlItem:XML, typeInfo:TypeInfo, appDomain:ApplicationDomain, isStatic:Boolean, isConstant:Boolean):PropertyInfo + { + var property:PropertyInfo; + var name:String = xmlItem.@name; + if(name != "prototype") + { + var access:String = String(xmlItem.@access).toLowerCase(); + property = new PropertyInfo(name, isStatic, Reflection.getClassByName(xmlItem.@type, appDomain), Reflection.getClassByName(xmlItem.@declaredBy, appDomain), typeInfo, access == "readonly" || access == "readwrite", access == "writeonly" || access == "readwrite"); + } + else + { + typeInfo.properties.fixed = false; + typeInfo.properties.length--; + typeInfo.properties.fixed = true; + } + return property; + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/serialization/ISerializer.as b/src/nexus/utils/serialization/ISerializer.as index 2f29043..da7fbbc 100644 --- a/src/nexus/utils/serialization/ISerializer.as +++ b/src/nexus/utils/serialization/ISerializer.as @@ -5,29 +5,29 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. package nexus.utils.serialization { - import flash.system.ApplicationDomain; - + import flash.system.ApplicationDomain; + /** * A standardized interface for serializers * */ public interface ISerializer { - /** - * Serializes the given object into the serialized type - * @param sourceObject - * @param includeReadOnlyFields - * @return - */ - function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null):Object; - - /** - * Deserializes the given serialized data into an object. If a type is not provided the object is a native Actionscript object. - * @param serializedData The serialized data to parse into an object - * @param type The type of object to deserialize to, or null if a native object should be returned - * @return An object instance parsed from the serialized data - */ - function deserialize(serializedData:Object, type:Class = null, applicationDomain:ApplicationDomain = null):Object; + /** + * Serializes the given object into the serialized type + * @param sourceObject + * @param includeReadOnlyFields + * @return + */ + function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null):Object; + + /** + * Deserializes the given serialized data into an object. If a type is not provided the object is a native Actionscript object. + * @param serializedData The serialized data to parse into an object + * @param type The type of object to deserialize to, or null if a native object should be returned + * @return An object instance parsed from the serialized data + */ + function deserialize(serializedData:Object, type:Class = null, applicationDomain:ApplicationDomain = null):Object; } -} \ No newline at end of file +} diff --git a/src/nexus/utils/serialization/amf/AmfSerializer.as b/src/nexus/utils/serialization/amf/AmfSerializer.as index 2e97922..34881b3 100644 --- a/src/nexus/utils/serialization/amf/AmfSerializer.as +++ b/src/nexus/utils/serialization/amf/AmfSerializer.as @@ -21,119 +21,119 @@ import nexus.utils.serialization.ISerializer; */ public class AmfSerializer implements ISerializer { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_isTypeSerialized : Boolean; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function AmfSerializer(serializeType:Boolean=true) - { - m_isTypeSerialized = serializeType; - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - /** - * If true, the object is serialized with its qualified type information. If false, it is serialized as a native Object - */ - public function get isTypeSerialized():Boolean { return m_isTypeSerialized; } - public function set isTypeSerialized(value:Boolean):void - { - m_isTypeSerialized = value; - } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * @inheritDoc - */ - public function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null):Object - { - return AmfSerializer.serialize(sourceObject, m_isTypeSerialized); - } - - /** - * @inheritDoc - */ - public function deserialize(serializedData:Object, type:Class=null, applicationDomain:ApplicationDomain = null):Object - { - return AmfSerializer.deserialize(serializedData, type, applicationDomain); - } - - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - static public function serialize(sourceObject:Object, typeIsSerialized:Boolean=true, applicationDomain:ApplicationDomain = null):Object - { - if(typeIsSerialized) - { - registerType(sourceObject); - } - - var bytes : ByteArray = new ByteArray(); - bytes.objectEncoding = ObjectEncoding.AMF3; - bytes.writeObject(sourceObject); - bytes.position = 0; - return bytes; - } - - static public function deserialize(serializedData:Object, type:Class=null, applicationDomain:ApplicationDomain = null):Object - { - if(serializedData is ByteArray) - { - var bytes : ByteArray = serializedData as ByteArray; - bytes.position = 0; - var object : Object = bytes.readObject(); - if(type != null && !(object is type)) - { - //object is not of the correct type, try to register it and read it out again - registerType(type, applicationDomain); - bytes.position = 0; - object = bytes.readObject(); - //still no? then parse it ourselves - if(!(object is type)) - { - return ObjectUtils.createTypedObjectFromNativeObject(type, object, applicationDomain); - } - } - return object; - } - else - { - throw new ArgumentError("Cannot deserialize object, it is not of type ByteArray"); - } - } - - //-------------------------------------- - // PRIVATE CLASS METHODS - //-------------------------------------- - - static private function registerType(sourceObject:Object, applicationDomain:ApplicationDomain = null):void - { - if(!Reflection.isScalar(sourceObject)) - { - var typeName : String = Reflection.getQualifiedClassName(sourceObject); - if(typeName != "Object" && typeName != "Array") - { - var type : Class = Reflection.getClassByName(typeName, applicationDomain); - registerClassAlias(typeName, type); - } - } - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_isTypeSerialized : Boolean; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function AmfSerializer(serializeType:Boolean=true) + { + m_isTypeSerialized = serializeType; + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + /** + * If true, the object is serialized with its qualified type information. If false, it is serialized as a native Object + */ + public function get isTypeSerialized():Boolean { return m_isTypeSerialized; } + public function set isTypeSerialized(value:Boolean):void + { + m_isTypeSerialized = value; + } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * @inheritDoc + */ + public function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null):Object + { + return AmfSerializer.serialize(sourceObject, m_isTypeSerialized); + } + + /** + * @inheritDoc + */ + public function deserialize(serializedData:Object, type:Class=null, applicationDomain:ApplicationDomain = null):Object + { + return AmfSerializer.deserialize(serializedData, type, applicationDomain); + } + + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + static public function serialize(sourceObject:Object, typeIsSerialized:Boolean=true, applicationDomain:ApplicationDomain = null):Object + { + if(typeIsSerialized) + { + registerType(sourceObject); + } + + var bytes : ByteArray = new ByteArray(); + bytes.objectEncoding = ObjectEncoding.AMF3; + bytes.writeObject(sourceObject); + bytes.position = 0; + return bytes; + } + + static public function deserialize(serializedData:Object, type:Class=null, applicationDomain:ApplicationDomain = null):Object + { + if(serializedData is ByteArray) + { + var bytes : ByteArray = serializedData as ByteArray; + bytes.position = 0; + var object : Object = bytes.readObject(); + if(type != null && !(object is type)) + { + //object is not of the correct type, try to register it and read it out again + registerType(type, applicationDomain); + bytes.position = 0; + object = bytes.readObject(); + //still no? then parse it ourselves + if(!(object is type)) + { + return ObjectUtils.createTypedObjectFromNativeObject(type, object, applicationDomain); + } + } + return object; + } + else + { + throw new ArgumentError("Cannot deserialize object, it is not of type ByteArray"); + } + } + + //-------------------------------------- + // PRIVATE CLASS METHODS + //-------------------------------------- + + static private function registerType(sourceObject:Object, applicationDomain:ApplicationDomain = null):void + { + if(!Reflection.isScalar(sourceObject)) + { + var typeName : String = Reflection.getQualifiedClassName(sourceObject); + if(typeName != "Object" && typeName != "Array") + { + var type : Class = Reflection.getClassByName(typeName, applicationDomain); + registerClassAlias(typeName, type); + } + } + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/serialization/json/IJsonSerializable.as b/src/nexus/utils/serialization/json/IJsonSerializable.as index 1aeadbb..4d04fde 100644 --- a/src/nexus/utils/serialization/json/IJsonSerializable.as +++ b/src/nexus/utils/serialization/json/IJsonSerializable.as @@ -14,22 +14,22 @@ package nexus.utils.serialization.json */ public interface IJsonSerializable { - /** - * Used by the JsonSerializer to return a custom native object representation of this instance. If an Object is returned, - * the serializer recurses into the object. If a String is returned, the serializer does not recurse and will continue on. - * @param key The key of this object in its parent - * @return A String or Object representing this object. - */ - function toJSON(key:String):Object; - - /** - * Returns true if the data provided has the same signature as this class (typically this means that all the fields and properties in - * the class have corresponding keys in the data, and there are no keys in the data that do not exist as class members -- however if - * you have provided a custom toJson() implementation then you will likely need to override this check as well) - * @param data A native object which has been parsed from JSON - * @return True if the provided data has an equivalent signature to this class, false if it does not. - */ - function jsonLikeType(data:Object):Boolean; + /** + * Used by the JsonSerializer to return a custom native object representation of this instance. If an Object is returned, + * the serializer recurses into the object. If a String is returned, the serializer does not recurse and will continue on. + * @param key The key of this object in its parent + * @return A String or Object representing this object. + */ + function toJSON(key:String):Object; + + /** + * Returns true if the data provided has the same signature as this class (typically this means that all the fields and properties in + * the class have corresponding keys in the data, and there are no keys in the data that do not exist as class members -- however if + * you have provided a custom toJson() implementation then you will likely need to override this check as well) + * @param data A native object which has been parsed from JSON + * @return True if the provided data has an equivalent signature to this class, false if it does not. + */ + function jsonLikeType(data:Object):Boolean; } -} \ No newline at end of file +} diff --git a/src/nexus/utils/serialization/json/JsonParser.as b/src/nexus/utils/serialization/json/JsonParser.as index 93e1ff1..5fcb6b0 100644 --- a/src/nexus/utils/serialization/json/JsonParser.as +++ b/src/nexus/utils/serialization/json/JsonParser.as @@ -13,41 +13,41 @@ package nexus.utils.serialization.json */ internal class JsonParser { - //-------------------------------------- - // CLASS VARIABLES - //-------------------------------------- - - /** - * Signature => public static function encode(object:Object):String - * @private - */ - internal static var encode : Function; - - /** - * Signature => public static function decode(json:String):Object - * @private - */ - internal static var decode : Function; - - //-------------------------------------- - // STATIC INITIALIZER - //-------------------------------------- - - { - try - { - encode = JSON.stringify; - decode = JSON.parse; - trace("Using native JSON"); - } - catch(e:Error) - { - encode = JsonParserBlooddy.encode; - decode = JsonParserBlooddy.decode; - trace("Using blooddy JSON"); - } - } - + //-------------------------------------- + // CLASS VARIABLES + //-------------------------------------- + + /** + * Signature => public static function encode(object:Object):String + * @private + */ + internal static var encode : Function; + + /** + * Signature => public static function decode(json:String):Object + * @private + */ + internal static var decode : Function; + + //-------------------------------------- + // STATIC INITIALIZER + //-------------------------------------- + + { + try + { + encode = JSON.stringify; + decode = JSON.parse; + trace("Using native JSON"); + } + catch(e:Error) + { + encode = JsonParserBlooddy.encode; + decode = JsonParserBlooddy.decode; + trace("Using blooddy JSON"); + } + } + } -} \ No newline at end of file +} diff --git a/src/nexus/utils/serialization/json/JsonParserBlooddy.as b/src/nexus/utils/serialization/json/JsonParserBlooddy.as index 4d95b6e..18eb43f 100644 --- a/src/nexus/utils/serialization/json/JsonParserBlooddy.as +++ b/src/nexus/utils/serialization/json/JsonParserBlooddy.as @@ -15,19 +15,19 @@ import by.blooddy.crypto.serialization.JSON; */ internal class JsonParserBlooddy { - //-------------------------------------- - // INTERNAL CLASS METHODS - //-------------------------------------- - - /** - * @private - */ - internal static const encode : Function = by.blooddy.crypto.serialization.JSON.encode; - - /** - * @private - */ - internal static const decode : Function = by.blooddy.crypto.serialization.JSON.decode; + //-------------------------------------- + // INTERNAL CLASS METHODS + //-------------------------------------- + + /** + * @private + */ + internal static const encode : Function = by.blooddy.crypto.serialization.JSON.encode; + + /** + * @private + */ + internal static const decode : Function = by.blooddy.crypto.serialization.JSON.decode; } -} \ No newline at end of file +} diff --git a/src/nexus/utils/serialization/json/JsonSerializer.as b/src/nexus/utils/serialization/json/JsonSerializer.as index d340fbf..8b19d7f 100644 --- a/src/nexus/utils/serialization/json/JsonSerializer.as +++ b/src/nexus/utils/serialization/json/JsonSerializer.as @@ -18,357 +18,357 @@ import nexus.utils.serialization.ISerializer; */ public class JsonSerializer implements ISerializer { - //-------------------------------------- - // SPECIAL - //-------------------------------------- - - /** - * Override the toJSON method for Date to return the milliseconds since epoch - */ - Date.prototype.toJSON = function(_:String):* - { - return this.getTime(); - } - - /** - * Override the toJSON method for Dictionary to return the contents as a native Object - */ - /* - Dictionary.prototype.toJSON = function(_:String):* - { - var result : Object = { }; - for(var key : Object in this) - { - result[key] = this[key]; - } - return result; - } - //*/ - - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - static private const s_staticSerializer : JsonSerializer = new JsonSerializer(); - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_indentationCharacters:String; - private var m_maxLineLength:int; - private var m_isSerializingConstantScalars:Boolean; - private var m_isOutputAlphabetized : Boolean; - private var m_includedNamespaces : Dictionary; - - ///the current indentation characters used in this serialization pass - private var m_currentIndentation:String; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - /** - * Creates a new JsonSerializer which provides more customization than that static serialize/deserialize methods. - * @param indentationCharacters The character(s) to use for indentation in the output JSON - * @param lineLength Pretty-print JSON by defining a maximum character length of a single line. By default the output JSON will not have any newlines. - * @param isSerializingConstantScalars By default, scalar values that are constant or are provided only through a get function (with no corresponding set function) are not serialized. - * @param isOutputAlphabetized Should the resulting JSON alphabetize objects by key, default is true. - */ - public function JsonSerializer(indentationCharacters:String = "", lineLength:int = int.MAX_VALUE, - isSerializingConstantScalars:Boolean = false, isOutputAlphabetized:Boolean = true) - { - this.indentationCharacters = indentationCharacters; - this.maxLineLength = lineLength; - this.isSerializingConstantScalars = isSerializingConstantScalars; - this.isOutputAlphabetized = isOutputAlphabetized; - - m_includedNamespaces = new Dictionary(); - m_includedNamespaces[new Namespace()] = true; - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - /** - * If the serializer has a maximum line length set, then the indentation character(s) provided here are used after each newline - * If the provided string value is longer than 10 characters, only the first 10 characters of the string value are used. - */ - public function get indentationCharacters():String { return m_indentationCharacters; } - public function set indentationCharacters(value:String):void - { - if(value == null) - { - m_indentationCharacters = ""; - } - else if(m_indentationCharacters != value) - { - m_indentationCharacters = value || ""; - if(m_indentationCharacters.length > 10) - { - m_indentationCharacters = m_indentationCharacters.substr(0, 10); - } - } - } - - /** - * If true, objects in the resulting JSON will be alphabetized by key - * @default true - */ - public function get isOutputAlphabetized():Boolean { return m_isOutputAlphabetized; } - public function set isOutputAlphabetized(value:Boolean):void - { - m_isOutputAlphabetized = value; - } - - /** - * If true, constants are serialized in the JSON output along with variables and getter properties. - * @default false - */ - public function get isSerializingConstantScalars():Boolean { return m_isSerializingConstantScalars; } - public function set isSerializingConstantScalars(value:Boolean):void - { - m_isSerializingConstantScalars = value; - } - - /** - * The maximum allowed length of a single line of the JSON string before the JSON data is wrapped appropriately. This - * value is not a hard limit but the serializer will do its best to meet the limit. - */ - public function get maxLineLength():int { return m_maxLineLength; } - public function set maxLineLength(value:int):void - { - m_maxLineLength = value; - } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * Includes the provided namespace in serialization. - * @param ns The namespace to include - * @param prefix The prefix to use on the key of serialized objects, defaults to the URI of the namespace - */ - public function includeNamespace(ns:Namespace, prefix:String=null):void - { - m_includedNamespaces[ns] = true; - } - - /** - * @inheritDoc - */ - public function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null):Object - { - m_currentIndentation = ""; - return serializeObject(sourceObject, applicationDomain); - } - - /** - * @inheritDoc - */ - public function deserialize(serializedData:Object, type:Class = null, applicationDomain:ApplicationDomain = null):Object - { - var json : String = serializedData as String; - var result : Object; - - try - { - result = JsonParser.decode(json); - } - catch(e:SyntaxError) - { - throw new SyntaxError("Error deserializing object, invalid JSON input."); - } - - if(type != null) - { - return ObjectUtils.createTypedObjectFromNativeObject(type, result, applicationDomain); - } - - return result; - } - - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - static public function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null, indentationCharacters:String = "", maxLineLength:int = int.MAX_VALUE):Object - { - s_staticSerializer.indentationCharacters = indentationCharacters; - s_staticSerializer.maxLineLength = maxLineLength; - return s_staticSerializer.serialize(sourceObject, applicationDomain); - } - - static public function deserialize(json:String, type:Class = null, applicationDomain:ApplicationDomain = null):Object - { - return s_staticSerializer.deserialize(json, type, applicationDomain); - } - - //-------------------------------------- - // PRIVATE METHODS - //-------------------------------------- - - private function serializeObject(sourceObject:Object, applicationDomain:ApplicationDomain):String - { - var result:String; - var lineWrap : Boolean; - var x : int; - - //see if this object has a toJSON method - if( sourceObject != null - && ( - sourceObject is IJsonSerializable - || (!(sourceObject is Dictionary) && "toJSON" in sourceObject && sourceObject["toJSON"] is Function) - ) - ) - { - sourceObject = sourceObject.toJSON(null); - } - - if(sourceObject == null) - { - result = "null"; - } - else if(Reflection.isScalar(sourceObject) || sourceObject is Date) - { - result = JsonParser.encode(sourceObject); - } - else - { - result = ""; - - //if a max line length has been set, use the native encoder to very quickly roughly determine the string length - //of the current object and then use that to determine if we need to run the pretty formatter or not - //TODO: find a faster way to determine this - lineWrap = (m_maxLineLength == 0 || (m_maxLineLength < int.MAX_VALUE && JsonParser.encode(sourceObject).length > m_maxLineLength)); - - if(lineWrap) - { - m_currentIndentation += m_indentationCharacters; - } - - if(Reflection.isArrayType(sourceObject)) - { - for(x = 0; x < sourceObject.length; x++) - { - if(result.length > 0) - { - result += lineWrap ? ",\n" : ","; - } - result += lineWrap ? m_currentIndentation : ""; - result += serializeObject(sourceObject[x], applicationDomain); - } - - if(lineWrap) - { - //unindent - m_currentIndentation = m_currentIndentation.substring(0, m_currentIndentation.length - m_indentationCharacters.length); - result = "[" + "\n" + result + "\n" + m_currentIndentation + "]"; - } - else - { - result = "[" + result + "]"; - } - } - else - { - //iterate over the keys in a native object, use reflection if it is typed - if(Reflection.isAssociativeArray(sourceObject)) - { - var key : String; - if(m_isOutputAlphabetized) - { - var keys : Array = []; - for(key in sourceObject) - { - keys.push(key); - } - keys.sort(Array.CASEINSENSITIVE); - - for(x = 0; x < keys.length; ++x) - { - key = keys[x]; - result += setupObjectString(result, key, sourceObject[key], lineWrap, applicationDomain); - } - } - else - { - for(key in sourceObject) - { - result += setupObjectString(result, key, sourceObject[key], lineWrap, applicationDomain); - } - } - } - else - { - //Loop over all of the variables and accessors in the class and - //serialize them along with their values. - var typeInfo : TypeInfo = Reflection.getTypeInfo(sourceObject, applicationDomain); - if(typeInfo.isDynamic) - { - var fieldsInDataFoundInClass : Dictionary = new Dictionary(); - } - - var memberNames : Vector. = m_isOutputAlphabetized ? typeInfo.allMembersSortedByName : typeInfo.allMembers; - for each(var member : AbstractMemberInfo in memberNames) - { - var field : AbstractFieldInfo = member as AbstractFieldInfo; - if( field != null - && field.canRead - && !field.isStatic - && (m_isSerializingConstantScalars || field.canWrite || !Reflection.isScalar(field.type)) - && field.getMetadataByName("Transient") == null - && (field.namespace == null || field.namespace in m_includedNamespaces) ) - { - result += setupObjectString(result, field.qname.toString(), sourceObject[field.qname], lineWrap, applicationDomain); - } - } - - if(typeInfo.isDynamic) - { - for(var dynamicKey:String in sourceObject) - { - if(!(dynamicKey in fieldsInDataFoundInClass)) - { - result += setupObjectString(result, dynamicKey, sourceObject[dynamicKey], lineWrap, applicationDomain); - } - } - } - } - - if(lineWrap) - { - //unindent - m_currentIndentation = m_currentIndentation.substring(0, m_currentIndentation.length - m_indentationCharacters.length); - result = "{" + "\n" + result + "\n" + m_currentIndentation + "}"; - } - else - { - result = "{" + result + "}"; - } - } - } - return result; - } - - private function setupObjectString(current:String, key:String, value:Object, lineWrap:Boolean, applicationDomain:ApplicationDomain):String - { - var result : String = ""; - if(!(value is Function)) - { - if(current.length > 0) - { - result += lineWrap ? ",\n" : ","; - } - result += lineWrap ? m_currentIndentation : ""; - result += JsonParser.encode(key); - result += lineWrap ? ": " : ":"; - result += serializeObject(value, applicationDomain); - } - return result; - } + //-------------------------------------- + // SPECIAL + //-------------------------------------- + + /** + * Override the toJSON method for Date to return the milliseconds since epoch + */ + Date.prototype.toJSON = function(_:String):* + { + return this.getTime(); + } + + /** + * Override the toJSON method for Dictionary to return the contents as a native Object + */ + /* + Dictionary.prototype.toJSON = function(_:String):* + { + var result : Object = { }; + for(var key : Object in this) + { + result[key] = this[key]; + } + return result; + } + //*/ + + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + static private const s_staticSerializer : JsonSerializer = new JsonSerializer(); + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_indentationCharacters:String; + private var m_maxLineLength:int; + private var m_isSerializingConstantScalars:Boolean; + private var m_isOutputAlphabetized : Boolean; + private var m_includedNamespaces : Dictionary; + + ///the current indentation characters used in this serialization pass + private var m_currentIndentation:String; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + /** + * Creates a new JsonSerializer which provides more customization than that static serialize/deserialize methods. + * @param indentationCharacters The character(s) to use for indentation in the output JSON + * @param lineLength Pretty-print JSON by defining a maximum character length of a single line. By default the output JSON will not have any newlines. + * @param isSerializingConstantScalars By default, scalar values that are constant or are provided only through a get function (with no corresponding set function) are not serialized. + * @param isOutputAlphabetized Should the resulting JSON alphabetize objects by key, default is true. + */ + public function JsonSerializer(indentationCharacters:String = "", lineLength:int = int.MAX_VALUE, + isSerializingConstantScalars:Boolean = false, isOutputAlphabetized:Boolean = true) + { + this.indentationCharacters = indentationCharacters; + this.maxLineLength = lineLength; + this.isSerializingConstantScalars = isSerializingConstantScalars; + this.isOutputAlphabetized = isOutputAlphabetized; + + m_includedNamespaces = new Dictionary(); + m_includedNamespaces[new Namespace()] = true; + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + /** + * If the serializer has a maximum line length set, then the indentation character(s) provided here are used after each newline + * If the provided string value is longer than 10 characters, only the first 10 characters of the string value are used. + */ + public function get indentationCharacters():String { return m_indentationCharacters; } + public function set indentationCharacters(value:String):void + { + if(value == null) + { + m_indentationCharacters = ""; + } + else if(m_indentationCharacters != value) + { + m_indentationCharacters = value || ""; + if(m_indentationCharacters.length > 10) + { + m_indentationCharacters = m_indentationCharacters.substr(0, 10); + } + } + } + + /** + * If true, objects in the resulting JSON will be alphabetized by key + * @default true + */ + public function get isOutputAlphabetized():Boolean { return m_isOutputAlphabetized; } + public function set isOutputAlphabetized(value:Boolean):void + { + m_isOutputAlphabetized = value; + } + + /** + * If true, constants are serialized in the JSON output along with variables and getter properties. + * @default false + */ + public function get isSerializingConstantScalars():Boolean { return m_isSerializingConstantScalars; } + public function set isSerializingConstantScalars(value:Boolean):void + { + m_isSerializingConstantScalars = value; + } + + /** + * The maximum allowed length of a single line of the JSON string before the JSON data is wrapped appropriately. This + * value is not a hard limit but the serializer will do its best to meet the limit. + */ + public function get maxLineLength():int { return m_maxLineLength; } + public function set maxLineLength(value:int):void + { + m_maxLineLength = value; + } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * Includes the provided namespace in serialization. + * @param ns The namespace to include + * @param prefix The prefix to use on the key of serialized objects, defaults to the URI of the namespace + */ + public function includeNamespace(ns:Namespace, prefix:String=null):void + { + m_includedNamespaces[ns] = true; + } + + /** + * @inheritDoc + */ + public function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null):Object + { + m_currentIndentation = ""; + return serializeObject(sourceObject, applicationDomain); + } + + /** + * @inheritDoc + */ + public function deserialize(serializedData:Object, type:Class = null, applicationDomain:ApplicationDomain = null):Object + { + var json : String = serializedData as String; + var result : Object; + + try + { + result = JsonParser.decode(json); + } + catch(e:SyntaxError) + { + throw new SyntaxError("Error deserializing object, invalid JSON input."); + } + + if(type != null) + { + return ObjectUtils.createTypedObjectFromNativeObject(type, result, applicationDomain); + } + + return result; + } + + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + static public function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null, indentationCharacters:String = "", maxLineLength:int = int.MAX_VALUE):Object + { + s_staticSerializer.indentationCharacters = indentationCharacters; + s_staticSerializer.maxLineLength = maxLineLength; + return s_staticSerializer.serialize(sourceObject, applicationDomain); + } + + static public function deserialize(json:String, type:Class = null, applicationDomain:ApplicationDomain = null):Object + { + return s_staticSerializer.deserialize(json, type, applicationDomain); + } + + //-------------------------------------- + // PRIVATE METHODS + //-------------------------------------- + + private function serializeObject(sourceObject:Object, applicationDomain:ApplicationDomain):String + { + var result:String; + var lineWrap : Boolean; + var x : int; + + //see if this object has a toJSON method + if( sourceObject != null + && ( + sourceObject is IJsonSerializable + || (!(sourceObject is Dictionary) && "toJSON" in sourceObject && sourceObject["toJSON"] is Function) + ) + ) + { + sourceObject = sourceObject.toJSON(null); + } + + if(sourceObject == null) + { + result = "null"; + } + else if(Reflection.isScalar(sourceObject) || sourceObject is Date) + { + result = JsonParser.encode(sourceObject); + } + else + { + result = ""; + + //if a max line length has been set, use the native encoder to very quickly roughly determine the string length + //of the current object and then use that to determine if we need to run the pretty formatter or not + //TODO: find a faster way to determine this + lineWrap = (m_maxLineLength == 0 || (m_maxLineLength < int.MAX_VALUE && JsonParser.encode(sourceObject).length > m_maxLineLength)); + + if(lineWrap) + { + m_currentIndentation += m_indentationCharacters; + } + + if(Reflection.isArrayType(sourceObject)) + { + for(x = 0; x < sourceObject.length; x++) + { + if(result.length > 0) + { + result += lineWrap ? ",\n" : ","; + } + result += lineWrap ? m_currentIndentation : ""; + result += serializeObject(sourceObject[x], applicationDomain); + } + + if(lineWrap) + { + //unindent + m_currentIndentation = m_currentIndentation.substring(0, m_currentIndentation.length - m_indentationCharacters.length); + result = "[" + "\n" + result + "\n" + m_currentIndentation + "]"; + } + else + { + result = "[" + result + "]"; + } + } + else + { + //iterate over the keys in a native object, use reflection if it is typed + if(Reflection.isAssociativeArray(sourceObject)) + { + var key : String; + if(m_isOutputAlphabetized) + { + var keys : Array = []; + for(key in sourceObject) + { + keys.push(key); + } + keys.sort(Array.CASEINSENSITIVE); + + for(x = 0; x < keys.length; ++x) + { + key = keys[x]; + result += setupObjectString(result, key, sourceObject[key], lineWrap, applicationDomain); + } + } + else + { + for(key in sourceObject) + { + result += setupObjectString(result, key, sourceObject[key], lineWrap, applicationDomain); + } + } + } + else + { + //Loop over all of the variables and accessors in the class and + //serialize them along with their values. + var typeInfo : TypeInfo = Reflection.getTypeInfo(sourceObject, applicationDomain); + if(typeInfo.isDynamic) + { + var fieldsInDataFoundInClass : Dictionary = new Dictionary(); + } + + var memberNames : Vector. = m_isOutputAlphabetized ? typeInfo.allMembersSortedByName : typeInfo.allMembers; + for each(var member : AbstractMemberInfo in memberNames) + { + var field : AbstractFieldInfo = member as AbstractFieldInfo; + if( field != null + && field.canRead + && !field.isStatic + && (m_isSerializingConstantScalars || field.canWrite || !Reflection.isScalar(field.type)) + && field.getMetadataByName("Transient") == null + && (field.namespace == null || field.namespace in m_includedNamespaces) ) + { + result += setupObjectString(result, field.qname.toString(), sourceObject[field.qname], lineWrap, applicationDomain); + } + } + + if(typeInfo.isDynamic) + { + for(var dynamicKey:String in sourceObject) + { + if(!(dynamicKey in fieldsInDataFoundInClass)) + { + result += setupObjectString(result, dynamicKey, sourceObject[dynamicKey], lineWrap, applicationDomain); + } + } + } + } + + if(lineWrap) + { + //unindent + m_currentIndentation = m_currentIndentation.substring(0, m_currentIndentation.length - m_indentationCharacters.length); + result = "{" + "\n" + result + "\n" + m_currentIndentation + "}"; + } + else + { + result = "{" + result + "}"; + } + } + } + return result; + } + + private function setupObjectString(current:String, key:String, value:Object, lineWrap:Boolean, applicationDomain:ApplicationDomain):String + { + var result : String = ""; + if(!(value is Function)) + { + if(current.length > 0) + { + result += lineWrap ? ",\n" : ","; + } + result += lineWrap ? m_currentIndentation : ""; + result += JsonParser.encode(key); + result += lineWrap ? ": " : ":"; + result += serializeObject(value, applicationDomain); + } + return result; + } } -} \ No newline at end of file +} diff --git a/src/nexus/utils/serialization/xml/IXmlSerializable.as b/src/nexus/utils/serialization/xml/IXmlSerializable.as index 89a324a..70e119f 100644 --- a/src/nexus/utils/serialization/xml/IXmlSerializable.as +++ b/src/nexus/utils/serialization/xml/IXmlSerializable.as @@ -5,14 +5,14 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. package nexus.utils.serialization.xml { - + /** * Implement on objects that want to override their serialization to XML * */ public interface IXmlSerializable { - function toXML():XML; + function toXML():XML; } -} \ No newline at end of file +} diff --git a/src/nexus/utils/serialization/xml/XmlMetadata.as b/src/nexus/utils/serialization/xml/XmlMetadata.as index 7a105e8..e57d91b 100644 --- a/src/nexus/utils/serialization/xml/XmlMetadata.as +++ b/src/nexus/utils/serialization/xml/XmlMetadata.as @@ -17,41 +17,41 @@ import nexus.utils.reflection.MetadataInfo; */ public class XmlMetadata extends MetadataInfo { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - public var nodeName : String; - public var isAttribute : Boolean; - public var flattenArray : Boolean; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function XmlMetadata(name:String, keyValueCollection:Dictionary) - { - super(name, keyValueCollection); - this.nodeName = this.getValue("nodeName"); - this.isAttribute = Parse.boolean(this.getValue("isAttribute"), false); - this.flattenArray = Parse.boolean(this.getValue("flattenArray"), false); - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + public var nodeName : String; + public var isAttribute : Boolean; + public var flattenArray : Boolean; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function XmlMetadata(name:String, keyValueCollection:Dictionary) + { + super(name, keyValueCollection); + this.nodeName = this.getValue("nodeName"); + this.isAttribute = Parse.boolean(this.getValue("isAttribute"), false); + this.flattenArray = Parse.boolean(this.getValue("flattenArray"), false); + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- } -} \ No newline at end of file +} diff --git a/src/nexus/utils/serialization/xml/XmlSerializer.as b/src/nexus/utils/serialization/xml/XmlSerializer.as index f43652c..fea9c33 100644 --- a/src/nexus/utils/serialization/xml/XmlSerializer.as +++ b/src/nexus/utils/serialization/xml/XmlSerializer.as @@ -21,267 +21,267 @@ import nexus.utils.serialization.ISerializer; */ public class XmlSerializer implements ISerializer { - //-------------------------------------- - // CLASS INITIALIZER - //-------------------------------------- - - { - Reflection.registerMetadataClass(XmlMetadata); - } - - //-------------------------------------- - // CLASS VARIABLES - //-------------------------------------- - - static private var s_serializeConstants:Boolean; - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function XmlSerializer() - { - - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - /** - * @inheritDoc - */ - public function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null):Object - { - return XmlSerializer.serialize(sourceObject, applicationDomain, false); - } - - /** - * @inheritDoc - */ - public function deserialize(serializedData:Object, type:Class = null, applicationDomain:ApplicationDomain = null):Object - { - var object:Object = XmlSerializer.deserialize(serializedData is XML ? serializedData as XML : new XML(serializedData)); - if(type != null) - { - return ObjectUtils.createTypedObjectFromNativeObject(type, object, applicationDomain); - } - else - { - return object; - } - } - - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - /** - * Creates an XML object representing the passed object instance. Only public properties are included, and Dates - * are converted to number of milliseconds since Jan 1, 1970 UTC - * @param sourceObject The object to convert to XML - * @param elementName The name of the root element. If null, the name of the object's class is used. - * @return - */ - public static function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null, serializeConstants:Boolean = false):XML - { - s_serializeConstants = serializeConstants; - var typeInfo:TypeInfo = Reflection.getTypeInfo(sourceObject); - var metadata:XmlMetadata = typeInfo.getMetadataByClass(XmlMetadata) as XmlMetadata; - var name:String = (metadata != null && metadata.nodeName != null ? metadata.nodeName : Reflection.getUnqualifiedClassName(typeInfo.type)).toLowerCase(); - var xml:XML = <{name}/>; - serializeObject(sourceObject, xml); - return xml; - } - - /** - * Creates an instance of the passed class from the passed XML data - * @param sourceXML The XML to source the object from - * @param type The type of object to create. If null, the Class type is derived from the "type" attribute of the root XML node - * @return - */ - public static function deserialize(sourceXML:XML):Object - { - if(sourceXML == null) - { - return null; - } - - var result:Object = {}; - var element:XML; - var arrays:Dictionary; - - //check if the xml is formatted such that the resulting object should be an array - if(sourceXML.hasComplexContent()) - { - if(sourceXML.children()[0].name().toString().charAt(0) == "_") - { - result = []; - } - else - { - arrays = new Dictionary(); - var names:Dictionary = new Dictionary(); - for each(element in sourceXML.elements()) - { - if(element.name().toString() in names) - { - //same named child element exists twice, if this element has the same name as well, then it is an array, otherwise - //it was flattened during serialization and we should create a child key with the name of the child elements - //and it should be an array - if(element.name().toString() == sourceXML.name().toString()) - { - result = []; - break; - } - else - { - result[element.name().toString()] = []; - arrays[element.name().toString()] = true; - } - } - names[element.name().toString()] = true; - } - names = null; - } - } - - for each(element in sourceXML.elements()) - { - var name:String = element.name().toString() - var obj:Object = name in arrays ? result[name] : result; - - if(element.hasComplexContent() || element.attributes().length() > 0) - { - obj[getKey(obj, name)] = deserialize(element); - } - else - { - setValue(obj, name, element.toString()); - } - } - - for each(element in sourceXML.attributes()) - { - setValue(result, element.name().toString(), element.toString()); - } - - return result; - } - - //-------------------------------------- - // PRIVATE CLASS METHODS - //-------------------------------------- - - static private function serializeObject(sourceObject:Object, parent:XML, elementName:String = null):XML - { - var x:int; - - if(sourceObject == null) - { - //no-op - } - else if(sourceObject is XML || Reflection.isScalar(sourceObject)) - { - parent.appendChild(sourceObject); - } - else if(sourceObject is Date) - { - parent.appendChild((sourceObject as Date).getTime()); - } - else if(sourceObject is IXmlSerializable || "toXML" in sourceObject) - { - parent.appendChild(sourceObject.toXML()); - } - else if(Reflection.isArrayType(sourceObject)) - { - for(x = 0; x < sourceObject.length; x++) - { - parent.appendChild(serializeObject(sourceObject[x], <{elementName || "_" + x}/>)); - } - } - else if(Reflection.isAssociativeArray(sourceObject)) - { - var key:String; - for(key in sourceObject) - { - parent.appendChild(serializeObject(sourceObject[key], <{key}/>)); - } - } - else - { - //Loop over all of the variables and accessors in the class and - //serialize them along with their values. - var typeInfo:TypeInfo = Reflection.getTypeInfo(sourceObject); - for each(var field:AbstractMemberInfo in typeInfo.allMembers) - { - if(field is AbstractFieldInfo && !AbstractFieldInfo(field).isStatic && AbstractFieldInfo(field).canRead - //don't serialize constant fields if told not to, but always serialize read-only properties - && (s_serializeConstants || AbstractFieldInfo(field).canWrite || field is PropertyInfo) && field.getMetadataByName("Transient") == null) - { - var metadata:XmlMetadata = field.getMetadataByClass(XmlMetadata) as XmlMetadata; - var nodeName:String = (metadata != null ? metadata.nodeName || field.name : field.name); - if(metadata != null && metadata.flattenArray) - { - serializeObject(sourceObject[field.name], parent, nodeName); - } - else - { - parent.appendChild(serializeObject(sourceObject[field.name], <{nodeName}/>)); - } - } - } - - if(typeInfo.isDynamic) - { - for(var dynamicField:String in sourceObject) - { - //won't this always be true if we'e able to iterate it with a for/in? - if(sourceObject.hasOwnProperty(dynamicField)) - { - parent.appendChild(serializeObject(sourceObject[dynamicField], <{dynamicField}/>)); - } - } - } - } - return parent; - } - - static private function setValue(obj:Object, name:String, value:String):void - { - if(/^\d*\.?\d+$/.test(value)) - { - obj[getKey(obj, name)] = parseFloat(value); - } - else - { - obj[getKey(obj, name)] = value; - } - } - - static private function getKey(object:Object, name:String):Object - { - if(object is Array) - { - if(name.charAt(0) == "_") - { - return parseInt(name.substring(1)); - } - else - { - return object.length; - } - } - return name; - } + //-------------------------------------- + // CLASS INITIALIZER + //-------------------------------------- + + { + Reflection.registerMetadataClass(XmlMetadata); + } + + //-------------------------------------- + // CLASS VARIABLES + //-------------------------------------- + + static private var s_serializeConstants:Boolean; + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function XmlSerializer() + { + + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + /** + * @inheritDoc + */ + public function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null):Object + { + return XmlSerializer.serialize(sourceObject, applicationDomain, false); + } + + /** + * @inheritDoc + */ + public function deserialize(serializedData:Object, type:Class = null, applicationDomain:ApplicationDomain = null):Object + { + var object:Object = XmlSerializer.deserialize(serializedData is XML ? serializedData as XML : new XML(serializedData)); + if(type != null) + { + return ObjectUtils.createTypedObjectFromNativeObject(type, object, applicationDomain); + } + else + { + return object; + } + } + + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + /** + * Creates an XML object representing the passed object instance. Only public properties are included, and Dates + * are converted to number of milliseconds since Jan 1, 1970 UTC + * @param sourceObject The object to convert to XML + * @param elementName The name of the root element. If null, the name of the object's class is used. + * @return + */ + public static function serialize(sourceObject:Object, applicationDomain:ApplicationDomain = null, serializeConstants:Boolean = false):XML + { + s_serializeConstants = serializeConstants; + var typeInfo:TypeInfo = Reflection.getTypeInfo(sourceObject); + var metadata:XmlMetadata = typeInfo.getMetadataByClass(XmlMetadata) as XmlMetadata; + var name:String = (metadata != null && metadata.nodeName != null ? metadata.nodeName : Reflection.getUnqualifiedClassName(typeInfo.type)).toLowerCase(); + var xml:XML = <{name}/>; + serializeObject(sourceObject, xml); + return xml; + } + + /** + * Creates an instance of the passed class from the passed XML data + * @param sourceXML The XML to source the object from + * @param type The type of object to create. If null, the Class type is derived from the "type" attribute of the root XML node + * @return + */ + public static function deserialize(sourceXML:XML):Object + { + if(sourceXML == null) + { + return null; + } + + var result:Object = {}; + var element:XML; + var arrays:Dictionary; + + //check if the xml is formatted such that the resulting object should be an array + if(sourceXML.hasComplexContent()) + { + if(sourceXML.children()[0].name().toString().charAt(0) == "_") + { + result = []; + } + else + { + arrays = new Dictionary(); + var names:Dictionary = new Dictionary(); + for each(element in sourceXML.elements()) + { + if(element.name().toString() in names) + { + //same named child element exists twice, if this element has the same name as well, then it is an array, otherwise + //it was flattened during serialization and we should create a child key with the name of the child elements + //and it should be an array + if(element.name().toString() == sourceXML.name().toString()) + { + result = []; + break; + } + else + { + result[element.name().toString()] = []; + arrays[element.name().toString()] = true; + } + } + names[element.name().toString()] = true; + } + names = null; + } + } + + for each(element in sourceXML.elements()) + { + var name:String = element.name().toString() + var obj:Object = name in arrays ? result[name] : result; + + if(element.hasComplexContent() || element.attributes().length() > 0) + { + obj[getKey(obj, name)] = deserialize(element); + } + else + { + setValue(obj, name, element.toString()); + } + } + + for each(element in sourceXML.attributes()) + { + setValue(result, element.name().toString(), element.toString()); + } + + return result; + } + + //-------------------------------------- + // PRIVATE CLASS METHODS + //-------------------------------------- + + static private function serializeObject(sourceObject:Object, parent:XML, elementName:String = null):XML + { + var x:int; + + if(sourceObject == null) + { + //no-op + } + else if(sourceObject is XML || Reflection.isScalar(sourceObject)) + { + parent.appendChild(sourceObject); + } + else if(sourceObject is Date) + { + parent.appendChild((sourceObject as Date).getTime()); + } + else if(sourceObject is IXmlSerializable || "toXML" in sourceObject) + { + parent.appendChild(sourceObject.toXML()); + } + else if(Reflection.isArrayType(sourceObject)) + { + for(x = 0; x < sourceObject.length; x++) + { + parent.appendChild(serializeObject(sourceObject[x], <{elementName || "_" + x}/>)); + } + } + else if(Reflection.isAssociativeArray(sourceObject)) + { + var key:String; + for(key in sourceObject) + { + parent.appendChild(serializeObject(sourceObject[key], <{key}/>)); + } + } + else + { + //Loop over all of the variables and accessors in the class and + //serialize them along with their values. + var typeInfo:TypeInfo = Reflection.getTypeInfo(sourceObject); + for each(var field:AbstractMemberInfo in typeInfo.allMembers) + { + if(field is AbstractFieldInfo && !AbstractFieldInfo(field).isStatic && AbstractFieldInfo(field).canRead + //don't serialize constant fields if told not to, but always serialize read-only properties + && (s_serializeConstants || AbstractFieldInfo(field).canWrite || field is PropertyInfo) && field.getMetadataByName("Transient") == null) + { + var metadata:XmlMetadata = field.getMetadataByClass(XmlMetadata) as XmlMetadata; + var nodeName:String = (metadata != null ? metadata.nodeName || field.name : field.name); + if(metadata != null && metadata.flattenArray) + { + serializeObject(sourceObject[field.name], parent, nodeName); + } + else + { + parent.appendChild(serializeObject(sourceObject[field.name], <{nodeName}/>)); + } + } + } + + if(typeInfo.isDynamic) + { + for(var dynamicField:String in sourceObject) + { + //won't this always be true if we'e able to iterate it with a for/in? + if(sourceObject.hasOwnProperty(dynamicField)) + { + parent.appendChild(serializeObject(sourceObject[dynamicField], <{dynamicField}/>)); + } + } + } + } + return parent; + } + + static private function setValue(obj:Object, name:String, value:String):void + { + if(/^\d*\.?\d+$/.test(value)) + { + obj[getKey(obj, name)] = parseFloat(value); + } + else + { + obj[getKey(obj, name)] = value; + } + } + + static private function getKey(object:Object, name:String):Object + { + if(object is Array) + { + if(name.charAt(0) == "_") + { + return parseInt(name.substring(1)); + } + else + { + return object.length; + } + } + return name; + } } -} \ No newline at end of file +} diff --git a/test/mxmlc_config.xml b/test/mxmlc_config.xml index 3b7f163..9012e00 100644 --- a/test/mxmlc_config.xml +++ b/test/mxmlc_config.xml @@ -1,12 +1,12 @@ - - - ClassMetadata - FieldMetadata - CtorMetadata - Suite - - true - + + + ClassMetadata + FieldMetadata + CtorMetadata + Suite + + true + diff --git a/test/src/MainTestSuite.as b/test/src/MainTestSuite.as index 45968df..172aab5 100644 --- a/test/src/MainTestSuite.as +++ b/test/src/MainTestSuite.as @@ -17,22 +17,22 @@ import test.nexus.utils.serialization.json.*; [Suite] public class MainTestSuite { - public var basic : BasicTest; - - public var enum : EnumTest; - public var enumSet : EnumSetTest; - - public var reflection : ReflectionTest; - public var reflection_typeInfo : TypeInfoTest; - - public var objectUtils : ObjectUtilsTest; - public var json : JsonSerializerTest; - - public var rngLehmer : LehmerGeneratorTest; - public var rngTinymt : TinyMTGeneratorTest; - public var rngNative : NativeRandomGeneratorTest; - - public var hmac : HMACTest; + public var basic : BasicTest; + + public var enum : EnumTest; + public var enumSet : EnumSetTest; + + public var reflection : ReflectionTest; + public var reflection_typeInfo : TypeInfoTest; + + public var objectUtils : ObjectUtilsTest; + public var json : JsonSerializerTest; + + public var rngLehmer : LehmerGeneratorTest; + public var rngTinymt : TinyMTGeneratorTest; + public var rngNative : NativeRandomGeneratorTest; + + public var hmac : HMACTest; } -} \ No newline at end of file +} diff --git a/test/src/NexuslibTestRunner.as b/test/src/NexuslibTestRunner.as index f20e5dd..a4cbb23 100644 --- a/test/src/NexuslibTestRunner.as +++ b/test/src/NexuslibTestRunner.as @@ -13,29 +13,29 @@ import flash.system.Capabilities; [SWF(width="800",height="600",backgroundColor="#333333",frameRate="30")] public class NexuslibTestRunner extends Sprite { - private var core:TextCore; - - public function NexuslibTestRunner() - { - //Use to trigger the FPL warning - /* - var stage3D:Stage3D = stage.stage3Ds[0]; - stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, function(e:Event):void - { - trace(stage.stage3Ds[0].context3D); - }); - stage.stage3Ds[0].requestContext3D(); - //*/ - - core = new TextCore(); - core.textPrinter.fontFamily = "Consolas"; - core.textPrinter.fontSize = 12; - core.textPrinter.header = "nexuslib\nFlash Player version: " + Capabilities.version; - core.textPrinter.hideLocalPaths = true; - core.textPrinter.traceOnComplete = false; - core.start(MainTestSuite, null, this); - //core.start(PerformanceTestSuite, null, this); - } + private var core:TextCore; + + public function NexuslibTestRunner() + { + //Use to trigger the FPL warning + /* + var stage3D:Stage3D = stage.stage3Ds[0]; + stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, function(e:Event):void + { + trace(stage.stage3Ds[0].context3D); + }); + stage.stage3Ds[0].requestContext3D(); + //*/ + + core = new TextCore(); + core.textPrinter.fontFamily = "Consolas"; + core.textPrinter.fontSize = 12; + core.textPrinter.header = "nexuslib\nFlash Player version: " + Capabilities.version; + core.textPrinter.hideLocalPaths = true; + core.textPrinter.traceOnComplete = false; + core.start(MainTestSuite, null, this); + //core.start(PerformanceTestSuite, null, this); + } } -} \ No newline at end of file +} diff --git a/test/src/PerformanceTestSuite.as b/test/src/PerformanceTestSuite.as index 64c8d11..5750fef 100644 --- a/test/src/PerformanceTestSuite.as +++ b/test/src/PerformanceTestSuite.as @@ -16,7 +16,7 @@ import test.nexus.utils.serialization.json.*; [Suite] public class PerformanceTestSuite { - public var reflection : ReflectionPerfTest; + public var reflection : ReflectionPerfTest; } -} \ No newline at end of file +} diff --git a/test/src/mock/BadEnum.as b/test/src/mock/BadEnum.as index c672c3d..91085c3 100644 --- a/test/src/mock/BadEnum.as +++ b/test/src/mock/BadEnum.as @@ -13,7 +13,7 @@ import nexus.Enum; */ public class BadEnum extends Enum { - public static const Value1:MockEnum = new MockEnum(); + public static const Value1:MockEnum = new MockEnum(); } -} \ No newline at end of file +} diff --git a/test/src/mock/BadEnum2.as b/test/src/mock/BadEnum2.as index 10a6ea4..3667272 100644 --- a/test/src/mock/BadEnum2.as +++ b/test/src/mock/BadEnum2.as @@ -13,10 +13,10 @@ import nexus.Enum; */ public class BadEnum2 extends Enum { - {Enum.initialize(BadEnum2); } - - public static var Value1:BadEnum2 = new BadEnum2(); - public static var Value2:BadEnum2 = new BadEnum2(); + {Enum.initialize(BadEnum2); } + + public static var Value1:BadEnum2 = new BadEnum2(); + public static var Value2:BadEnum2 = new BadEnum2(); } -} \ No newline at end of file +} diff --git a/test/src/mock/BadEnum3.as b/test/src/mock/BadEnum3.as index 7531444..03fd8b1 100644 --- a/test/src/mock/BadEnum3.as +++ b/test/src/mock/BadEnum3.as @@ -13,8 +13,8 @@ import nexus.Enum; */ public class BadEnum3 extends Enum { - public static var Value1:BadEnum3 = new BadEnum3(); - public static var Value2:BadEnum3 = new BadEnum3(); + public static var Value1:BadEnum3 = new BadEnum3(); + public static var Value2:BadEnum3 = new BadEnum3(); } -} \ No newline at end of file +} diff --git a/test/src/mock/MockEnum.as b/test/src/mock/MockEnum.as index 9431976..8572c46 100644 --- a/test/src/mock/MockEnum.as +++ b/test/src/mock/MockEnum.as @@ -11,34 +11,34 @@ import nexus.utils.serialization.json.IJsonSerializable; public class MockEnum extends Enum implements IJsonSerializable { - public static const Value1 : MockEnum = new MockEnum(); - public static const Value2 : MockEnum = new MockEnum(); - public static const Value3 : MockEnum = new MockEnum(); - - nexuslib_internal static const Value3:MockEnum = new MockEnum(); - - public static const FOO:String = "FOO"; - - public static function get All():EnumSet { return Enum.values(MockEnum); } + public static const Value1 : MockEnum = new MockEnum(); + public static const Value2 : MockEnum = new MockEnum(); + public static const Value3 : MockEnum = new MockEnum(); + + nexuslib_internal static const Value3:MockEnum = new MockEnum(); + + public static const FOO:String = "FOO"; + + public static function get All():EnumSet { return Enum.values(MockEnum); } /* INTERFACE nexus.utils.serialization.json.IJsonSerializable */ - - public function toJSON(key:String):Object - { - return this.name; - } + + public function toJSON(key:String):Object + { + return this.name; + } - public function jsonLikeType(data:Object):Boolean - { - var str : String = data + ""; - return false; - } + public function jsonLikeType(data:Object):Boolean + { + var str : String = data + ""; + return false; + } public static function fromNative(data:Object):MockEnum - { + { var enum : Object = Enum.fromString(MockEnum, data +""); - return enum as MockEnum; - } + return enum as MockEnum; + } } -} \ No newline at end of file +} diff --git a/test/src/mock/MockEnum2.as b/test/src/mock/MockEnum2.as index 1cf1329..06ac290 100644 --- a/test/src/mock/MockEnum2.as +++ b/test/src/mock/MockEnum2.as @@ -10,9 +10,9 @@ import nexus.Enum; public class MockEnum2 extends Enum { - public static const Value1:MockEnum2 = new MockEnum2(); - public static const Value2:MockEnum2 = new MockEnum2(); - public static const Value3:MockEnum2 = new MockEnum2(); + public static const Value1:MockEnum2 = new MockEnum2(); + public static const Value2:MockEnum2 = new MockEnum2(); + public static const Value3:MockEnum2 = new MockEnum2(); } -} \ No newline at end of file +} diff --git a/test/src/mock/foo/IFoo.as b/test/src/mock/foo/IFoo.as index 314aadf..edc49f3 100644 --- a/test/src/mock/foo/IFoo.as +++ b/test/src/mock/foo/IFoo.as @@ -3,10 +3,10 @@ package mock.foo public interface IFoo { - [MetadataOnInterface(foo="foo")] - function get publicProperty():int; - - function publicFun(arg1:Date, arg2:Number = 556, arg3:*= null):String; + [MetadataOnInterface(foo="foo")] + function get publicProperty():int; + + function publicFun(arg1:Date, arg2:Number = 556, arg3:*= null):String; } -} \ No newline at end of file +} diff --git a/test/src/mock/foo/SubObject.as b/test/src/mock/foo/SubObject.as index 72429a6..eb1e7b9 100644 --- a/test/src/mock/foo/SubObject.as +++ b/test/src/mock/foo/SubObject.as @@ -5,52 +5,52 @@ import flash.utils.*; public final class SubObject { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_timing : Date; - private var m_array : Array; - private var m_timeVec : Vector.; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function SubObject() - { - - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - public function get array():Array { return m_array; } - - public function get date():Date { return m_timing; } - public function set date(value:Date):void - { - m_timing = value; - } - - public function get vector():Vector. { return m_timeVec; } - public function set vector(value:Vector.):void - { - m_timeVec = value; - } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_timing : Date; + private var m_array : Array; + private var m_timeVec : Vector.; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function SubObject() + { + + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + public function get array():Array { return m_array; } + + public function get date():Date { return m_timing; } + public function set date(value:Date):void + { + m_timing = value; + } + + public function get vector():Vector. { return m_timeVec; } + public function set vector(value:Vector.):void + { + m_timeVec = value; + } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- } -} \ No newline at end of file +} diff --git a/test/src/mock/foo/bar/BaseClass.as b/test/src/mock/foo/bar/BaseClass.as index 16caf7e..17ff1e3 100644 --- a/test/src/mock/foo/bar/BaseClass.as +++ b/test/src/mock/foo/bar/BaseClass.as @@ -10,13 +10,13 @@ import nexus.errors.NotImplementedError; [ClassMetadata(on="BaseClass")] public class BaseClass { - include "_BaseClassContent.as"; - - public function BaseClass() - { - m_baseVector = new Vector.(); - m_subObj2 = new SubObject(); - } + include "_BaseClassContent.as"; + + public function BaseClass() + { + m_baseVector = new Vector.(); + m_subObj2 = new SubObject(); + } } -} \ No newline at end of file +} diff --git a/test/src/mock/foo/bar/CustomSerializationClass.as b/test/src/mock/foo/bar/CustomSerializationClass.as index cf0c926..971be8f 100644 --- a/test/src/mock/foo/bar/CustomSerializationClass.as +++ b/test/src/mock/foo/bar/CustomSerializationClass.as @@ -5,34 +5,34 @@ import nexus.utils.serialization.json.IJsonSerializable; public class CustomSerializationClass extends BaseClass implements IJsonSerializable { - private static var s_id:int = 1; - - static public function get id():int - { - return s_id; - } - - public function CustomSerializationClass() - { - this.baseString = "CustomSerializationClass" + (++s_id); - } - - public function toJSON(key:String):Object - { - return this.baseString; - } - - public function jsonLikeType(data:Object):Boolean - { - return data is String; - } - - public static function fromNative(data:Object):Object - { - var result:CustomSerializationClass = new CustomSerializationClass(); - result.baseString = data + ""; - return result; - } + private static var s_id:int = 1; + + static public function get id():int + { + return s_id; + } + + public function CustomSerializationClass() + { + this.baseString = "CustomSerializationClass" + (++s_id); + } + + public function toJSON(key:String):Object + { + return this.baseString; + } + + public function jsonLikeType(data:Object):Boolean + { + return data is String; + } + + public static function fromNative(data:Object):Object + { + var result:CustomSerializationClass = new CustomSerializationClass(); + result.baseString = data + ""; + return result; + } } -} \ No newline at end of file +} diff --git a/test/src/mock/foo/bar/DynamicBaseClass.as b/test/src/mock/foo/bar/DynamicBaseClass.as index 7c80cc2..8d456cc 100644 --- a/test/src/mock/foo/bar/DynamicBaseClass.as +++ b/test/src/mock/foo/bar/DynamicBaseClass.as @@ -10,13 +10,13 @@ import nexus.errors.NotImplementedError; [ClassMetadata(on="DynamicBaseClass")] dynamic public class DynamicBaseClass { - include "_BaseClassContent.as"; - - public function DynamicBaseClass() - { - m_baseVector = new Vector.(); - m_subObj2 = new SubObject(); - } + include "_BaseClassContent.as"; + + public function DynamicBaseClass() + { + m_baseVector = new Vector.(); + m_subObj2 = new SubObject(); + } } -} \ No newline at end of file +} diff --git a/test/src/mock/foo/bar/FinalClass.as b/test/src/mock/foo/bar/FinalClass.as index 6db2ca2..eedfaae 100644 --- a/test/src/mock/foo/bar/FinalClass.as +++ b/test/src/mock/foo/bar/FinalClass.as @@ -5,40 +5,40 @@ import flash.utils.*; public final class FinalClass extends TestClass { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function FinalClass(ctorArgReq:Boolean=true, ctorArgOpt:String=null) - { - super(ctorArgReq, ctorArgOpt); - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - [MethodMetadata(on="FinalClass")] - override public function baseMethod(arg1:String, arg2:String="", arg3:Array=null):Object - { - return super.baseMethod(arg1, arg2, arg3); - } - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function FinalClass(ctorArgReq:Boolean=true, ctorArgOpt:String=null) + { + super(ctorArgReq, ctorArgOpt); + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + [MethodMetadata(on="FinalClass")] + override public function baseMethod(arg1:String, arg2:String="", arg3:Array=null):Object + { + return super.baseMethod(arg1, arg2, arg3); + } + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- } -} \ No newline at end of file +} diff --git a/test/src/mock/foo/bar/TestClass.as b/test/src/mock/foo/bar/TestClass.as index 98b074d..9a75986 100644 --- a/test/src/mock/foo/bar/TestClass.as +++ b/test/src/mock/foo/bar/TestClass.as @@ -7,119 +7,119 @@ import mock.testing_namespace; [ClassMetadata(param="value", on="TestClass")] public dynamic class TestClass extends BaseClass implements IFoo { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - public static const staticConst:String = "staticConst"; - public static var staticVar:String = "staticVar"; - - private static const privateStaticConst:String = "privateStaticConst"; - private static var privateStaticVar:String = "privateStaticVar"; - - protected static const protectedStaticConst:String = "protectedStaticConst"; - protected static var protectedStaticVar:String = "protectedStaticvar"; + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + public static const staticConst:String = "staticConst"; + public static var staticVar:String = "staticVar"; + + private static const privateStaticConst:String = "privateStaticConst"; + private static var privateStaticVar:String = "privateStaticVar"; + + protected static const protectedStaticConst:String = "protectedStaticConst"; + protected static var protectedStaticVar:String = "protectedStaticvar"; - testing_namespace static const namespacedStaticConst:String = "namespacedStaticConst"; - testing_namespace static var namespacedStaticVar:String = "namespacedStaticvar"; - - [Embed(source="test.xml", mimeType="application/octet-stream")] - public static const embed : Class; - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_privateVar:int; - protected var m_protectedVar: int; - testing_namespace var m_namespacedVar : int; + testing_namespace static const namespacedStaticConst:String = "namespacedStaticConst"; + testing_namespace static var namespacedStaticVar:String = "namespacedStaticvar"; + + [Embed(source="test.xml", mimeType="application/octet-stream")] + public static const embed : Class; + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_privateVar:int; + protected var m_protectedVar: int; + testing_namespace var m_namespacedVar : int; private var m_circular:TestClass; - - [Embed(source="test.xml", mimeType="application/octet-stream")] - public const instanceEmbed:Class; - - [FieldMetadata(on="TestClass", param="public var param")] - public var publicVar:int; - - public namespace class_namespace = "mock.foo.bar::TestClass.class_namespace"; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - [CtorMetadata(param="value", param2="value2")] - public function TestClass(ctorArgReq:Boolean=true, ctorArgOpt:String=null) - { - - } - - //-------------------------------------- - // GETTER/SETTERS - //-------------------------------------- - - [FieldMetadata(param="value", param2="value2")] - public function get publicProperty():int { return m_privateVar; } - public function set publicProperty(value:int):void - { - m_privateVar = value; - } - - public static function get staticProperty():String { return protectedStaticVar; } + + [Embed(source="test.xml", mimeType="application/octet-stream")] + public const instanceEmbed:Class; + + [FieldMetadata(on="TestClass", param="public var param")] + public var publicVar:int; + + public namespace class_namespace = "mock.foo.bar::TestClass.class_namespace"; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + [CtorMetadata(param="value", param2="value2")] + public function TestClass(ctorArgReq:Boolean=true, ctorArgOpt:String=null) + { + + } + + //-------------------------------------- + // GETTER/SETTERS + //-------------------------------------- + + [FieldMetadata(param="value", param2="value2")] + public function get publicProperty():int { return m_privateVar; } + public function set publicProperty(value:int):void + { + m_privateVar = value; + } + + public static function get staticProperty():String { return protectedStaticVar; } public function get circular():TestClass { return m_circular;} public function set circular(value:TestClass):void { m_circular = value; } - - //-------------------------------------- - // PUBLIC INSTANCE METHODS - //-------------------------------------- - - override public function baseMethod(arg1:String, arg2:String="", arg3:Array=null):Object - { - return m_privateVar + arg1 + (arg2 != null ? arg2 : ""); - } - - [MethodMetadata(on="TestClass", type="final function")] - public final function publicFinalFun(arg1:Vector.):* - { - return ""; - } - - public function publicFun(arg1:Date, arg2:Number=556, arg3:*=null):String - { - return arg2 == 556 ? "default" : "provided"; - } - - //-------------------------------------- - // PUBLIC CLASS METHODS - //-------------------------------------- - - public static function foo():void - { - - } - - //-------------------------------------- - // PRIVATE & PROTECTED INSTANCE METHODS - //-------------------------------------- - - protected function protectedMethod(p1:int, p2:String):void - { - - } - - //-------------------------------------- - // INTERNAL & NAMESPACED INSTANCE METHODS - //-------------------------------------- - - [MethodMetadata(on="TestClass", type="namespaced method")] - testing_namespace function namespacedMethod(arg1:String, arg2:String=null, arg3:Vector.=null):Object - { - return m_privateVar + arg1 + (arg2 != null ? arg2 : ""); - } + + //-------------------------------------- + // PUBLIC INSTANCE METHODS + //-------------------------------------- + + override public function baseMethod(arg1:String, arg2:String="", arg3:Array=null):Object + { + return m_privateVar + arg1 + (arg2 != null ? arg2 : ""); + } + + [MethodMetadata(on="TestClass", type="final function")] + public final function publicFinalFun(arg1:Vector.):* + { + return ""; + } + + public function publicFun(arg1:Date, arg2:Number=556, arg3:*=null):String + { + return arg2 == 556 ? "default" : "provided"; + } + + //-------------------------------------- + // PUBLIC CLASS METHODS + //-------------------------------------- + + public static function foo():void + { + + } + + //-------------------------------------- + // PRIVATE & PROTECTED INSTANCE METHODS + //-------------------------------------- + + protected function protectedMethod(p1:int, p2:String):void + { + + } + + //-------------------------------------- + // INTERNAL & NAMESPACED INSTANCE METHODS + //-------------------------------------- + + [MethodMetadata(on="TestClass", type="namespaced method")] + testing_namespace function namespacedMethod(arg1:String, arg2:String=null, arg3:Vector.=null):Object + { + return m_privateVar + arg1 + (arg2 != null ? arg2 : ""); + } } -} \ No newline at end of file +} diff --git a/test/src/mock/foo/bar/_BaseClassContent.as b/test/src/mock/foo/bar/_BaseClassContent.as index 81823b7..35f95e0 100644 --- a/test/src/mock/foo/bar/_BaseClassContent.as +++ b/test/src/mock/foo/bar/_BaseClassContent.as @@ -11,7 +11,7 @@ private var m_enum : MockEnum; [MethodMetadata(on="BaseClass")] public function baseMethod(arg1:String, arg2:String="", arg3:Array=null):Object { - throw new NotImplementedError(); + throw new NotImplementedError(); } [PropertyMetadata(on="BaseClass", type="final")] @@ -21,7 +21,7 @@ public final function get baseVector():Vector. { return m_baseVector; } public function get subObj1():SubObject { return m_subObj1; } public function set subObj1(value:SubObject):void { - m_subObj1 = value; + m_subObj1 = value; } public function get mockEnum():MockEnum { return m_enum; } @@ -34,5 +34,5 @@ public function get subObj2():SubObject { return m_subObj2; } public function get baseString():String{ return m_baseString; } public function set baseString(value:String):void { - m_baseString = value; -} \ No newline at end of file + m_baseString = value; +} diff --git a/test/src/mock/testing_namespace.as b/test/src/mock/testing_namespace.as index 6026856..89d9635 100644 --- a/test/src/mock/testing_namespace.as +++ b/test/src/mock/testing_namespace.as @@ -1,4 +1,4 @@ package mock { - public namespace testing_namespace = "http://mock.testing_namespace"; -} \ No newline at end of file + public namespace testing_namespace = "http://mock.testing_namespace"; +} diff --git a/test/src/test/BasicTest.as b/test/src/test/BasicTest.as index 294fc10..4e5edcb 100644 --- a/test/src/test/BasicTest.as +++ b/test/src/test/BasicTest.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -13,76 +13,76 @@ import asunit.framework.TestCase; */ public class BasicTest extends TestCase { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function BasicTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - - } - - override protected function tearDown():void - { - - } - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_vectorEquality():void - { - assertTrue( "new Vector.<*>() is Vector.<*>", new Vector.<*>() is Vector.<*>); - assertFalse("new Vector.<*>() is Vector.", new Vector.<*>() is Vector.); - assertTrue( "Vector.<*> is Class", Vector.<*> is Class); - - assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.<*>); - assertTrue( "new Vector.() is Vector.<*>", new Vector.() is Vector.); - assertTrue( "Vector. is Class", Vector. is Class); - - assertTrue( "new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); - assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "Vector. is Class", Vector. is Class); - - assertFalse("new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); - assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "Vector. is Class", Vector. is Class); - - assertFalse("new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); - assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "Vector. is Class", Vector. is Class); - - assertFalse("new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); - assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "Vector. is Class", Vector. is Class); - - assertTrue("new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); - assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); - assertTrue( "Vector. is Class", Vector. is Class); - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function BasicTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + + } + + override protected function tearDown():void + { + + } + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_vectorEquality():void + { + assertTrue( "new Vector.<*>() is Vector.<*>", new Vector.<*>() is Vector.<*>); + assertFalse("new Vector.<*>() is Vector.", new Vector.<*>() is Vector.); + assertTrue( "Vector.<*> is Class", Vector.<*> is Class); + + assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.<*>); + assertTrue( "new Vector.() is Vector.<*>", new Vector.() is Vector.); + assertTrue( "Vector. is Class", Vector. is Class); + + assertTrue( "new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); + assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "Vector. is Class", Vector. is Class); + + assertFalse("new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); + assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "Vector. is Class", Vector. is Class); + + assertFalse("new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); + assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "Vector. is Class", Vector. is Class); + + assertFalse("new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); + assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "Vector. is Class", Vector. is Class); + + assertTrue("new Vector.() is Vector.<*>", new Vector.() is Vector.<*>); + assertFalse("new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "new Vector.() is Vector.", new Vector.() is Vector.); + assertTrue( "Vector. is Class", Vector. is Class); + } +} + } - -} \ No newline at end of file diff --git a/test/src/test/nexus/EnumSetTest.as b/test/src/test/nexus/EnumSetTest.as index 5d3c46f..1910fdf 100644 --- a/test/src/test/nexus/EnumSetTest.as +++ b/test/src/test/nexus/EnumSetTest.as @@ -15,110 +15,110 @@ import nexus.*; */ public class EnumSetTest extends TestCase { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function EnumSetTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - - } - - override protected function tearDown():void - { - - } - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_intersects():void - { - assertTrue(MockEnum.All.intersects(MockEnum.Value1)); - assertTrue(MockEnum.All.intersects(MockEnum.Value2)); - assertTrue(MockEnum.All.intersects(MockEnum.Value3)); - - assertTrue(MockEnum.All.intersects([MockEnum.Value1, MockEnum.Value2])); - assertTrue(MockEnum.All.intersects([MockEnum.Value1, MockEnum.Value3])); - assertTrue(MockEnum.All.intersects([MockEnum.Value2, MockEnum.Value3])); - - assertTrue(MockEnum.All.intersects([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3])); - - assertFalse(MockEnum.All.intersects(MockEnum2.Value1)); - - assertTrue(MockEnum.All.intersects(MockEnum.All)); - assertTrue(MockEnum.All.intersects(Enum.values(MockEnum))); - - assertTrue(MockEnum.All.intersects(MockEnum.Value2)); - assertTrue(MockEnum.All.intersects([MockEnum.Value2])); - assertTrue(MockEnum.All.intersects(EnumSet.fromArray([MockEnum.Value2]))); - //assertTrue(MockEnum.All.intersects(new [MockEnum.Value2])); - - assertTrue(EnumSet.fromArgs(MockEnum.Value1, MockEnum2.Value1).intersects(EnumSet.fromArray([MockEnum.Value1, MockEnum2.Value1]))); - assertTrue(EnumSet.fromArgs(MockEnum.Value1, MockEnum2.Value1).intersects(EnumSet.fromArray([MockEnum.Value1]))); - assertTrue(EnumSet.fromArgs(MockEnum2.Value1).intersects(EnumSet.fromArray([MockEnum.Value1, MockEnum2.Value1]))); - - assertFalse(MockEnum.All.intersects([])); - assertFalse(MockEnum.All.intersects(null)); - assertFalse(MockEnum.All.intersects(Array)); - assertFalse(MockEnum.All.intersects(new EnumSet())); - } - - public function test_equals():void - { - assertFalse(MockEnum.All.equals(MockEnum.Value1)); - assertFalse(MockEnum.All.equals(MockEnum.Value2)); - assertFalse(MockEnum.All.equals(MockEnum.Value3)); - - assertFalse(MockEnum.All.equals([MockEnum.Value1, MockEnum.Value2])); - assertFalse(MockEnum.All.equals([MockEnum.Value1, MockEnum.Value3])); - assertFalse(MockEnum.All.equals([MockEnum.Value2, MockEnum.Value3])); - - assertFalse(MockEnum.All.equals([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3])); - assertTrue(MockEnum.All.equals([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3, MockEnum.nexuslib_internal::Value3])); - - assertFalse(MockEnum.All.equals(MockEnum2.Value1)); - - assertTrue(MockEnum.All.equals(MockEnum.All)); - assertTrue(MockEnum.All.equals(Enum.values(MockEnum))); - assertTrue(MockEnum.All.equals(EnumSet.fromArray(MockEnum.All.getValues()))); - - assertFalse(MockEnum.All.equals(MockEnum.Value2)); - assertFalse(MockEnum.All.equals([MockEnum.Value2])); - assertFalse(MockEnum.All.equals(EnumSet.fromArray([MockEnum.Value2]))); - //assertTrue(MockEnum.All.equals(new [MockEnum.Value2])); - - assertTrue(EnumSet.fromArgs(MockEnum.Value1, MockEnum2.Value1).equals(EnumSet.fromArray([MockEnum.Value1, MockEnum2.Value1]))); - assertFalse(EnumSet.fromArgs(MockEnum.Value1, MockEnum2.Value1).equals(EnumSet.fromArray([MockEnum.Value1]))); - assertFalse(EnumSet.fromArgs(MockEnum2.Value1).equals(EnumSet.fromArray([MockEnum.Value1, MockEnum2.Value1]))); - - assertFalse(MockEnum.All.equals([])); - assertFalse(MockEnum.All.equals(null)); - assertFalse(MockEnum.All.equals(Array)); - assertFalse(MockEnum.All.equals(new EnumSet())); - } - - //-------------------------------------- - // UTILITY METHODS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function EnumSetTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + + } + + override protected function tearDown():void + { + + } + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_intersects():void + { + assertTrue(MockEnum.All.intersects(MockEnum.Value1)); + assertTrue(MockEnum.All.intersects(MockEnum.Value2)); + assertTrue(MockEnum.All.intersects(MockEnum.Value3)); + + assertTrue(MockEnum.All.intersects([MockEnum.Value1, MockEnum.Value2])); + assertTrue(MockEnum.All.intersects([MockEnum.Value1, MockEnum.Value3])); + assertTrue(MockEnum.All.intersects([MockEnum.Value2, MockEnum.Value3])); + + assertTrue(MockEnum.All.intersects([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3])); + + assertFalse(MockEnum.All.intersects(MockEnum2.Value1)); + + assertTrue(MockEnum.All.intersects(MockEnum.All)); + assertTrue(MockEnum.All.intersects(Enum.values(MockEnum))); + + assertTrue(MockEnum.All.intersects(MockEnum.Value2)); + assertTrue(MockEnum.All.intersects([MockEnum.Value2])); + assertTrue(MockEnum.All.intersects(EnumSet.fromArray([MockEnum.Value2]))); + //assertTrue(MockEnum.All.intersects(new [MockEnum.Value2])); + + assertTrue(EnumSet.fromArgs(MockEnum.Value1, MockEnum2.Value1).intersects(EnumSet.fromArray([MockEnum.Value1, MockEnum2.Value1]))); + assertTrue(EnumSet.fromArgs(MockEnum.Value1, MockEnum2.Value1).intersects(EnumSet.fromArray([MockEnum.Value1]))); + assertTrue(EnumSet.fromArgs(MockEnum2.Value1).intersects(EnumSet.fromArray([MockEnum.Value1, MockEnum2.Value1]))); + + assertFalse(MockEnum.All.intersects([])); + assertFalse(MockEnum.All.intersects(null)); + assertFalse(MockEnum.All.intersects(Array)); + assertFalse(MockEnum.All.intersects(new EnumSet())); + } + + public function test_equals():void + { + assertFalse(MockEnum.All.equals(MockEnum.Value1)); + assertFalse(MockEnum.All.equals(MockEnum.Value2)); + assertFalse(MockEnum.All.equals(MockEnum.Value3)); + + assertFalse(MockEnum.All.equals([MockEnum.Value1, MockEnum.Value2])); + assertFalse(MockEnum.All.equals([MockEnum.Value1, MockEnum.Value3])); + assertFalse(MockEnum.All.equals([MockEnum.Value2, MockEnum.Value3])); + + assertFalse(MockEnum.All.equals([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3])); + assertTrue(MockEnum.All.equals([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3, MockEnum.nexuslib_internal::Value3])); + + assertFalse(MockEnum.All.equals(MockEnum2.Value1)); + + assertTrue(MockEnum.All.equals(MockEnum.All)); + assertTrue(MockEnum.All.equals(Enum.values(MockEnum))); + assertTrue(MockEnum.All.equals(EnumSet.fromArray(MockEnum.All.getValues()))); + + assertFalse(MockEnum.All.equals(MockEnum.Value2)); + assertFalse(MockEnum.All.equals([MockEnum.Value2])); + assertFalse(MockEnum.All.equals(EnumSet.fromArray([MockEnum.Value2]))); + //assertTrue(MockEnum.All.equals(new [MockEnum.Value2])); + + assertTrue(EnumSet.fromArgs(MockEnum.Value1, MockEnum2.Value1).equals(EnumSet.fromArray([MockEnum.Value1, MockEnum2.Value1]))); + assertFalse(EnumSet.fromArgs(MockEnum.Value1, MockEnum2.Value1).equals(EnumSet.fromArray([MockEnum.Value1]))); + assertFalse(EnumSet.fromArgs(MockEnum2.Value1).equals(EnumSet.fromArray([MockEnum.Value1, MockEnum2.Value1]))); + + assertFalse(MockEnum.All.equals([])); + assertFalse(MockEnum.All.equals(null)); + assertFalse(MockEnum.All.equals(Array)); + assertFalse(MockEnum.All.equals(new EnumSet())); + } + + //-------------------------------------- + // UTILITY METHODS + //-------------------------------------- +} + } - -} \ No newline at end of file diff --git a/test/src/test/nexus/EnumTest.as b/test/src/test/nexus/EnumTest.as index f04d0e5..fc31742 100644 --- a/test/src/test/nexus/EnumTest.as +++ b/test/src/test/nexus/EnumTest.as @@ -16,160 +16,160 @@ import nexus.*; */ public class EnumTest extends TestCase { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function EnumTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - - } - - override protected function tearDown():void - { - - } - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_name():void - { - assertEquals("Value1", MockEnum2.Value1.name); - assertEquals("Value2", MockEnum2.Value2.name); - assertEquals("Value3", MockEnum2.Value3.name); - - assertEquals("Value3", MockEnum.nexuslib_internal::Value3.name); - } - - public function test_fullname():void - { - assertEquals("mock::MockEnum.Value3", MockEnum.Value3.fullname); - assertEquals("mock::MockEnum.Value3", MockEnum.nexuslib_internal::Value3.fullname); - assertEquals("mock::MockEnum2.Value1", MockEnum2.Value1.fullname); - } - - public function test_value():void - { - assertEquals(1, MockEnum2.Value1.value); - assertEquals(2, MockEnum2.Value2.value); - assertEquals(4, MockEnum2.Value3.value); - } - - public function test_equals():void - { - assertNotSame(MockEnum.Value1, MockEnum.Value2, MockEnum.Value3); - - assertSame(MockEnum.Value1, MockEnum.Value1); - - assertTrue(MockEnum.Value1 == MockEnum.Value1); - assertFalse(MockEnum.Value1 == MockEnum.Value2); - assertFalse(MockEnum.Value1 == MockEnum.Value3); - - assertTrue(MockEnum.Value1.equals(MockEnum.Value1)); - assertFalse(MockEnum.Value1.equals(MockEnum.Value2)); - assertFalse(MockEnum.Value1.equals(MockEnum.Value3)); - - assertFalse(MockEnum.Value3.equals([MockEnum.Value1, MockEnum.Value2])); - assertFalse(MockEnum.Value3.equals([MockEnum.Value1, MockEnum.Value3])); - assertFalse(MockEnum.Value3.equals([MockEnum.Value2, MockEnum.Value3])); - - assertFalse(MockEnum.Value3.equals([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3])); - - //compile-time type error. Enums ftw. - //assertFalse(MockEnum.Value1 == MockEnum2.Value1); - assertFalse(MockEnum.Value1.equals(MockEnum2.Value1)); - - assertTrue(MockEnum.Value2.equals(MockEnum.Value2)); - assertTrue(MockEnum.Value2.equals([MockEnum.Value2])); - assertTrue(MockEnum.Value2.equals(EnumSet.fromArray([MockEnum.Value2]))); - assertTrue(MockEnum.Value2.equals(EnumSet.fromArgs(MockEnum.Value2))); - assertTrue(MockEnum.Value2.equals(new [MockEnum.Value2])); - - assertFalse(MockEnum.Value2.equals([])); - assertFalse(MockEnum.Value2.equals(null)); - assertFalse(MockEnum.Value2.equals(Array)); - assertFalse(MockEnum.Value2.equals(new EnumSet())); - } - - public function test_intersects():void - { - assertTrue(MockEnum.Value1.intersects(MockEnum.Value1)); - assertFalse(MockEnum.Value1.intersects(MockEnum.Value2)); - assertFalse(MockEnum.Value1.intersects(MockEnum.Value3)); - - assertFalse(MockEnum.Value3.intersects([MockEnum.Value1, MockEnum.Value2])); - assertTrue(MockEnum.Value3.intersects([MockEnum.Value1, MockEnum.Value3])); - assertTrue(MockEnum.Value3.intersects([MockEnum.Value2, MockEnum.Value3])); - - assertTrue(MockEnum.Value3.intersects([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3])); - - assertFalse(MockEnum.Value1.intersects(MockEnum2.Value1)); - - assertTrue(MockEnum.Value2.intersects(MockEnum.Value2)); - assertTrue(MockEnum.Value2.intersects([MockEnum.Value2])); - assertTrue(MockEnum.Value2.equals(EnumSet.fromArray([MockEnum.Value2]))); - assertTrue(MockEnum.Value2.equals(EnumSet.fromArgs(MockEnum.Value2))); - assertTrue(MockEnum.Value2.intersects(new [MockEnum.Value2])); - - assertFalse(MockEnum.Value2.intersects([])); - assertFalse(MockEnum.Value2.intersects(null)); - assertFalse(MockEnum.Value2.intersects(Array)); - assertFalse(MockEnum.Value2.intersects(new EnumSet())); - } - - public function test_instantiation():void - { - assertThrows(IllegalOperationError, function():void { new MockEnum() } ); - - var fail : MockEnum; - assertThrows(IllegalOperationError, function():void { fail = new MockEnum() } ); - assertNull(fail); - } - - public function test_badEnum1():void - { - assertThrows(IllegalOperationError, function():void { BadEnum.Value1 } ); - - //should have thrown in the constructor and should not exist - assertThrows(TypeError, function():void { BadEnum.Value1 } ); - } - - public function test_badEnum2():void - { - assertThrows(SyntaxError, function():void { BadEnum2.Value1 } ); - } - - public function test_badEnum3():void - { - assertFalse(BadEnum3.Value1 == BadEnum3.Value2); - BadEnum3.Value1 = BadEnum3.Value2; - assertTrue(BadEnum3.Value1 == BadEnum3.Value2); - - assertThrows(SyntaxError, function():void { BadEnum3.Value1.name } ); - } - - //-------------------------------------- - // UTILITY METHODS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function EnumTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + + } + + override protected function tearDown():void + { + + } + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_name():void + { + assertEquals("Value1", MockEnum2.Value1.name); + assertEquals("Value2", MockEnum2.Value2.name); + assertEquals("Value3", MockEnum2.Value3.name); + + assertEquals("Value3", MockEnum.nexuslib_internal::Value3.name); + } + + public function test_fullname():void + { + assertEquals("mock::MockEnum.Value3", MockEnum.Value3.fullname); + assertEquals("mock::MockEnum.Value3", MockEnum.nexuslib_internal::Value3.fullname); + assertEquals("mock::MockEnum2.Value1", MockEnum2.Value1.fullname); + } + + public function test_value():void + { + assertEquals(1, MockEnum2.Value1.value); + assertEquals(2, MockEnum2.Value2.value); + assertEquals(4, MockEnum2.Value3.value); + } + + public function test_equals():void + { + assertNotSame(MockEnum.Value1, MockEnum.Value2, MockEnum.Value3); + + assertSame(MockEnum.Value1, MockEnum.Value1); + + assertTrue(MockEnum.Value1 == MockEnum.Value1); + assertFalse(MockEnum.Value1 == MockEnum.Value2); + assertFalse(MockEnum.Value1 == MockEnum.Value3); + + assertTrue(MockEnum.Value1.equals(MockEnum.Value1)); + assertFalse(MockEnum.Value1.equals(MockEnum.Value2)); + assertFalse(MockEnum.Value1.equals(MockEnum.Value3)); + + assertFalse(MockEnum.Value3.equals([MockEnum.Value1, MockEnum.Value2])); + assertFalse(MockEnum.Value3.equals([MockEnum.Value1, MockEnum.Value3])); + assertFalse(MockEnum.Value3.equals([MockEnum.Value2, MockEnum.Value3])); + + assertFalse(MockEnum.Value3.equals([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3])); + + //compile-time type error. Enums ftw. + //assertFalse(MockEnum.Value1 == MockEnum2.Value1); + assertFalse(MockEnum.Value1.equals(MockEnum2.Value1)); + + assertTrue(MockEnum.Value2.equals(MockEnum.Value2)); + assertTrue(MockEnum.Value2.equals([MockEnum.Value2])); + assertTrue(MockEnum.Value2.equals(EnumSet.fromArray([MockEnum.Value2]))); + assertTrue(MockEnum.Value2.equals(EnumSet.fromArgs(MockEnum.Value2))); + assertTrue(MockEnum.Value2.equals(new [MockEnum.Value2])); + + assertFalse(MockEnum.Value2.equals([])); + assertFalse(MockEnum.Value2.equals(null)); + assertFalse(MockEnum.Value2.equals(Array)); + assertFalse(MockEnum.Value2.equals(new EnumSet())); + } + + public function test_intersects():void + { + assertTrue(MockEnum.Value1.intersects(MockEnum.Value1)); + assertFalse(MockEnum.Value1.intersects(MockEnum.Value2)); + assertFalse(MockEnum.Value1.intersects(MockEnum.Value3)); + + assertFalse(MockEnum.Value3.intersects([MockEnum.Value1, MockEnum.Value2])); + assertTrue(MockEnum.Value3.intersects([MockEnum.Value1, MockEnum.Value3])); + assertTrue(MockEnum.Value3.intersects([MockEnum.Value2, MockEnum.Value3])); + + assertTrue(MockEnum.Value3.intersects([MockEnum.Value1, MockEnum.Value2, MockEnum.Value3])); + + assertFalse(MockEnum.Value1.intersects(MockEnum2.Value1)); + + assertTrue(MockEnum.Value2.intersects(MockEnum.Value2)); + assertTrue(MockEnum.Value2.intersects([MockEnum.Value2])); + assertTrue(MockEnum.Value2.equals(EnumSet.fromArray([MockEnum.Value2]))); + assertTrue(MockEnum.Value2.equals(EnumSet.fromArgs(MockEnum.Value2))); + assertTrue(MockEnum.Value2.intersects(new [MockEnum.Value2])); + + assertFalse(MockEnum.Value2.intersects([])); + assertFalse(MockEnum.Value2.intersects(null)); + assertFalse(MockEnum.Value2.intersects(Array)); + assertFalse(MockEnum.Value2.intersects(new EnumSet())); + } + + public function test_instantiation():void + { + assertThrows(IllegalOperationError, function():void { new MockEnum() } ); + + var fail : MockEnum; + assertThrows(IllegalOperationError, function():void { fail = new MockEnum() } ); + assertNull(fail); + } + + public function test_badEnum1():void + { + assertThrows(IllegalOperationError, function():void { BadEnum.Value1 } ); + + //should have thrown in the constructor and should not exist + assertThrows(TypeError, function():void { BadEnum.Value1 } ); + } + + public function test_badEnum2():void + { + assertThrows(SyntaxError, function():void { BadEnum2.Value1 } ); + } + + public function test_badEnum3():void + { + assertFalse(BadEnum3.Value1 == BadEnum3.Value2); + BadEnum3.Value1 = BadEnum3.Value2; + assertTrue(BadEnum3.Value1 == BadEnum3.Value2); + + assertThrows(SyntaxError, function():void { BadEnum3.Value1.name } ); + } + + //-------------------------------------- + // UTILITY METHODS + //-------------------------------------- +} + } - -} \ No newline at end of file diff --git a/test/src/test/nexus/math/AbstractIPRNGTest.as b/test/src/test/nexus/math/AbstractIPRNGTest.as index 3165327..ba73957 100644 --- a/test/src/test/nexus/math/AbstractIPRNGTest.as +++ b/test/src/test/nexus/math/AbstractIPRNGTest.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -17,241 +17,241 @@ import nexus.math.*; */ public class AbstractIPRNGTest extends TestCase { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - public static const DISTRIBUTION_ITERATIONS:int = 10000; - public static const STRESS_ITERATIONS:int = 1000000; - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - protected var m_generator:IPRNG; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function AbstractIPRNGTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - - } - - override protected function tearDown():void - { - - } - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_monteCarlo():void - { - for(var x:int = 0; x < 10; ++x) - { - runMonteCarloTest(); - } - } - - public function off_test_performance():void - { - var start:int = getTimer(); - for(var x:int = 0; x < STRESS_ITERATIONS; ++x) - { - m_generator.next(); - } - var end:int = getTimer() - start; - //trace("test_performance", m_generator, STRESS_ITERATIONS + " iterations: " + end + "ms"); - assertTrue(end < 800); - } - - public function test_randomInteger():void - { - var rand : Random = new Random(m_generator); - var highHit : Boolean = false; - var midHit : Boolean = false; - var lowHit : Boolean = false; - const low : int = 1; - const high : int = 100; - const mid :int = low + high / 2; - for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) - { - var num : int = rand.integer(low, high); - assertTrue(num + " is not < " + high, num < high); - assertTrue(num + " is not >= " + low, num >= low); - if(!lowHit && num == low) - { - lowHit = true; - } - if(!midHit && num == mid) - { - midHit = true; - } - if(!highHit && num == high - 1) - { - highHit = true; - } - } - - assertTrue(low + " never generated", lowHit); - assertTrue(mid + " never generated", midHit); - assertTrue((high - 1) + " never generated", highHit); - } - - public function test_randomUnsignedInteger():void - { - var rand : Random = new Random(m_generator); - var highHit : Boolean = false; - var midHit : Boolean = false; - var lowHit : Boolean = false; - const low : int = 1; - const high : int = 100; - const mid :int = low + high / 2; - for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) - { - var num : uint = rand.unsignedInteger(low, high); - assertTrue(num + " is not < " + high, num < high); - assertTrue(num + " is not >= " + low, num >= low); - if(!lowHit && num == low) - { - lowHit = true; - } - if(!midHit && num == mid) - { - midHit = true; - } - if(!highHit && num == high - 1) - { - highHit = true; - } - } - - assertTrue(low + " never generated", lowHit); - assertTrue(mid + " never generated", midHit); - assertTrue((high - 1) + " never generated", highHit); - } - - public function test_randomFloat():void - { - var rand : Random = new Random(m_generator); - var highHit : Boolean = false; - var midHit : Boolean = false; - var lowHit : Boolean = false; - const low : Number = 1.0; - const high : Number = 100.0; - const mid :Number = low + high / 2; - for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) - { - var num : int = rand.float(low, high); - assertTrue(num + " is not < " + high, num < high); - assertTrue(num + " is not >= " + low, num >= low); - if(!lowHit && num == low) - { - lowHit = true; - } - if(!midHit && num == mid) - { - midHit = true; - } - if(!highHit && num == high - 1) - { - highHit = true; - } - } - - assertTrue(low.toFixed(1) + " never generated", lowHit); - assertTrue(mid.toFixed(1) + " never generated", midHit); - assertTrue((high - 1).toFixed(1) + " never generated", highHit); - } - - public function test_boolean():void - { - var rand : Random = new Random(m_generator); - var trueCount : int = 0; - var falseCount : int = 0; - for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) - { - if(rand.boolean()) - { - trueCount++; - } - else - { - falseCount++; - } - } - var diff : int = Math.abs(trueCount - falseCount); - //trace("test_boolean", m_generator, diff, trueCount, falseCount, diff / DISTRIBUTION_ITERATIONS * 100); - //trace("test_boolean", m_generator, "variance", diff / DISTRIBUTION_ITERATIONS); - assertTrue(diff / DISTRIBUTION_ITERATIONS < .02); - } - - public function test_round():void - { - var rand : Random = new Random(m_generator); - var upCount : int = 0; - var downCount : int = 0; - const num : Number = 4.5; - for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) - { - var result : int = rand.weightedRound(num); - assertTrue("weightedRound(" + num + ") returned " + result, result == 4 || result == 5); - if(result == 4) - { - downCount++; - } - else - { - upCount++; - } - } - var diff : int = Math.abs(upCount - downCount); - //trace("test_round", m_generator, diff, upCount, downCount, diff / DISTRIBUTION_ITERATIONS * 100); - //trace("test_round", m_generator, "variance", diff / DISTRIBUTION_ITERATIONS); - assertTrue("Variance > .02 => " + (diff / DISTRIBUTION_ITERATIONS), diff / DISTRIBUTION_ITERATIONS < .02); - } - - //-------------------------------------- - // HELPER METHODS - //-------------------------------------- - - protected function runMonteCarloTest():void - { - var inCircle:int = 0; - for(var i:int = 0; i < DISTRIBUTION_ITERATIONS; ++i) - { - var xr:Number = m_generator.next() / m_generator.period; - var yr:Number = m_generator.next() / m_generator.period; - // find the calculated distance to the center - if((xr * xr) + (yr * yr) <= 1.0) - { - inCircle++; - } - } - - // calculate the Pi approximations - var calculatedPi:Number = inCircle / DISTRIBUTION_ITERATIONS * 4; - - // calculate the % error - var error:Number = Math.abs((calculatedPi - Math.PI) / Math.PI * 100); - - var resultText:String = "Random Pi Approximation: " + calculatedPi + " Error: " + (Math.floor(error * 100) / 100) + "%"; - //trace(m_generator + " " + resultText); - - assertTrue(resultText, error < 1.5); - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + public static const DISTRIBUTION_ITERATIONS:int = 10000; + public static const STRESS_ITERATIONS:int = 1000000; + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + protected var m_generator:IPRNG; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function AbstractIPRNGTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + + } + + override protected function tearDown():void + { + + } + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_monteCarlo():void + { + for(var x:int = 0; x < 10; ++x) + { + runMonteCarloTest(); + } + } + + public function off_test_performance():void + { + var start:int = getTimer(); + for(var x:int = 0; x < STRESS_ITERATIONS; ++x) + { + m_generator.next(); + } + var end:int = getTimer() - start; + //trace("test_performance", m_generator, STRESS_ITERATIONS + " iterations: " + end + "ms"); + assertTrue(end < 800); + } + + public function test_randomInteger():void + { + var rand : Random = new Random(m_generator); + var highHit : Boolean = false; + var midHit : Boolean = false; + var lowHit : Boolean = false; + const low : int = 1; + const high : int = 100; + const mid :int = low + high / 2; + for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) + { + var num : int = rand.integer(low, high); + assertTrue(num + " is not < " + high, num < high); + assertTrue(num + " is not >= " + low, num >= low); + if(!lowHit && num == low) + { + lowHit = true; + } + if(!midHit && num == mid) + { + midHit = true; + } + if(!highHit && num == high - 1) + { + highHit = true; + } + } + + assertTrue(low + " never generated", lowHit); + assertTrue(mid + " never generated", midHit); + assertTrue((high - 1) + " never generated", highHit); + } + + public function test_randomUnsignedInteger():void + { + var rand : Random = new Random(m_generator); + var highHit : Boolean = false; + var midHit : Boolean = false; + var lowHit : Boolean = false; + const low : int = 1; + const high : int = 100; + const mid :int = low + high / 2; + for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) + { + var num : uint = rand.unsignedInteger(low, high); + assertTrue(num + " is not < " + high, num < high); + assertTrue(num + " is not >= " + low, num >= low); + if(!lowHit && num == low) + { + lowHit = true; + } + if(!midHit && num == mid) + { + midHit = true; + } + if(!highHit && num == high - 1) + { + highHit = true; + } + } + + assertTrue(low + " never generated", lowHit); + assertTrue(mid + " never generated", midHit); + assertTrue((high - 1) + " never generated", highHit); + } + + public function test_randomFloat():void + { + var rand : Random = new Random(m_generator); + var highHit : Boolean = false; + var midHit : Boolean = false; + var lowHit : Boolean = false; + const low : Number = 1.0; + const high : Number = 100.0; + const mid :Number = low + high / 2; + for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) + { + var num : int = rand.float(low, high); + assertTrue(num + " is not < " + high, num < high); + assertTrue(num + " is not >= " + low, num >= low); + if(!lowHit && num == low) + { + lowHit = true; + } + if(!midHit && num == mid) + { + midHit = true; + } + if(!highHit && num == high - 1) + { + highHit = true; + } + } + + assertTrue(low.toFixed(1) + " never generated", lowHit); + assertTrue(mid.toFixed(1) + " never generated", midHit); + assertTrue((high - 1).toFixed(1) + " never generated", highHit); + } + + public function test_boolean():void + { + var rand : Random = new Random(m_generator); + var trueCount : int = 0; + var falseCount : int = 0; + for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) + { + if(rand.boolean()) + { + trueCount++; + } + else + { + falseCount++; + } + } + var diff : int = Math.abs(trueCount - falseCount); + //trace("test_boolean", m_generator, diff, trueCount, falseCount, diff / DISTRIBUTION_ITERATIONS * 100); + //trace("test_boolean", m_generator, "variance", diff / DISTRIBUTION_ITERATIONS); + assertTrue(diff / DISTRIBUTION_ITERATIONS < .02); + } + + public function test_round():void + { + var rand : Random = new Random(m_generator); + var upCount : int = 0; + var downCount : int = 0; + const num : Number = 4.5; + for(var x : int = 0; x < DISTRIBUTION_ITERATIONS; ++x) + { + var result : int = rand.weightedRound(num); + assertTrue("weightedRound(" + num + ") returned " + result, result == 4 || result == 5); + if(result == 4) + { + downCount++; + } + else + { + upCount++; + } + } + var diff : int = Math.abs(upCount - downCount); + //trace("test_round", m_generator, diff, upCount, downCount, diff / DISTRIBUTION_ITERATIONS * 100); + //trace("test_round", m_generator, "variance", diff / DISTRIBUTION_ITERATIONS); + assertTrue("Variance > .02 => " + (diff / DISTRIBUTION_ITERATIONS), diff / DISTRIBUTION_ITERATIONS < .02); + } + + //-------------------------------------- + // HELPER METHODS + //-------------------------------------- + + protected function runMonteCarloTest():void + { + var inCircle:int = 0; + for(var i:int = 0; i < DISTRIBUTION_ITERATIONS; ++i) + { + var xr:Number = m_generator.next() / m_generator.period; + var yr:Number = m_generator.next() / m_generator.period; + // find the calculated distance to the center + if((xr * xr) + (yr * yr) <= 1.0) + { + inCircle++; + } + } + + // calculate the Pi approximations + var calculatedPi:Number = inCircle / DISTRIBUTION_ITERATIONS * 4; + + // calculate the % error + var error:Number = Math.abs((calculatedPi - Math.PI) / Math.PI * 100); + + var resultText:String = "Random Pi Approximation: " + calculatedPi + " Error: " + (Math.floor(error * 100) / 100) + "%"; + //trace(m_generator + " " + resultText); + + assertTrue(resultText, error < 1.5); + } } -} \ No newline at end of file +} diff --git a/test/src/test/nexus/math/AbstractISeededPRNGTest.as b/test/src/test/nexus/math/AbstractISeededPRNGTest.as index 57f147b..ea24d6e 100644 --- a/test/src/test/nexus/math/AbstractISeededPRNGTest.as +++ b/test/src/test/nexus/math/AbstractISeededPRNGTest.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -17,87 +17,87 @@ import nexus.math.*; */ public class AbstractISeededPRNGTest extends AbstractIPRNGTest { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - private static const DISTRIBUTION_ITERATIONS : int = 1000; - private static const STRESS_ITERATIONS : int = 1000000; - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - protected var m_algorithm : Class; - private var m_seededGenerator1 : ISeededPRNG; - private var m_seededGenerator2 : ISeededPRNG; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function AbstractISeededPRNGTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - m_seededGenerator1 = new m_algorithm(); - m_seededGenerator1.seed = (new Date()).getTime(); - m_seededGenerator2 = new m_algorithm(); - m_seededGenerator2.seed = (new Date()).getTime() - getTimer(); - m_generator = m_seededGenerator1; - } - - override protected function tearDown():void - { - - } - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_seeds():void - { - assertEqualsArrays(get100(m_seededGenerator1, 0), get100(m_seededGenerator2, 0)); - assertEqualsArrays(get100(m_seededGenerator1, 1), get100(m_seededGenerator2, 1)); - assertEqualsArrays(get100(m_seededGenerator1, 2), get100(m_seededGenerator2, 2)); - assertEqualsArrays(get100(m_seededGenerator1, 1000), get100(m_seededGenerator2, 1000)); - //prime - assertEqualsArrays(get100(m_seededGenerator1, 214021), get100(m_seededGenerator2, 214021)); - - assertEqualsArrays(get100(m_seededGenerator1, int.MAX_VALUE), get100(m_seededGenerator2, int.MAX_VALUE)); - assertEqualsArrays(get100(m_seededGenerator1, int.MIN_VALUE), get100(m_seededGenerator2, int.MIN_VALUE)); - assertEqualsArrays(get100(m_seededGenerator1, uint.MAX_VALUE), get100(m_seededGenerator2, uint.MAX_VALUE)); - assertEqualsArrays(get100(m_seededGenerator1, uint.MIN_VALUE), get100(m_seededGenerator2, uint.MIN_VALUE)); - } - - //-------------------------------------- - // HELPER METHODS - //-------------------------------------- - - private function get100(prng : ISeededPRNG, seed:int):Array - { - prng.seed = seed; - var result : Array = []; - for(var x : int = 0; x < 100; ++x) - { - result[x] = prng.next(); - } - return result; - } - - override protected function runMonteCarloTest():void - { - m_seededGenerator1.seed = (new Date()).getTime(); - super.runMonteCarloTest(); - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + private static const DISTRIBUTION_ITERATIONS : int = 1000; + private static const STRESS_ITERATIONS : int = 1000000; + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + protected var m_algorithm : Class; + private var m_seededGenerator1 : ISeededPRNG; + private var m_seededGenerator2 : ISeededPRNG; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function AbstractISeededPRNGTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + m_seededGenerator1 = new m_algorithm(); + m_seededGenerator1.seed = (new Date()).getTime(); + m_seededGenerator2 = new m_algorithm(); + m_seededGenerator2.seed = (new Date()).getTime() - getTimer(); + m_generator = m_seededGenerator1; + } + + override protected function tearDown():void + { + + } + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_seeds():void + { + assertEqualsArrays(get100(m_seededGenerator1, 0), get100(m_seededGenerator2, 0)); + assertEqualsArrays(get100(m_seededGenerator1, 1), get100(m_seededGenerator2, 1)); + assertEqualsArrays(get100(m_seededGenerator1, 2), get100(m_seededGenerator2, 2)); + assertEqualsArrays(get100(m_seededGenerator1, 1000), get100(m_seededGenerator2, 1000)); + //prime + assertEqualsArrays(get100(m_seededGenerator1, 214021), get100(m_seededGenerator2, 214021)); + + assertEqualsArrays(get100(m_seededGenerator1, int.MAX_VALUE), get100(m_seededGenerator2, int.MAX_VALUE)); + assertEqualsArrays(get100(m_seededGenerator1, int.MIN_VALUE), get100(m_seededGenerator2, int.MIN_VALUE)); + assertEqualsArrays(get100(m_seededGenerator1, uint.MAX_VALUE), get100(m_seededGenerator2, uint.MAX_VALUE)); + assertEqualsArrays(get100(m_seededGenerator1, uint.MIN_VALUE), get100(m_seededGenerator2, uint.MIN_VALUE)); + } + + //-------------------------------------- + // HELPER METHODS + //-------------------------------------- + + private function get100(prng : ISeededPRNG, seed:int):Array + { + prng.seed = seed; + var result : Array = []; + for(var x : int = 0; x < 100; ++x) + { + result[x] = prng.next(); + } + return result; + } + + override protected function runMonteCarloTest():void + { + m_seededGenerator1.seed = (new Date()).getTime(); + super.runMonteCarloTest(); + } +} + } - -} \ No newline at end of file diff --git a/test/src/test/nexus/math/LehmerGeneratorTest.as b/test/src/test/nexus/math/LehmerGeneratorTest.as index c9b7491..890ebbb 100644 --- a/test/src/test/nexus/math/LehmerGeneratorTest.as +++ b/test/src/test/nexus/math/LehmerGeneratorTest.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -14,43 +14,43 @@ import nexus.math.LehmerGenerator; */ public class LehmerGeneratorTest extends AbstractISeededPRNGTest { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function LehmerGeneratorTest(testMethod:String = null) - { - super(testMethod); - - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - m_algorithm = LehmerGenerator; - - super.setUp(); - } - - override protected function tearDown():void - { - super.tearDown(); - } - - //-------------------------------------- - // TESTS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function LehmerGeneratorTest(testMethod:String = null) + { + super(testMethod); + + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + m_algorithm = LehmerGenerator; + + super.setUp(); + } + + override protected function tearDown():void + { + super.tearDown(); + } + + //-------------------------------------- + // TESTS + //-------------------------------------- +} + } - -} \ No newline at end of file diff --git a/test/src/test/nexus/math/NativeRandomGeneratorTest.as b/test/src/test/nexus/math/NativeRandomGeneratorTest.as index 4c10711..e3c5827 100644 --- a/test/src/test/nexus/math/NativeRandomGeneratorTest.as +++ b/test/src/test/nexus/math/NativeRandomGeneratorTest.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -11,30 +11,30 @@ import nexus.math.NativeRandomGenerator; public class NativeRandomGeneratorTest extends AbstractIPRNGTest { - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function NativeRandomGeneratorTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - m_generator = new NativeRandomGenerator(); - - super.setUp(); - } - - override protected function tearDown():void - { - super.tearDown(); - } + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function NativeRandomGeneratorTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + m_generator = new NativeRandomGenerator(); + + super.setUp(); + } + + override protected function tearDown():void + { + super.tearDown(); + } +} + } - -} \ No newline at end of file diff --git a/test/src/test/nexus/math/TinyMTGeneratorTest.as b/test/src/test/nexus/math/TinyMTGeneratorTest.as index a7a9187..7d17ad5 100644 --- a/test/src/test/nexus/math/TinyMTGeneratorTest.as +++ b/test/src/test/nexus/math/TinyMTGeneratorTest.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -14,43 +14,43 @@ import nexus.math.TinyMersenneTwisterGenerator; */ public class TinyMTGeneratorTest extends AbstractISeededPRNGTest { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function TinyMTGeneratorTest(testMethod:String = null) - { - super(testMethod); - - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - m_algorithm = TinyMersenneTwisterGenerator; - - super.setUp(); - } - - override protected function tearDown():void - { - super.tearDown(); - } - - //-------------------------------------- - // TESTS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function TinyMTGeneratorTest(testMethod:String = null) + { + super(testMethod); + + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + m_algorithm = TinyMersenneTwisterGenerator; + + super.setUp(); + } + + override protected function tearDown():void + { + super.tearDown(); + } + + //-------------------------------------- + // TESTS + //-------------------------------------- +} + } - -} \ No newline at end of file diff --git a/test/src/test/nexus/security/crypto/HMACTest.as b/test/src/test/nexus/security/crypto/HMACTest.as index bb7aef1..042b344 100644 --- a/test/src/test/nexus/security/crypto/HMACTest.as +++ b/test/src/test/nexus/security/crypto/HMACTest.as @@ -13,219 +13,219 @@ import nexus.utils.ByteUtils; public class HMACTest extends TestCase { - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var digests_SHA1 : Array; - private var digests_SHA256 : Array; - private var keys : Array; - private var messages : Array; - - private var emptyBytes : ByteArray; - private var randomBytes : ByteArray; - - private var hmac_sha1:HMAC; - private var hmac_sha256:HMAC; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function HMACTest(testMethod:String = null) - { - super(testMethod); - - // - // these should be state-less so instantiate here instead of in setUp() to confirm - // - - emptyBytes = new ByteArray(); - randomBytes = ByteUtils.createByteArrayFromString("Lorem Ipsum" + (new Date()).getTime()); - - // http://tools.ietf.org/html/rfc2202 - // http://tools.ietf.org/html/rfc4231 - - digests_SHA1 = [ - "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d", - "b617318655057264e28bc0b6fb378c8ef146be00", - "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", - "125d7342b9ac11cd91a39af48aa17b4f63f175d3", - "4c9007f4026250c6bc8414f9bf50c86c2d7235da", - "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", - "aa4ae5e15272d00e95705637ce8a3b55ed402112", - null, - "e8e99d0f45237d786d6bbaa7965c7808bbff1a91", - null - ]; - digests_SHA256 = [ - "b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", - "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", - "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", - "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", - "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", - "a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5", - null, - "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", - null, - "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2" - ]; - keys = [ - ByteUtils.createByteArrayFromString(""), - // 20 bytes - ByteUtils.hexToBytes("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), - // "Jefe" - ByteUtils.hexToBytes("4a656665"), - // 20 bytes - ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), - // 25 bytes - ByteUtils.hexToBytes("0102030405060708090a0b0c0d0e0f10111213141516171819"), - // 20 bytes - ByteUtils.hexToBytes("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"), - // 80 bytes - ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), - // 131 bytes - ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), - // 80 bytes - ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), - // 131 bytes - ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), - ]; - messages = [ - ByteUtils.createByteArrayFromString(""), - //"Hi There" - ByteUtils.hexToBytes("4869205468657265"), - //"what do ya want for nothing?" - ByteUtils.hexToBytes("7768617420646f2079612077616e7420666f72206e6f7468696e673f"), - // 50 bytes - ByteUtils.hexToBytes("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), - //50 bytes - ByteUtils.hexToBytes("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"), - // "Test With Truncation" - ByteUtils.hexToBytes("546573742057697468205472756e636174696f6e"), - // "Test Using Larger Than Block-Size Key - Hash Key First" - ByteUtils.hexToBytes("54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374"), - // "Test Using Larger Than Block-Size Key - Hash Key First" - ByteUtils.hexToBytes("54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374"), - // "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" - ByteUtils.createByteArrayFromString("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), - // "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." - ByteUtils.hexToBytes("5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e") - ]; - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - hmac_sha1 = new HMAC(new SHA1HashFunction()); - hmac_sha256 = new HMAC(new SHA256HashFunction()); - } - - override protected function tearDown():void - { - hmac_sha1 = null; - hmac_sha256 = null; - } - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_testHarness():void - { - assertEquals("m_digestsSHA1", 10, digests_SHA1.length); - assertEquals("m_digestsSHA256", 10, digests_SHA256.length); - assertEquals("m_keys", 10, keys.length); - assertEquals("m_messages", 10, messages.length); - } - - public function test_sha1():void - { - runTestsOnHMAC(hmac_sha1, digests_SHA1); - } - - public function test_sha1Static():void - { - runTestsOnFunction(HMAC.sha1, digests_SHA1); - } - - public function test_sha256():void - { - runTestsOnHMAC(hmac_sha256, digests_SHA256); - } - - public function test_sha256Static():void - { - runTestsOnFunction(HMAC.sha256, digests_SHA256); - } - - public function test_nullKey():void - { - assertThrows(ArgumentError, function():void { hmac_sha1.generate(null, null) } ); - assertThrows(ArgumentError, function():void { hmac_sha1.generate(emptyBytes, null) } ); - assertThrows(ArgumentError, function():void { hmac_sha1.generate(randomBytes, null) } ); - - assertThrows(ArgumentError, function():void { hmac_sha256.generate(null, null) } ); - assertThrows(ArgumentError, function():void { hmac_sha256.generate(emptyBytes, null) } ); - assertThrows(ArgumentError, function():void { hmac_sha256.generate(randomBytes, null) } ); - } - - public function test_emptyMessage():void - { - assertSame(ByteUtils.bytesToHex(hmac_sha1.generate(null, emptyBytes)), - ByteUtils.bytesToHex(hmac_sha1.generate(emptyBytes, emptyBytes))); - - assertSame(ByteUtils.bytesToHex(hmac_sha256.generate(null, emptyBytes)), - ByteUtils.bytesToHex(hmac_sha256.generate(emptyBytes, emptyBytes))); - } - - /* - public function test_performance():void - { - var hmac_sha1 : HMAC = new HMAC(new SHA1()); - - var start : int = getTimer(); - for(var x : int = 0; x < 5000; ++x) - { - hmac_sha1.hash("key", "The quick brown fox jumps over the lazy dog"); - } - var end : int = getTimer() - start; - trace("test_hashPerf", end + "ms"); - assertTrue(end < 1000); - } - //*/ - - //-------------------------------------- - // PRIVATE METHODS - //-------------------------------------- - - private function runTestsOnHMAC(hmac:HMAC, digests:Array):void - { - runTestsOnFunction(hmac.generate, digests); - - for(var x : int = 0; x < digests.length; ++x) - { - if(digests[x] != null) - { - hmac.secretKey = keys[x]; - assertEquals(digests[x], ByteUtils.bytesToHex(hmac.generate(messages[x]))); - } - } - } - - private function runTestsOnFunction(func:Function, digests:Array):void - { - for(var x : int = 0; x < digests.length; ++x) - { - if(digests[x] != null) - { - assertEquals(digests[x], ByteUtils.bytesToHex(func(messages[x], keys[x]))); - } - } - } + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var digests_SHA1 : Array; + private var digests_SHA256 : Array; + private var keys : Array; + private var messages : Array; + + private var emptyBytes : ByteArray; + private var randomBytes : ByteArray; + + private var hmac_sha1:HMAC; + private var hmac_sha256:HMAC; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function HMACTest(testMethod:String = null) + { + super(testMethod); + + // + // these should be state-less so instantiate here instead of in setUp() to confirm + // + + emptyBytes = new ByteArray(); + randomBytes = ByteUtils.createByteArrayFromString("Lorem Ipsum" + (new Date()).getTime()); + + // http://tools.ietf.org/html/rfc2202 + // http://tools.ietf.org/html/rfc4231 + + digests_SHA1 = [ + "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d", + "b617318655057264e28bc0b6fb378c8ef146be00", + "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + "125d7342b9ac11cd91a39af48aa17b4f63f175d3", + "4c9007f4026250c6bc8414f9bf50c86c2d7235da", + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + "aa4ae5e15272d00e95705637ce8a3b55ed402112", + null, + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91", + null + ]; + digests_SHA256 = [ + "b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", + "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", + "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", + "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", + "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", + "a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5", + null, + "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", + null, + "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2" + ]; + keys = [ + ByteUtils.createByteArrayFromString(""), + // 20 bytes + ByteUtils.hexToBytes("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + // "Jefe" + ByteUtils.hexToBytes("4a656665"), + // 20 bytes + ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + // 25 bytes + ByteUtils.hexToBytes("0102030405060708090a0b0c0d0e0f10111213141516171819"), + // 20 bytes + ByteUtils.hexToBytes("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"), + // 80 bytes + ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + // 131 bytes + ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + // 80 bytes + ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + // 131 bytes + ByteUtils.hexToBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + ]; + messages = [ + ByteUtils.createByteArrayFromString(""), + //"Hi There" + ByteUtils.hexToBytes("4869205468657265"), + //"what do ya want for nothing?" + ByteUtils.hexToBytes("7768617420646f2079612077616e7420666f72206e6f7468696e673f"), + // 50 bytes + ByteUtils.hexToBytes("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"), + //50 bytes + ByteUtils.hexToBytes("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"), + // "Test With Truncation" + ByteUtils.hexToBytes("546573742057697468205472756e636174696f6e"), + // "Test Using Larger Than Block-Size Key - Hash Key First" + ByteUtils.hexToBytes("54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374"), + // "Test Using Larger Than Block-Size Key - Hash Key First" + ByteUtils.hexToBytes("54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374"), + // "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" + ByteUtils.createByteArrayFromString("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), + // "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + ByteUtils.hexToBytes("5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e") + ]; + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + hmac_sha1 = new HMAC(new SHA1HashFunction()); + hmac_sha256 = new HMAC(new SHA256HashFunction()); + } + + override protected function tearDown():void + { + hmac_sha1 = null; + hmac_sha256 = null; + } + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_testHarness():void + { + assertEquals("m_digestsSHA1", 10, digests_SHA1.length); + assertEquals("m_digestsSHA256", 10, digests_SHA256.length); + assertEquals("m_keys", 10, keys.length); + assertEquals("m_messages", 10, messages.length); + } + + public function test_sha1():void + { + runTestsOnHMAC(hmac_sha1, digests_SHA1); + } + + public function test_sha1Static():void + { + runTestsOnFunction(HMAC.sha1, digests_SHA1); + } + + public function test_sha256():void + { + runTestsOnHMAC(hmac_sha256, digests_SHA256); + } + + public function test_sha256Static():void + { + runTestsOnFunction(HMAC.sha256, digests_SHA256); + } + + public function test_nullKey():void + { + assertThrows(ArgumentError, function():void { hmac_sha1.generate(null, null) } ); + assertThrows(ArgumentError, function():void { hmac_sha1.generate(emptyBytes, null) } ); + assertThrows(ArgumentError, function():void { hmac_sha1.generate(randomBytes, null) } ); + + assertThrows(ArgumentError, function():void { hmac_sha256.generate(null, null) } ); + assertThrows(ArgumentError, function():void { hmac_sha256.generate(emptyBytes, null) } ); + assertThrows(ArgumentError, function():void { hmac_sha256.generate(randomBytes, null) } ); + } + + public function test_emptyMessage():void + { + assertSame(ByteUtils.bytesToHex(hmac_sha1.generate(null, emptyBytes)), + ByteUtils.bytesToHex(hmac_sha1.generate(emptyBytes, emptyBytes))); + + assertSame(ByteUtils.bytesToHex(hmac_sha256.generate(null, emptyBytes)), + ByteUtils.bytesToHex(hmac_sha256.generate(emptyBytes, emptyBytes))); + } + + /* + public function test_performance():void + { + var hmac_sha1 : HMAC = new HMAC(new SHA1()); + + var start : int = getTimer(); + for(var x : int = 0; x < 5000; ++x) + { + hmac_sha1.hash("key", "The quick brown fox jumps over the lazy dog"); + } + var end : int = getTimer() - start; + trace("test_hashPerf", end + "ms"); + assertTrue(end < 1000); + } + //*/ + + //-------------------------------------- + // PRIVATE METHODS + //-------------------------------------- + + private function runTestsOnHMAC(hmac:HMAC, digests:Array):void + { + runTestsOnFunction(hmac.generate, digests); + + for(var x : int = 0; x < digests.length; ++x) + { + if(digests[x] != null) + { + hmac.secretKey = keys[x]; + assertEquals(digests[x], ByteUtils.bytesToHex(hmac.generate(messages[x]))); + } + } + } + + private function runTestsOnFunction(func:Function, digests:Array):void + { + for(var x : int = 0; x < digests.length; ++x) + { + if(digests[x] != null) + { + assertEquals(digests[x], ByteUtils.bytesToHex(func(messages[x], keys[x]))); + } + } + } } -} \ No newline at end of file +} diff --git a/test/src/test/nexus/utils/ObjectUtilsTest.as b/test/src/test/nexus/utils/ObjectUtilsTest.as index 4358ed0..1d42932 100644 --- a/test/src/test/nexus/utils/ObjectUtilsTest.as +++ b/test/src/test/nexus/utils/ObjectUtilsTest.as @@ -17,110 +17,110 @@ import nexus.utils.reflection.Reflection; */ public class ObjectUtilsTest extends TestCase { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_goodJson : Object; - private var m_badJson : Object; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function ObjectUtilsTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - m_goodJson = { - "baseString": "string value", - "baseVector": [ - "vector value 0", - "vector value 1" - ], - "subObj1": { - "array": [ - "array value 0", - "array value 1" - ], - "vector": [ - "vector value 0", - "vector value 1" - ], - "date": 1275838483 - }, - "subObj2": { - - } - }; - - m_badJson = { - "baseString": { - obj: "sub value" - }, - "baseVector": { - vec: "is object" - }, - "newValue": 500, - "subObj1": "bad string value", - "subObj2": { - "array": [ - "array value 0", - "array value 1" - ], - "vector": [ - "vector value 0", - "vector value 1" - ], - "date": 1275838483 - } - }; - } - - override protected function tearDown():void - { - - } - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_createTypedObjectFromNativeObject_good():void - { - var base : BaseClass; - - base = ObjectUtils.createTypedObjectFromNativeObject(BaseClass, m_goodJson) as BaseClass; - - assertSame(BaseClass, Reflection.getClass(base)); - - assertEquals("string value", base.baseString); - assertEquals("vector value 0", base.baseVector[0]); - assertEquals("vector value 1", base.baseVector[1]); - } - - public function test_createTypedObjectFromNativeObject_bad():void - { - var base : BaseClass; - - base = ObjectUtils.createTypedObjectFromNativeObject(BaseClass, m_badJson) as BaseClass; - - assertSame(BaseClass, Reflection.getClass(base)); - - assertNull(base.baseString); - assertEquals(0, base.baseVector.length); - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_goodJson : Object; + private var m_badJson : Object; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function ObjectUtilsTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + m_goodJson = { + "baseString": "string value", + "baseVector": [ + "vector value 0", + "vector value 1" + ], + "subObj1": { + "array": [ + "array value 0", + "array value 1" + ], + "vector": [ + "vector value 0", + "vector value 1" + ], + "date": 1275838483 + }, + "subObj2": { + + } + }; + + m_badJson = { + "baseString": { + obj: "sub value" + }, + "baseVector": { + vec: "is object" + }, + "newValue": 500, + "subObj1": "bad string value", + "subObj2": { + "array": [ + "array value 0", + "array value 1" + ], + "vector": [ + "vector value 0", + "vector value 1" + ], + "date": 1275838483 + } + }; + } + + override protected function tearDown():void + { + + } + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_createTypedObjectFromNativeObject_good():void + { + var base : BaseClass; + + base = ObjectUtils.createTypedObjectFromNativeObject(BaseClass, m_goodJson) as BaseClass; + + assertSame(BaseClass, Reflection.getClass(base)); + + assertEquals("string value", base.baseString); + assertEquals("vector value 0", base.baseVector[0]); + assertEquals("vector value 1", base.baseVector[1]); + } + + public function test_createTypedObjectFromNativeObject_bad():void + { + var base : BaseClass; + + base = ObjectUtils.createTypedObjectFromNativeObject(BaseClass, m_badJson) as BaseClass; + + assertSame(BaseClass, Reflection.getClass(base)); + + assertNull(base.baseString); + assertEquals(0, base.baseVector.length); + } } -} \ No newline at end of file +} diff --git a/test/src/test/nexus/utils/reflection/AbstractReflectionTest.as b/test/src/test/nexus/utils/reflection/AbstractReflectionTest.as index e9e95e2..8a1760f 100644 --- a/test/src/test/nexus/utils/reflection/AbstractReflectionTest.as +++ b/test/src/test/nexus/utils/reflection/AbstractReflectionTest.as @@ -18,48 +18,48 @@ import mock.foo.IFoo; */ public class AbstractReflectionTest extends TestCase { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - protected var m_finalTypeInfo:TypeInfo; - protected var m_testTypeInfo:TypeInfo; - protected var m_baseTypeInfo:TypeInfo; - protected var m_test:TestClass; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function AbstractReflectionTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - m_test = new TestClass(); - var finalClass : FinalClass = new FinalClass(false); - m_finalTypeInfo = Reflection.getTypeInfo(finalClass); - m_testTypeInfo = Reflection.getTypeInfo(m_finalTypeInfo.extendedClasses[0]); - m_baseTypeInfo = Reflection.getTypeInfo(BaseClass); - } - - override protected function tearDown():void - { - m_testTypeInfo = null; - m_finalTypeInfo = null; - m_baseTypeInfo = null; - m_test = null; - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + protected var m_finalTypeInfo:TypeInfo; + protected var m_testTypeInfo:TypeInfo; + protected var m_baseTypeInfo:TypeInfo; + protected var m_test:TestClass; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function AbstractReflectionTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + m_test = new TestClass(); + var finalClass : FinalClass = new FinalClass(false); + m_finalTypeInfo = Reflection.getTypeInfo(finalClass); + m_testTypeInfo = Reflection.getTypeInfo(m_finalTypeInfo.extendedClasses[0]); + m_baseTypeInfo = Reflection.getTypeInfo(BaseClass); + } + + override protected function tearDown():void + { + m_testTypeInfo = null; + m_finalTypeInfo = null; + m_baseTypeInfo = null; + m_test = null; + } } -} \ No newline at end of file +} diff --git a/test/src/test/nexus/utils/reflection/ReflectionPerfTest.as b/test/src/test/nexus/utils/reflection/ReflectionPerfTest.as index 0ee6e0b..b78b802 100644 --- a/test/src/test/nexus/utils/reflection/ReflectionPerfTest.as +++ b/test/src/test/nexus/utils/reflection/ReflectionPerfTest.as @@ -1,4 +1,4 @@ -// Copyright 2012 Malachi Griffie +// Copyright M. Griffie // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -16,91 +16,91 @@ import nexus.utils.reflection.Reflection; */ public class ReflectionPerfTest extends TestCase { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function ReflectionPerfTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - - } - - override protected function tearDown():void - { - - } - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_isVector_perfHitString():void - { - var start : int = getTimer(); - var str : Vector. = new Vector.(); - for(var x : int = 0; x < 1000000; ++x) - { - Reflection.isVector(str); - } - var end : int = getTimer() - start; - trace("test_isVector_perfHitString", end + "ms"); - assertTrue("test_isVector_perfHitString < 1000ms = " + end, end < 1000); - } - - public function test_isVector_perfHitNumber():void - { - var start : int = getTimer(); - var num : Vector. = new Vector.(); - for(var x : int = 0; x < 1000000; ++x) - { - Reflection.isVector(num); - } - var end : int = getTimer() - start; - trace("test_isVector_perfHitNumber", end + "ms"); - assertTrue("test_isVector_perfHitNumber < 1000ms = " + end, end < 1000); - } - - public function test_isVector_perfMissClass():void - { - var start : int = getTimer(); - for(var x : int = 0; x < 1000000; ++x) - { - Reflection.isVector(TestClass); - } - var end : int = getTimer() - start; - trace("test_isVector_perfMissClass", end + "ms"); - assertTrue("test_isVector_perfMissClass < 1000ms = " + end, end < 1000); - } - - public function test_isVector_perfMissNonVector():void - { - var start : int = getTimer(); - var str : String = ""; - for(var x : int = 0; x < 1000000; ++x) - { - Reflection.isVector(str); - } - var end : int = getTimer() - start; - trace("test_isVector_perfMissNonVector", end + "ms"); - assertTrue("test_isVector_perfMissNonVector < 1000ms = " + end, end < 1000); - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function ReflectionPerfTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + + } + + override protected function tearDown():void + { + + } + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_isVector_perfHitString():void + { + var start : int = getTimer(); + var str : Vector. = new Vector.(); + for(var x : int = 0; x < 1000000; ++x) + { + Reflection.isVector(str); + } + var end : int = getTimer() - start; + trace("test_isVector_perfHitString", end + "ms"); + assertTrue("test_isVector_perfHitString < 1000ms = " + end, end < 1000); + } + + public function test_isVector_perfHitNumber():void + { + var start : int = getTimer(); + var num : Vector. = new Vector.(); + for(var x : int = 0; x < 1000000; ++x) + { + Reflection.isVector(num); + } + var end : int = getTimer() - start; + trace("test_isVector_perfHitNumber", end + "ms"); + assertTrue("test_isVector_perfHitNumber < 1000ms = " + end, end < 1000); + } + + public function test_isVector_perfMissClass():void + { + var start : int = getTimer(); + for(var x : int = 0; x < 1000000; ++x) + { + Reflection.isVector(TestClass); + } + var end : int = getTimer() - start; + trace("test_isVector_perfMissClass", end + "ms"); + assertTrue("test_isVector_perfMissClass < 1000ms = " + end, end < 1000); + } + + public function test_isVector_perfMissNonVector():void + { + var start : int = getTimer(); + var str : String = ""; + for(var x : int = 0; x < 1000000; ++x) + { + Reflection.isVector(str); + } + var end : int = getTimer() - start; + trace("test_isVector_perfMissNonVector", end + "ms"); + assertTrue("test_isVector_perfMissNonVector < 1000ms = " + end, end < 1000); + } +} + } - -} \ No newline at end of file diff --git a/test/src/test/nexus/utils/reflection/ReflectionTest.as b/test/src/test/nexus/utils/reflection/ReflectionTest.as index 10c59a7..63a742d 100644 --- a/test/src/test/nexus/utils/reflection/ReflectionTest.as +++ b/test/src/test/nexus/utils/reflection/ReflectionTest.as @@ -22,409 +22,409 @@ import nexus.utils.reflection.*; */ public class ReflectionTest extends AbstractReflectionTest { - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function ReflectionTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_getClass():void - { - baseTest_getClass(null); - } - - //TODO: Increase the scope of this test by loading in a new app domain - public function test_getClassWithApplicationDomain():void - { - baseTest_getClass(Reflection.SYSTEM_DOMAIN); - baseTest_getClass(ApplicationDomain.currentDomain); - //FIXME: I feel like this should work - //baseTest_getClass(new ApplicationDomain(ApplicationDomain.currentDomain)); - } - - public function test_getClassByName():void - { - baseTest_getClassByName(null); - } - - //TODO: Increase the scope of this test by loading in a new app domain - public function test_getClassByNameWithApplicationDomain():void - { - baseTest_getClassByName(Reflection.SYSTEM_DOMAIN); - baseTest_getClassByName(ApplicationDomain.currentDomain); - //baseTest_getClassByName(new ApplicationDomain(ApplicationDomain.currentDomain)); - } - - public function test_getSuperClass():void - { - baseTest_getSuperClass(null); - } - - //TODO: Increase the scope of this test by loading in a new app domain - public function test_getSuperClassWithApplicationDomain():void - { - baseTest_getSuperClass(Reflection.SYSTEM_DOMAIN); - baseTest_getSuperClass(ApplicationDomain.currentDomain); - //baseTest_getSuperClass(new ApplicationDomain(ApplicationDomain.currentDomain)); - } - - public function test_getApplicationDomain():void - { - assertSame(Reflection.SYSTEM_DOMAIN, Reflection.getApplicationDomain(m_test)); - - assertTrue(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, Reflection.getApplicationDomain(m_test))); - } - - public function test_getVectorType():void - { - baseTest_getVectorType(null); - } - - public function test_getVectorTypeWithApplicationDomain():void - { - baseTest_getVectorType(Reflection.SYSTEM_DOMAIN); - baseTest_getVectorType(ApplicationDomain.currentDomain); - } - - public function test_getQualifiedClassName():void - { - assertEquals("mock.foo.bar::BaseClass", Reflection.getQualifiedClassName(BaseClass)); - assertEquals("mock.foo.bar::BaseClass", Reflection.getQualifiedClassName(new BaseClass())); - assertEquals("mock.foo.bar::TestClass", Reflection.getQualifiedClassName(m_test)); - assertEquals("mock.foo::IFoo", Reflection.getQualifiedClassName(IFoo)); - - assertEquals("__AS3__.vec::Vector.", Reflection.getQualifiedClassName(Vector.)); - assertEquals("__AS3__.vec::Vector.", Reflection.getQualifiedClassName(new Vector.())); - assertEquals("__AS3__.vec::Vector.", Reflection.getQualifiedClassName(new ["foo", "bar"])); - - assertSame("null", Reflection.getQualifiedClassName(null)); - assertSame("null", Reflection.getQualifiedClassName(undefined)); - - ///@see: http://jacksondunstan.com/articles/1357 - assertEquals("int", Reflection.getQualifiedClassName(5)); - assertEquals("int", Reflection.getQualifiedClassName(5.0)); - assertEquals("Number", Reflection.getQualifiedClassName(5.555)); - } - - public function test_getUnqualifiedClassName():void - { - assertEquals("TestClass", Reflection.getUnqualifiedClassName(m_test)); - assertEquals("TestClass", Reflection.getUnqualifiedClassName(TestClass)); - assertEquals("TestClass", Reflection.getUnqualifiedClassName(new TestClass())); - assertEquals("TestClass", Reflection.getUnqualifiedClassName("foo::TestClass")); - assertEquals("TestClass", Reflection.getUnqualifiedClassName("mock.foo.bar::TestClass")); - //TODO: Support this case? - //assertEquals("TestClass", Reflection.getUnqualifiedClassName("mock.foo.bar.TestClass")); - assertEquals("TestClass", Reflection.getUnqualifiedClassName("[class TestClass]")); - assertEquals("String", Reflection.getUnqualifiedClassName("TestClass")); - - assertEquals("IFoo", Reflection.getUnqualifiedClassName(IFoo)); - - assertEquals("Vector.<*>", Reflection.getUnqualifiedClassName(new Vector.<*>())); - assertEquals("Vector.", Reflection.getUnqualifiedClassName(Vector.)); - assertEquals("Vector.", Reflection.getUnqualifiedClassName("__AS3__.vec::Vector.")); - assertEquals("Vector.", Reflection.getUnqualifiedClassName(new ["foo", "bar"])); - - assertSame("null", Reflection.getUnqualifiedClassName(null)); - assertSame("null", Reflection.getUnqualifiedClassName(undefined)); - - assertEquals("int", Reflection.getUnqualifiedClassName(5)); - assertEquals("int", Reflection.getUnqualifiedClassName(5.0)); - assertEquals("Number", Reflection.getUnqualifiedClassName(5.555)); - } - - public function test_classExtendsClass():void - { - baseTest_classExtendsClass(null); - } - - public function test_classExtendsClassWithApplicationDomain():void - { - baseTest_classExtendsClass(Reflection.SYSTEM_DOMAIN); - baseTest_classExtendsClass(ApplicationDomain.currentDomain); - } - - public function test_applicationDomainsAreEqual():void - { - var childDomain : ApplicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain); - - assertTrue(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, ApplicationDomain.currentDomain)); - - assertTrue(Reflection.areApplicationDomainsEqual(Reflection.SYSTEM_DOMAIN, ApplicationDomain.currentDomain)); - assertTrue(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, Reflection.SYSTEM_DOMAIN)); - - assertTrue(Reflection.areApplicationDomainsEqual(childDomain.parentDomain, Reflection.SYSTEM_DOMAIN)); - assertTrue(Reflection.areApplicationDomainsEqual(childDomain.parentDomain, ApplicationDomain.currentDomain)); - - assertFalse(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, childDomain)); - assertFalse(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, new ApplicationDomain(Reflection.SYSTEM_DOMAIN))); - assertFalse(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, new ApplicationDomain(null))); - } - - public function test_isScalar():void - { - //scalars - - assertTrue(Reflection.isScalar(int)); - assertTrue(Reflection.isScalar(0)); - assertTrue(Reflection.isScalar(1)); - assertTrue(Reflection.isScalar(uint)); - assertTrue(Reflection.isScalar(Number)); - assertTrue(Reflection.isScalar(5.55555)); - - assertTrue(Reflection.isScalar(String)); - assertTrue(Reflection.isScalar("foo")); - assertTrue(Reflection.isScalar("")); - - assertTrue(Reflection.isScalar(Boolean)); - assertTrue(Reflection.isScalar(false)); - assertTrue(Reflection.isScalar(true)); - - //not scalars - - assertFalse(Reflection.isScalar(Object)); - assertFalse(Reflection.isScalar({})); - - assertFalse(Reflection.isScalar(Array)); - assertFalse(Reflection.isScalar([])); - - assertFalse(Reflection.isScalar(null)); - - assertFalse(Reflection.isScalar(TestClass)); - assertFalse(Reflection.isScalar(m_test)); - } - - public function test_isArrayType():void - { - assertTrue(Reflection.isArrayType(new Vector.())); - assertTrue(Reflection.isArrayType(new [new TestClass(), m_test])); - assertTrue(Reflection.isArrayType(Vector.)); - - assertTrue(Reflection.isArrayType(Array)); - assertTrue(Reflection.isArrayType([])); - - assertFalse(Reflection.isArrayType(Object)); - assertFalse(Reflection.isArrayType({})); - } - - public function test_isVector():void - { - assertTrue(Reflection.isVector(new Vector.())); - assertTrue(Reflection.isVector(new Vector.())); - assertTrue(Reflection.isVector(new Vector.())); - assertTrue(Reflection.isVector(new Vector.())); - assertTrue(Reflection.isVector(new Vector.())); - assertTrue(Reflection.isVector(new Vector.<*>())); - assertTrue(Reflection.isVector(new [new TestClass(), m_test])); - assertTrue(Reflection.isVector(Vector.)); - assertTrue(Reflection.isVector(Vector.)); - assertTrue(Reflection.isVector(Vector.)); - assertTrue(Reflection.isVector(Vector.)); - assertTrue(Reflection.isVector(Vector.)); - assertTrue(Reflection.isVector(Vector.<*>)); - assertTrue(Reflection.isVector(Vector)); - - assertFalse(Reflection.isVector(null)); - assertFalse(Reflection.isVector(undefined)); - assertFalse(Reflection.isVector(false)); - assertFalse(Reflection.isVector(0)); - - assertFalse(Reflection.isVector("Vector.<*>")); - assertFalse(Reflection.isVector("new Vector.<*>")); - assertFalse(Reflection.isVector("new Vector.<*>()")); - assertFalse(Reflection.isVector("Vector")); - - assertFalse(Reflection.isVector(Array)); - assertFalse(Reflection.isVector([])); - - assertFalse(Reflection.isVector(Object)); - assertFalse(Reflection.isVector({})); - } - - public function test_isAssociativeArray():void - { - assertTrue(Reflection.isAssociativeArray(Object)); - assertTrue(Reflection.isAssociativeArray({})); - assertTrue(Reflection.isAssociativeArray(new Dictionary())); - assertTrue(Reflection.isAssociativeArray(Dictionary)); - - assertFalse(Reflection.isAssociativeArray(new Vector.())); - assertFalse(Reflection.isAssociativeArray(new [new TestClass(), m_test])); - assertFalse(Reflection.isAssociativeArray(Vector.)); - - assertFalse(Reflection.isAssociativeArray("Object")); - assertFalse(Reflection.isAssociativeArray("{}")); - assertFalse(Reflection.isAssociativeArray("new Dictionary()")); - assertFalse(Reflection.isAssociativeArray("Dictionary")); - - assertFalse(Reflection.isAssociativeArray(null)); - assertFalse(Reflection.isAssociativeArray(undefined)); - assertFalse(Reflection.isAssociativeArray(false)); - assertFalse(Reflection.isAssociativeArray(0)); - - assertFalse(Reflection.isAssociativeArray(Array)); - assertFalse(Reflection.isAssociativeArray([])); - - assertFalse(Reflection.isAssociativeArray(m_test)); - assertFalse(Reflection.isAssociativeArray(BaseClass)); - } - - public function testComprehensive():void - { - assertSame(Vector., - Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(new Vector.())))()) ); - assertSame(Vector.<*>, - Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(new Vector.<*>())))()) ); - assertSame(Vector., - Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(new Vector.())))()) ); - - assertSame(TestClass, - Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(TestClass)))()) ); - assertSame(Date, - Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(new Date())))()) ); - - assertSame(Object, - Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName({})))()) ); - - assertSame(int, - Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(5)))()) ); - } - - //-------------------------------------- - // PRIVATE INSTANCE METHODS - //-------------------------------------- - - /** - * Test Reflection.getClass with the provided ApplicationDomain - * @param appDomain - */ - private function baseTest_getClass(appDomain:ApplicationDomain):void - { - assertSame(int, Reflection.getClass(0, appDomain)); - assertSame(Array, Reflection.getClass([], appDomain)); - assertSame(Date, Reflection.getClass(new Date(), appDomain)); - assertSame(Object, Reflection.getClass({}, appDomain)); - - assertNull(Reflection.getClass(null, appDomain)); - - assertSame(TestClass, Reflection.getClass(m_test, appDomain)); - assertSame(BaseClass, Reflection.getClass(BaseClass, appDomain)); - assertSame(String, Reflection.getClass("TypeInfo", appDomain)); - assertSame(String, Reflection.getClass("dna.utils.reflection::TypeInfo", appDomain)); - } - - private function baseTest_getClassByName(appDomain:ApplicationDomain):void - { - assertSame(uint, Reflection.getClassByName("uint", appDomain)); - assertSame(int, Reflection.getClassByName("int", appDomain)); - assertSame(Number, Reflection.getClassByName("Number", appDomain)); - assertSame(Array, Reflection.getClassByName("Array", appDomain)); - assertSame(Date, Reflection.getClassByName("Date", appDomain)); - assertSame(Class, Reflection.getClassByName("Class", appDomain)); - assertSame(Dictionary, Reflection.getClassByName("flash.utils.Dictionary", appDomain)); - assertSame(Dictionary, Reflection.getClassByName("flash.utils::Dictionary", appDomain)); - assertSame(BaseClass, Reflection.getClassByName("mock.foo.bar.BaseClass", appDomain)); - assertSame(BaseClass, Reflection.getClassByName("mock.foo.bar::BaseClass", appDomain)); - assertSame(TestClass, Reflection.getClassByName("mock.foo.bar::TestClass", appDomain)); - assertSame(IFoo, Reflection.getClassByName("mock.foo::IFoo", appDomain)); - - assertSame(Object, Reflection.getClassByName("*", appDomain)); - assertSame(Object, Reflection.getClassByName("Object", appDomain)); - - assertNull(Reflection.getClassByName("null", appDomain)); - assertNull(Reflection.getClassByName("void", appDomain)); - assertNull(Reflection.getClassByName("undefined", appDomain)); - - assertSame(Vector.<*>, Reflection.getClassByName("Vector.<*>", appDomain)); - assertSame(Vector.<*>, Reflection.getClassByName("__AS3__.vec::Vector.<*>", appDomain)); - assertSame(Vector., Reflection.getClassByName("Vector.", appDomain)); - assertSame(Vector., Reflection.getClassByName("__AS3__.vec::Vector.", appDomain)); - assertSame(Vector.>,Reflection.getClassByName("Vector.<__AS3__.vec::Vector.>", appDomain)); - - assertThrows(ClassNotFoundError, function():void { Reflection.getClassByName("foo", appDomain) } ); - assertThrows(ClassNotFoundError, function():void { Reflection.getClassByName("TestClass", appDomain) } ); - //TODO: Find a fix for this? - assertThrows(ClassNotFoundError, function():void { Reflection.getClassByName("Vector.<__AS3__.vec::Vector.<*>>", appDomain) }); - } - - private function baseTest_getSuperClass(appDomain:ApplicationDomain):void - { - assertSame(BaseClass, Reflection.getSuperClass(m_test, appDomain)); - assertSame(BaseClass, Reflection.getSuperClass(TestClass, appDomain)); - assertSame(TestClass, Reflection.getSuperClass(FinalClass, appDomain)); - assertSame(Object, Reflection.getSuperClass(BaseClass, appDomain)); - assertSame(Object, Reflection.getSuperClass(Date, appDomain)); - assertSame(Object, Reflection.getSuperClass(Array, appDomain)); - - assertSame(Vector.<*>, Reflection.getSuperClass(Vector., appDomain)); - assertSame(Vector.<*>, Reflection.getSuperClass(Vector.>, appDomain)); - assertSame(Vector.<*>, Reflection.getSuperClass(Vector., appDomain)); - assertSame(Object, Reflection.getSuperClass(Vector.<*>, appDomain)); - - //strings - assertSame(Object, Reflection.getSuperClass("TestClass", appDomain)); - assertSame(Object, Reflection.getSuperClass("mock.foo.bar::TestClass", appDomain)); - - //no parent class of Object - assertNull(Reflection.getSuperClass(Object, appDomain)); - - //should return null instead of throwing null argument error - assertNull(Reflection.getSuperClass(null, appDomain)); - } - - private function baseTest_getVectorType(appDomain:ApplicationDomain):void - { - assertSame(String, Reflection.getVectorType(new Vector.(), appDomain)); - assertSame(BaseClass, Reflection.getVectorType(new Vector.(), appDomain)); - - assertSame(IFoo, Reflection.getVectorType(new Vector.(), appDomain)); - - assertSame(Object, Reflection.getVectorType(new Vector.(), appDomain)); - assertSame(Object, Reflection.getVectorType(new Vector.<*>(), appDomain)); - - assertNull(Reflection.getVectorType([], appDomain)); - assertNull(Reflection.getVectorType("string", appDomain)); - - assertSame(Vector., Reflection.getVectorType(new Vector.>(), appDomain)); - assertSame(Vector.>, Reflection.getVectorType(new Vector.>>(), appDomain)); - assertSame(Vector., Reflection.getVectorType(new Vector.>(), appDomain)); - - assertNull(Reflection.getVectorType(null, appDomain)); - } - - private function baseTest_classExtendsClass(appDomain:ApplicationDomain):void - { - assertTrue(Reflection.classExtendsClass(FinalClass, TestClass, appDomain)); - assertTrue(Reflection.classExtendsClass(FinalClass, BaseClass, appDomain)); - assertTrue(Reflection.classExtendsClass(BaseClass, Object, appDomain)); - - assertFalse(Reflection.classExtendsClass(TestClass, FinalClass, appDomain)); - assertFalse(Reflection.classExtendsClass(TestClass, TestClass, appDomain)); - assertFalse(Reflection.classExtendsClass(Object, Object, appDomain)); - - assertFalse(Reflection.classExtendsClass(null, Object, appDomain)); - assertFalse(Reflection.classExtendsClass(Object, null, appDomain)); - assertFalse(Reflection.classExtendsClass(null, FinalClass, appDomain)); - assertFalse(Reflection.classExtendsClass(FinalClass,null, appDomain)); - assertFalse(Reflection.classExtendsClass(null, null, appDomain)); - - //assertFalse(Reflection.classExtendsClass(Class(Vector.), Class(Vector.), appDomain)); - } + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function ReflectionTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_getClass():void + { + baseTest_getClass(null); + } + + //TODO: Increase the scope of this test by loading in a new app domain + public function test_getClassWithApplicationDomain():void + { + baseTest_getClass(Reflection.SYSTEM_DOMAIN); + baseTest_getClass(ApplicationDomain.currentDomain); + //FIXME: I feel like this should work + //baseTest_getClass(new ApplicationDomain(ApplicationDomain.currentDomain)); + } + + public function test_getClassByName():void + { + baseTest_getClassByName(null); + } + + //TODO: Increase the scope of this test by loading in a new app domain + public function test_getClassByNameWithApplicationDomain():void + { + baseTest_getClassByName(Reflection.SYSTEM_DOMAIN); + baseTest_getClassByName(ApplicationDomain.currentDomain); + //baseTest_getClassByName(new ApplicationDomain(ApplicationDomain.currentDomain)); + } + + public function test_getSuperClass():void + { + baseTest_getSuperClass(null); + } + + //TODO: Increase the scope of this test by loading in a new app domain + public function test_getSuperClassWithApplicationDomain():void + { + baseTest_getSuperClass(Reflection.SYSTEM_DOMAIN); + baseTest_getSuperClass(ApplicationDomain.currentDomain); + //baseTest_getSuperClass(new ApplicationDomain(ApplicationDomain.currentDomain)); + } + + public function test_getApplicationDomain():void + { + assertSame(Reflection.SYSTEM_DOMAIN, Reflection.getApplicationDomain(m_test)); + + assertTrue(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, Reflection.getApplicationDomain(m_test))); + } + + public function test_getVectorType():void + { + baseTest_getVectorType(null); + } + + public function test_getVectorTypeWithApplicationDomain():void + { + baseTest_getVectorType(Reflection.SYSTEM_DOMAIN); + baseTest_getVectorType(ApplicationDomain.currentDomain); + } + + public function test_getQualifiedClassName():void + { + assertEquals("mock.foo.bar::BaseClass", Reflection.getQualifiedClassName(BaseClass)); + assertEquals("mock.foo.bar::BaseClass", Reflection.getQualifiedClassName(new BaseClass())); + assertEquals("mock.foo.bar::TestClass", Reflection.getQualifiedClassName(m_test)); + assertEquals("mock.foo::IFoo", Reflection.getQualifiedClassName(IFoo)); + + assertEquals("__AS3__.vec::Vector.", Reflection.getQualifiedClassName(Vector.)); + assertEquals("__AS3__.vec::Vector.", Reflection.getQualifiedClassName(new Vector.())); + assertEquals("__AS3__.vec::Vector.", Reflection.getQualifiedClassName(new ["foo", "bar"])); + + assertSame("null", Reflection.getQualifiedClassName(null)); + assertSame("null", Reflection.getQualifiedClassName(undefined)); + + ///@see: http://jacksondunstan.com/articles/1357 + assertEquals("int", Reflection.getQualifiedClassName(5)); + assertEquals("int", Reflection.getQualifiedClassName(5.0)); + assertEquals("Number", Reflection.getQualifiedClassName(5.555)); + } + + public function test_getUnqualifiedClassName():void + { + assertEquals("TestClass", Reflection.getUnqualifiedClassName(m_test)); + assertEquals("TestClass", Reflection.getUnqualifiedClassName(TestClass)); + assertEquals("TestClass", Reflection.getUnqualifiedClassName(new TestClass())); + assertEquals("TestClass", Reflection.getUnqualifiedClassName("foo::TestClass")); + assertEquals("TestClass", Reflection.getUnqualifiedClassName("mock.foo.bar::TestClass")); + //TODO: Support this case? + //assertEquals("TestClass", Reflection.getUnqualifiedClassName("mock.foo.bar.TestClass")); + assertEquals("TestClass", Reflection.getUnqualifiedClassName("[class TestClass]")); + assertEquals("String", Reflection.getUnqualifiedClassName("TestClass")); + + assertEquals("IFoo", Reflection.getUnqualifiedClassName(IFoo)); + + assertEquals("Vector.<*>", Reflection.getUnqualifiedClassName(new Vector.<*>())); + assertEquals("Vector.", Reflection.getUnqualifiedClassName(Vector.)); + assertEquals("Vector.", Reflection.getUnqualifiedClassName("__AS3__.vec::Vector.")); + assertEquals("Vector.", Reflection.getUnqualifiedClassName(new ["foo", "bar"])); + + assertSame("null", Reflection.getUnqualifiedClassName(null)); + assertSame("null", Reflection.getUnqualifiedClassName(undefined)); + + assertEquals("int", Reflection.getUnqualifiedClassName(5)); + assertEquals("int", Reflection.getUnqualifiedClassName(5.0)); + assertEquals("Number", Reflection.getUnqualifiedClassName(5.555)); + } + + public function test_classExtendsClass():void + { + baseTest_classExtendsClass(null); + } + + public function test_classExtendsClassWithApplicationDomain():void + { + baseTest_classExtendsClass(Reflection.SYSTEM_DOMAIN); + baseTest_classExtendsClass(ApplicationDomain.currentDomain); + } + + public function test_applicationDomainsAreEqual():void + { + var childDomain : ApplicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain); + + assertTrue(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, ApplicationDomain.currentDomain)); + + assertTrue(Reflection.areApplicationDomainsEqual(Reflection.SYSTEM_DOMAIN, ApplicationDomain.currentDomain)); + assertTrue(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, Reflection.SYSTEM_DOMAIN)); + + assertTrue(Reflection.areApplicationDomainsEqual(childDomain.parentDomain, Reflection.SYSTEM_DOMAIN)); + assertTrue(Reflection.areApplicationDomainsEqual(childDomain.parentDomain, ApplicationDomain.currentDomain)); + + assertFalse(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, childDomain)); + assertFalse(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, new ApplicationDomain(Reflection.SYSTEM_DOMAIN))); + assertFalse(Reflection.areApplicationDomainsEqual(ApplicationDomain.currentDomain, new ApplicationDomain(null))); + } + + public function test_isScalar():void + { + //scalars + + assertTrue(Reflection.isScalar(int)); + assertTrue(Reflection.isScalar(0)); + assertTrue(Reflection.isScalar(1)); + assertTrue(Reflection.isScalar(uint)); + assertTrue(Reflection.isScalar(Number)); + assertTrue(Reflection.isScalar(5.55555)); + + assertTrue(Reflection.isScalar(String)); + assertTrue(Reflection.isScalar("foo")); + assertTrue(Reflection.isScalar("")); + + assertTrue(Reflection.isScalar(Boolean)); + assertTrue(Reflection.isScalar(false)); + assertTrue(Reflection.isScalar(true)); + + //not scalars + + assertFalse(Reflection.isScalar(Object)); + assertFalse(Reflection.isScalar({})); + + assertFalse(Reflection.isScalar(Array)); + assertFalse(Reflection.isScalar([])); + + assertFalse(Reflection.isScalar(null)); + + assertFalse(Reflection.isScalar(TestClass)); + assertFalse(Reflection.isScalar(m_test)); + } + + public function test_isArrayType():void + { + assertTrue(Reflection.isArrayType(new Vector.())); + assertTrue(Reflection.isArrayType(new [new TestClass(), m_test])); + assertTrue(Reflection.isArrayType(Vector.)); + + assertTrue(Reflection.isArrayType(Array)); + assertTrue(Reflection.isArrayType([])); + + assertFalse(Reflection.isArrayType(Object)); + assertFalse(Reflection.isArrayType({})); + } + + public function test_isVector():void + { + assertTrue(Reflection.isVector(new Vector.())); + assertTrue(Reflection.isVector(new Vector.())); + assertTrue(Reflection.isVector(new Vector.())); + assertTrue(Reflection.isVector(new Vector.())); + assertTrue(Reflection.isVector(new Vector.())); + assertTrue(Reflection.isVector(new Vector.<*>())); + assertTrue(Reflection.isVector(new [new TestClass(), m_test])); + assertTrue(Reflection.isVector(Vector.)); + assertTrue(Reflection.isVector(Vector.)); + assertTrue(Reflection.isVector(Vector.)); + assertTrue(Reflection.isVector(Vector.)); + assertTrue(Reflection.isVector(Vector.)); + assertTrue(Reflection.isVector(Vector.<*>)); + assertTrue(Reflection.isVector(Vector)); + + assertFalse(Reflection.isVector(null)); + assertFalse(Reflection.isVector(undefined)); + assertFalse(Reflection.isVector(false)); + assertFalse(Reflection.isVector(0)); + + assertFalse(Reflection.isVector("Vector.<*>")); + assertFalse(Reflection.isVector("new Vector.<*>")); + assertFalse(Reflection.isVector("new Vector.<*>()")); + assertFalse(Reflection.isVector("Vector")); + + assertFalse(Reflection.isVector(Array)); + assertFalse(Reflection.isVector([])); + + assertFalse(Reflection.isVector(Object)); + assertFalse(Reflection.isVector({})); + } + + public function test_isAssociativeArray():void + { + assertTrue(Reflection.isAssociativeArray(Object)); + assertTrue(Reflection.isAssociativeArray({})); + assertTrue(Reflection.isAssociativeArray(new Dictionary())); + assertTrue(Reflection.isAssociativeArray(Dictionary)); + + assertFalse(Reflection.isAssociativeArray(new Vector.())); + assertFalse(Reflection.isAssociativeArray(new [new TestClass(), m_test])); + assertFalse(Reflection.isAssociativeArray(Vector.)); + + assertFalse(Reflection.isAssociativeArray("Object")); + assertFalse(Reflection.isAssociativeArray("{}")); + assertFalse(Reflection.isAssociativeArray("new Dictionary()")); + assertFalse(Reflection.isAssociativeArray("Dictionary")); + + assertFalse(Reflection.isAssociativeArray(null)); + assertFalse(Reflection.isAssociativeArray(undefined)); + assertFalse(Reflection.isAssociativeArray(false)); + assertFalse(Reflection.isAssociativeArray(0)); + + assertFalse(Reflection.isAssociativeArray(Array)); + assertFalse(Reflection.isAssociativeArray([])); + + assertFalse(Reflection.isAssociativeArray(m_test)); + assertFalse(Reflection.isAssociativeArray(BaseClass)); + } + + public function testComprehensive():void + { + assertSame(Vector., + Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(new Vector.())))()) ); + assertSame(Vector.<*>, + Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(new Vector.<*>())))()) ); + assertSame(Vector., + Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(new Vector.())))()) ); + + assertSame(TestClass, + Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(TestClass)))()) ); + assertSame(Date, + Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(new Date())))()) ); + + assertSame(Object, + Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName({})))()) ); + + assertSame(int, + Reflection.getClass(new (Reflection.getClassByName(Reflection.getQualifiedClassName(5)))()) ); + } + + //-------------------------------------- + // PRIVATE INSTANCE METHODS + //-------------------------------------- + + /** + * Test Reflection.getClass with the provided ApplicationDomain + * @param appDomain + */ + private function baseTest_getClass(appDomain:ApplicationDomain):void + { + assertSame(int, Reflection.getClass(0, appDomain)); + assertSame(Array, Reflection.getClass([], appDomain)); + assertSame(Date, Reflection.getClass(new Date(), appDomain)); + assertSame(Object, Reflection.getClass({}, appDomain)); + + assertNull(Reflection.getClass(null, appDomain)); + + assertSame(TestClass, Reflection.getClass(m_test, appDomain)); + assertSame(BaseClass, Reflection.getClass(BaseClass, appDomain)); + assertSame(String, Reflection.getClass("TypeInfo", appDomain)); + assertSame(String, Reflection.getClass("dna.utils.reflection::TypeInfo", appDomain)); + } + + private function baseTest_getClassByName(appDomain:ApplicationDomain):void + { + assertSame(uint, Reflection.getClassByName("uint", appDomain)); + assertSame(int, Reflection.getClassByName("int", appDomain)); + assertSame(Number, Reflection.getClassByName("Number", appDomain)); + assertSame(Array, Reflection.getClassByName("Array", appDomain)); + assertSame(Date, Reflection.getClassByName("Date", appDomain)); + assertSame(Class, Reflection.getClassByName("Class", appDomain)); + assertSame(Dictionary, Reflection.getClassByName("flash.utils.Dictionary", appDomain)); + assertSame(Dictionary, Reflection.getClassByName("flash.utils::Dictionary", appDomain)); + assertSame(BaseClass, Reflection.getClassByName("mock.foo.bar.BaseClass", appDomain)); + assertSame(BaseClass, Reflection.getClassByName("mock.foo.bar::BaseClass", appDomain)); + assertSame(TestClass, Reflection.getClassByName("mock.foo.bar::TestClass", appDomain)); + assertSame(IFoo, Reflection.getClassByName("mock.foo::IFoo", appDomain)); + + assertSame(Object, Reflection.getClassByName("*", appDomain)); + assertSame(Object, Reflection.getClassByName("Object", appDomain)); + + assertNull(Reflection.getClassByName("null", appDomain)); + assertNull(Reflection.getClassByName("void", appDomain)); + assertNull(Reflection.getClassByName("undefined", appDomain)); + + assertSame(Vector.<*>, Reflection.getClassByName("Vector.<*>", appDomain)); + assertSame(Vector.<*>, Reflection.getClassByName("__AS3__.vec::Vector.<*>", appDomain)); + assertSame(Vector., Reflection.getClassByName("Vector.", appDomain)); + assertSame(Vector., Reflection.getClassByName("__AS3__.vec::Vector.", appDomain)); + assertSame(Vector.>,Reflection.getClassByName("Vector.<__AS3__.vec::Vector.>", appDomain)); + + assertThrows(ClassNotFoundError, function():void { Reflection.getClassByName("foo", appDomain) } ); + assertThrows(ClassNotFoundError, function():void { Reflection.getClassByName("TestClass", appDomain) } ); + //TODO: Find a fix for this? + assertThrows(ClassNotFoundError, function():void { Reflection.getClassByName("Vector.<__AS3__.vec::Vector.<*>>", appDomain) }); + } + + private function baseTest_getSuperClass(appDomain:ApplicationDomain):void + { + assertSame(BaseClass, Reflection.getSuperClass(m_test, appDomain)); + assertSame(BaseClass, Reflection.getSuperClass(TestClass, appDomain)); + assertSame(TestClass, Reflection.getSuperClass(FinalClass, appDomain)); + assertSame(Object, Reflection.getSuperClass(BaseClass, appDomain)); + assertSame(Object, Reflection.getSuperClass(Date, appDomain)); + assertSame(Object, Reflection.getSuperClass(Array, appDomain)); + + assertSame(Vector.<*>, Reflection.getSuperClass(Vector., appDomain)); + assertSame(Vector.<*>, Reflection.getSuperClass(Vector.>, appDomain)); + assertSame(Vector.<*>, Reflection.getSuperClass(Vector., appDomain)); + assertSame(Object, Reflection.getSuperClass(Vector.<*>, appDomain)); + + //strings + assertSame(Object, Reflection.getSuperClass("TestClass", appDomain)); + assertSame(Object, Reflection.getSuperClass("mock.foo.bar::TestClass", appDomain)); + + //no parent class of Object + assertNull(Reflection.getSuperClass(Object, appDomain)); + + //should return null instead of throwing null argument error + assertNull(Reflection.getSuperClass(null, appDomain)); + } + + private function baseTest_getVectorType(appDomain:ApplicationDomain):void + { + assertSame(String, Reflection.getVectorType(new Vector.(), appDomain)); + assertSame(BaseClass, Reflection.getVectorType(new Vector.(), appDomain)); + + assertSame(IFoo, Reflection.getVectorType(new Vector.(), appDomain)); + + assertSame(Object, Reflection.getVectorType(new Vector.(), appDomain)); + assertSame(Object, Reflection.getVectorType(new Vector.<*>(), appDomain)); + + assertNull(Reflection.getVectorType([], appDomain)); + assertNull(Reflection.getVectorType("string", appDomain)); + + assertSame(Vector., Reflection.getVectorType(new Vector.>(), appDomain)); + assertSame(Vector.>, Reflection.getVectorType(new Vector.>>(), appDomain)); + assertSame(Vector., Reflection.getVectorType(new Vector.>(), appDomain)); + + assertNull(Reflection.getVectorType(null, appDomain)); + } + + private function baseTest_classExtendsClass(appDomain:ApplicationDomain):void + { + assertTrue(Reflection.classExtendsClass(FinalClass, TestClass, appDomain)); + assertTrue(Reflection.classExtendsClass(FinalClass, BaseClass, appDomain)); + assertTrue(Reflection.classExtendsClass(BaseClass, Object, appDomain)); + + assertFalse(Reflection.classExtendsClass(TestClass, FinalClass, appDomain)); + assertFalse(Reflection.classExtendsClass(TestClass, TestClass, appDomain)); + assertFalse(Reflection.classExtendsClass(Object, Object, appDomain)); + + assertFalse(Reflection.classExtendsClass(null, Object, appDomain)); + assertFalse(Reflection.classExtendsClass(Object, null, appDomain)); + assertFalse(Reflection.classExtendsClass(null, FinalClass, appDomain)); + assertFalse(Reflection.classExtendsClass(FinalClass,null, appDomain)); + assertFalse(Reflection.classExtendsClass(null, null, appDomain)); + + //assertFalse(Reflection.classExtendsClass(Class(Vector.), Class(Vector.), appDomain)); + } } -} \ No newline at end of file +} diff --git a/test/src/test/nexus/utils/reflection/TypeInfoTest.as b/test/src/test/nexus/utils/reflection/TypeInfoTest.as index 9684794..878123b 100644 --- a/test/src/test/nexus/utils/reflection/TypeInfoTest.as +++ b/test/src/test/nexus/utils/reflection/TypeInfoTest.as @@ -17,165 +17,165 @@ import nexus.utils.reflection.*; public class TypeInfoTest extends AbstractReflectionTest { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function TypeInfoTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - //-------------------------------------- - // TESTS - //-------------------------------------- - - public function test_caching():void - { - assertSame(m_testTypeInfo, Reflection.getTypeInfo(m_test)); - assertSame(m_baseTypeInfo, Reflection.getTypeInfo(m_baseTypeInfo.type, ApplicationDomain.currentDomain)); - assertSame(m_finalTypeInfo, Reflection.getTypeInfo(FinalClass, Reflection.SYSTEM_DOMAIN)); - - //TODO: Add checking for child app domains - //assertSame(m_baseTypeInfo, Reflection.getTypeInfo(m_baseTypeInfo.type, new ApplicationDomain(ApplicationDomain.currentDomain))); - } - - public function test_isDynamic():void - { - assertEquals(true, m_testTypeInfo.isDynamic); - assertEquals(false, m_baseTypeInfo.isDynamic); - assertEquals(false, m_finalTypeInfo.isDynamic); - } - - public function test_isFinal():void - { - assertEquals(false, m_testTypeInfo.isFinal); - assertEquals(false, m_baseTypeInfo.isFinal); - assertEquals(true, m_finalTypeInfo.isFinal); - } - - public function test_type():void - { - assertSame(TestClass, m_testTypeInfo.type); - assertSame(BaseClass, m_baseTypeInfo.type); - assertSame(FinalClass, m_finalTypeInfo.type); - } - - public function test_name():void - { - assertEquals("mock.foo.bar::TestClass", m_testTypeInfo.name); - assertEquals("mock.foo.bar::BaseClass", m_baseTypeInfo.name); - assertEquals("mock.foo.bar::FinalClass",m_finalTypeInfo.name); - } - - public function test_extendedClasses():void - { - assertEquals(1, m_testTypeInfo.extendedClasses.indexOf(Object)); - assertEquals(0, m_testTypeInfo.extendedClasses.indexOf(BaseClass)); - assertEquals( -1, m_testTypeInfo.extendedClasses.indexOf(TestClass)); - assertEquals( -1, m_testTypeInfo.extendedClasses.indexOf(Sprite)); - - assertEquals(0, m_baseTypeInfo.extendedClasses.indexOf(Object)); - assertEquals( -1, m_baseTypeInfo.extendedClasses.indexOf(BaseClass)); - assertEquals( -1, m_baseTypeInfo.extendedClasses.indexOf(TestClass)); - assertEquals( -1, m_baseTypeInfo.extendedClasses.indexOf(Sprite)); - - assertEquals(2, m_finalTypeInfo.extendedClasses.indexOf(Object)); - assertEquals(1, m_finalTypeInfo.extendedClasses.indexOf(BaseClass)); - assertEquals(0, m_finalTypeInfo.extendedClasses.indexOf(TestClass)); - assertEquals( -1, m_finalTypeInfo.extendedClasses.indexOf(Sprite)); - } - - public function test_implementedInterfaces():void - { - assertEquals(0, m_testTypeInfo.implementedInterfaces.indexOf(IFoo)); - - assertEquals( -1, m_baseTypeInfo.implementedInterfaces.indexOf(IFoo)); - - assertEquals(-1, m_baseTypeInfo.implementedInterfaces.indexOf(IFoo)); - } - - public function testNamespacing():void - { - m_test.publicProperty = 555; - - assertNotNull(m_testTypeInfo.getMethodByName("namespacedMethod")); - testMethodCalls(m_testTypeInfo.getMethodByName("namespacedMethod")); - - assertNotNull(m_testTypeInfo.getMethodByName("baseMethod")); - testMethodCalls(m_testTypeInfo.getMethodByName("baseMethod")); - } - - private function testMethodCalls(methodInfo:MethodInfo):void - { - assertEquals("555append", methodInfo.invoke(m_test, "append")); - assertEquals("555appendfoo", methodInfo.invoke(m_test, "append", "foo")); - assertEquals("555", methodInfo.invoke(m_test, null)); - assertEquals("555foo", methodInfo.invoke(m_test, null, "foo")); - - assertEquals("555append", m_test[methodInfo.qname]("append")); - assertEquals("555appendfoo", m_test[methodInfo.qname]("append", "foo")); - assertEquals("555", m_test[methodInfo.qname](null)); - assertEquals("555foo", m_test[methodInfo.qname](null, "foo")); - } - - public function testMetadata():void - { - var method : MethodInfo; - // - //base class - // - assertNotNull(m_baseTypeInfo.getMetadataByName("ClassMetadata")); - - assertNotNull(m_baseTypeInfo.getMethodByName("baseMethod")); - method = m_baseTypeInfo.getMethodByName("baseMethod"); - - assertNotNull(method.getMetadataByName("MethodMetadata")); - - assertEquals("BaseClass", method.getMetadataByName("MethodMetadata").getValue("on")); - - // - //test class - // - assertNotNull(m_testTypeInfo.getMetadataByName("ClassMetadata")); - - assertEquals("ClassMetadata", m_testTypeInfo.getMetadataByName("ClassMetadata").metadataName); - - assertEquals("TestClass", m_testTypeInfo.getMetadataByName("ClassMetadata").getValue("on")); - assertEquals("value", m_testTypeInfo.getMetadataByName("ClassMetadata").metadataKeyValuePairs["param"]); - - assertNotNull(m_testTypeInfo.getMethodByName("baseMethod")); - method = m_testTypeInfo.getMethodByName("baseMethod"); - - //TODO: I feel like there is some inconsistency here and that these should work - //assertNotNull(method.getMetadataByName("MethodMetadata")); - - //assertEquals("BaseClass", method.getMetadataByName("MethodMetadata").getValue("on")); - - // - //final class - // - assertNull(m_finalTypeInfo.getMetadataByName("ClassMetadata")); - - assertNotNull(m_finalTypeInfo.getMethodByName("baseMethod")); - method = m_finalTypeInfo.getMethodByName("baseMethod"); - - assertNotNull(method.getMetadataByName("MethodMetadata")); - - assertEquals("FinalClass", method.getMetadataByName("MethodMetadata").getValue("on")); - } + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function TypeInfoTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + //-------------------------------------- + // TESTS + //-------------------------------------- + + public function test_caching():void + { + assertSame(m_testTypeInfo, Reflection.getTypeInfo(m_test)); + assertSame(m_baseTypeInfo, Reflection.getTypeInfo(m_baseTypeInfo.type, ApplicationDomain.currentDomain)); + assertSame(m_finalTypeInfo, Reflection.getTypeInfo(FinalClass, Reflection.SYSTEM_DOMAIN)); + + //TODO: Add checking for child app domains + //assertSame(m_baseTypeInfo, Reflection.getTypeInfo(m_baseTypeInfo.type, new ApplicationDomain(ApplicationDomain.currentDomain))); + } + + public function test_isDynamic():void + { + assertEquals(true, m_testTypeInfo.isDynamic); + assertEquals(false, m_baseTypeInfo.isDynamic); + assertEquals(false, m_finalTypeInfo.isDynamic); + } + + public function test_isFinal():void + { + assertEquals(false, m_testTypeInfo.isFinal); + assertEquals(false, m_baseTypeInfo.isFinal); + assertEquals(true, m_finalTypeInfo.isFinal); + } + + public function test_type():void + { + assertSame(TestClass, m_testTypeInfo.type); + assertSame(BaseClass, m_baseTypeInfo.type); + assertSame(FinalClass, m_finalTypeInfo.type); + } + + public function test_name():void + { + assertEquals("mock.foo.bar::TestClass", m_testTypeInfo.name); + assertEquals("mock.foo.bar::BaseClass", m_baseTypeInfo.name); + assertEquals("mock.foo.bar::FinalClass",m_finalTypeInfo.name); + } + + public function test_extendedClasses():void + { + assertEquals(1, m_testTypeInfo.extendedClasses.indexOf(Object)); + assertEquals(0, m_testTypeInfo.extendedClasses.indexOf(BaseClass)); + assertEquals( -1, m_testTypeInfo.extendedClasses.indexOf(TestClass)); + assertEquals( -1, m_testTypeInfo.extendedClasses.indexOf(Sprite)); + + assertEquals(0, m_baseTypeInfo.extendedClasses.indexOf(Object)); + assertEquals( -1, m_baseTypeInfo.extendedClasses.indexOf(BaseClass)); + assertEquals( -1, m_baseTypeInfo.extendedClasses.indexOf(TestClass)); + assertEquals( -1, m_baseTypeInfo.extendedClasses.indexOf(Sprite)); + + assertEquals(2, m_finalTypeInfo.extendedClasses.indexOf(Object)); + assertEquals(1, m_finalTypeInfo.extendedClasses.indexOf(BaseClass)); + assertEquals(0, m_finalTypeInfo.extendedClasses.indexOf(TestClass)); + assertEquals( -1, m_finalTypeInfo.extendedClasses.indexOf(Sprite)); + } + + public function test_implementedInterfaces():void + { + assertEquals(0, m_testTypeInfo.implementedInterfaces.indexOf(IFoo)); + + assertEquals( -1, m_baseTypeInfo.implementedInterfaces.indexOf(IFoo)); + + assertEquals(-1, m_baseTypeInfo.implementedInterfaces.indexOf(IFoo)); + } + + public function testNamespacing():void + { + m_test.publicProperty = 555; + + assertNotNull(m_testTypeInfo.getMethodByName("namespacedMethod")); + testMethodCalls(m_testTypeInfo.getMethodByName("namespacedMethod")); + + assertNotNull(m_testTypeInfo.getMethodByName("baseMethod")); + testMethodCalls(m_testTypeInfo.getMethodByName("baseMethod")); + } + + private function testMethodCalls(methodInfo:MethodInfo):void + { + assertEquals("555append", methodInfo.invoke(m_test, "append")); + assertEquals("555appendfoo", methodInfo.invoke(m_test, "append", "foo")); + assertEquals("555", methodInfo.invoke(m_test, null)); + assertEquals("555foo", methodInfo.invoke(m_test, null, "foo")); + + assertEquals("555append", m_test[methodInfo.qname]("append")); + assertEquals("555appendfoo", m_test[methodInfo.qname]("append", "foo")); + assertEquals("555", m_test[methodInfo.qname](null)); + assertEquals("555foo", m_test[methodInfo.qname](null, "foo")); + } + + public function testMetadata():void + { + var method : MethodInfo; + // + //base class + // + assertNotNull(m_baseTypeInfo.getMetadataByName("ClassMetadata")); + + assertNotNull(m_baseTypeInfo.getMethodByName("baseMethod")); + method = m_baseTypeInfo.getMethodByName("baseMethod"); + + assertNotNull(method.getMetadataByName("MethodMetadata")); + + assertEquals("BaseClass", method.getMetadataByName("MethodMetadata").getValue("on")); + + // + //test class + // + assertNotNull(m_testTypeInfo.getMetadataByName("ClassMetadata")); + + assertEquals("ClassMetadata", m_testTypeInfo.getMetadataByName("ClassMetadata").metadataName); + + assertEquals("TestClass", m_testTypeInfo.getMetadataByName("ClassMetadata").getValue("on")); + assertEquals("value", m_testTypeInfo.getMetadataByName("ClassMetadata").metadataKeyValuePairs["param"]); + + assertNotNull(m_testTypeInfo.getMethodByName("baseMethod")); + method = m_testTypeInfo.getMethodByName("baseMethod"); + + //TODO: I feel like there is some inconsistency here and that these should work + //assertNotNull(method.getMetadataByName("MethodMetadata")); + + //assertEquals("BaseClass", method.getMetadataByName("MethodMetadata").getValue("on")); + + // + //final class + // + assertNull(m_finalTypeInfo.getMetadataByName("ClassMetadata")); + + assertNotNull(m_finalTypeInfo.getMethodByName("baseMethod")); + method = m_finalTypeInfo.getMethodByName("baseMethod"); + + assertNotNull(method.getMetadataByName("MethodMetadata")); + + assertEquals("FinalClass", method.getMetadataByName("MethodMetadata").getValue("on")); + } } -} \ No newline at end of file +} diff --git a/test/src/test/nexus/utils/serialization/amf/AmfSerializationTest.as b/test/src/test/nexus/utils/serialization/amf/AmfSerializationTest.as index ce5f3ae..dc9d642 100644 --- a/test/src/test/nexus/utils/serialization/amf/AmfSerializationTest.as +++ b/test/src/test/nexus/utils/serialization/amf/AmfSerializationTest.as @@ -14,30 +14,30 @@ import asunit.framework.TestCase; */ public class AmfSerializationTest extends TestCase { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function AmfSerializationTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - //-------------------------------------- - // TESTS - //-------------------------------------- + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function AmfSerializationTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + //-------------------------------------- + // TESTS + //-------------------------------------- } -} \ No newline at end of file +} diff --git a/test/src/test/nexus/utils/serialization/json/JsonSerializerTest.as b/test/src/test/nexus/utils/serialization/json/JsonSerializerTest.as index 7c93705..0a46987 100644 --- a/test/src/test/nexus/utils/serialization/json/JsonSerializerTest.as +++ b/test/src/test/nexus/utils/serialization/json/JsonSerializerTest.as @@ -22,193 +22,193 @@ import nexus.utils.serialization.json.JsonSerializer; */ public class JsonSerializerTest extends TestCase { - //-------------------------------------- - // CLASS CONSTANTS - //-------------------------------------- - - //-------------------------------------- - // INSTANCE VARIABLES - //-------------------------------------- - - private var m_base1 : BaseClass; - private var m_base2 : BaseClass; + //-------------------------------------- + // CLASS CONSTANTS + //-------------------------------------- + + //-------------------------------------- + // INSTANCE VARIABLES + //-------------------------------------- + + private var m_base1 : BaseClass; + private var m_base2 : BaseClass; private var m_sub1 : TestClass; private var m_sub2 : TestClass; - - private var m_serializer1 : JsonSerializer; - private var m_serializer2 : JsonSerializer; - - private var m_json1 : Object; - private var m_json2 : Object; - - //-------------------------------------- - // CONSTRUCTOR - //-------------------------------------- - - public function JsonSerializerTest(testMethod:String = null) - { - super(testMethod); - } - - //-------------------------------------- - // SETUP & TEARDOWN - //-------------------------------------- - - override protected function setUp():void - { - m_base1 = new BaseClass(); - m_base2 = new BaseClass(); - m_base1.baseVar = m_base2.baseVar = 100; - m_base1.mockEnum = m_base2.mockEnum = MockEnum.Value2; - m_base1.testing_namespace::baseVar = "test_serialization3"; + + private var m_serializer1 : JsonSerializer; + private var m_serializer2 : JsonSerializer; + + private var m_json1 : Object; + private var m_json2 : Object; + + //-------------------------------------- + // CONSTRUCTOR + //-------------------------------------- + + public function JsonSerializerTest(testMethod:String = null) + { + super(testMethod); + } + + //-------------------------------------- + // SETUP & TEARDOWN + //-------------------------------------- + + override protected function setUp():void + { + m_base1 = new BaseClass(); + m_base2 = new BaseClass(); + m_base1.baseVar = m_base2.baseVar = 100; + m_base1.mockEnum = m_base2.mockEnum = MockEnum.Value2; + m_base1.testing_namespace::baseVar = "test_serialization3"; m_sub1 = new TestClass(); m_sub2 = new TestClass(); - m_serializer1 = new JsonSerializer(); - m_serializer2 = new JsonSerializer(); - } - - override protected function tearDown():void - { - m_base1 = null; - m_base2 = null; - - m_serializer1 = null; - m_serializer2 = null; + m_serializer1 = new JsonSerializer(); + m_serializer2 = new JsonSerializer(); + } + + override protected function tearDown():void + { + m_base1 = null; + m_base2 = null; + + m_serializer1 = null; + m_serializer2 = null; - m_json1 = null; - m_json2 = null; - } - - //-------------------------------------- - // TESTS - //-------------------------------------- - - /** - * Ensure that all calls to a serializer with identical data produce identical results - */ - public function test_determinism():void - { - //first instance - - m_json1 = m_serializer1.serialize(m_base1); - m_json2 = m_serializer1.serialize(m_base1); - assertEquals(m_json1, m_json2); - - m_json1 = m_serializer2.serialize(m_base1); - m_json2 = m_serializer2.serialize(m_base1); - assertEquals(m_json1, m_json2); - - m_json1 = m_serializer1.serialize(m_base1); - m_json2 = m_serializer2.serialize(m_base1); - assertEquals(m_json1, m_json2); - - //second instance - - m_json1 = m_serializer1.serialize(m_base2); - m_json2 = m_serializer1.serialize(m_base2); - assertEquals(m_json1, m_json2); - - m_json1 = m_serializer2.serialize(m_base2); - m_json2 = m_serializer2.serialize(m_base2); - assertEquals(m_json1, m_json2); - - m_json1 = m_serializer1.serialize(m_base2); - m_json2 = m_serializer2.serialize(m_base2); - assertEquals(m_json1, m_json2); - - //both instances - - m_json1 = m_serializer1.serialize(m_base1); - m_json2 = m_serializer1.serialize(m_base2); - assertEquals(m_json1, m_json2); - - m_json1 = m_serializer2.serialize(m_base1); - m_json2 = m_serializer2.serialize(m_base2); - assertEquals(m_json1, m_json2); - - m_json1 = m_serializer1.serialize(m_base1); - m_json2 = m_serializer2.serialize(m_base2); - assertEquals(m_json1, m_json2); - - m_json1 = m_serializer1.serialize(m_base2); - m_json2 = m_serializer2.serialize(m_base1); - assertEquals(m_json1, m_json2); - } - - /** - * Repeatedly serialize and deserialize the same data to insure integrity - */ - public function test_integrity():void - { - internal_testIntegrity(false); - } - - /** - * Ensure serializing with a namespace is different than without (where m_base1 has namespaced fields) - */ - public function test_namespace1():void - { - m_serializer1.includeNamespace(testing_namespace); - - m_json1 = m_serializer1.serialize(m_base1); - m_json2 = m_serializer2.serialize(m_base1); - assertTrue(m_json1 != m_json2); - } - - /** - * Repeatedly serialize and deserialize the same data, including a namespace, to insure integrity - */ - public function test_namespaceIntegrity():void - { - //internal_testIntegrity(true); - } - - /** - * serialize a typed object with a namespaced field and then deserialize into a typed object - */ - public function test_namespace3():void - { - //TODO: This is really a test of ObjectUtils - m_serializer1.includeNamespace(testing_namespace); - - m_json1 = m_serializer1.serialize(m_base1); - m_base2 = m_serializer1.deserialize(m_json1, BaseClass) as BaseClass; - m_json2 = m_serializer1.serialize(m_base2); - assertEquals(m_json1, m_json2); - } - - /** - * Add a bunch of extra values to the deserialized object and create an instance of it - */ - public function test_dynamic():void - { - var deserialized : Object; - - m_serializer1.includeNamespace(testing_namespace); - - m_json1 = m_serializer1.serialize(m_base1); - deserialized = m_serializer1.deserialize(m_json1); - deserialized["extra.foo::field"] = "blah blah"; - deserialized["http://mock.testing_namespace::var"] = "foo"; - m_base2 = ObjectUtils.createTypedObjectFromNativeObject(BaseClass, deserialized) as BaseClass; - m_json2 = m_serializer1.serialize(m_base2); - assertEquals(m_json1, m_json2); - } - - public function test_IJsonSerializable():void - { - var custom : CustomSerializationClass = new CustomSerializationClass(); - var id : int = CustomSerializationClass.id; - - m_json1 = m_serializer1.serialize(custom); - assertEquals("\"CustomSerializationClass" + id + "\"", m_json1); - - custom = m_serializer1.deserialize(m_json1, CustomSerializationClass) as CustomSerializationClass; - assertEquals("CustomSerializationClass" + id, custom.baseString); - } + m_json1 = null; + m_json2 = null; + } + + //-------------------------------------- + // TESTS + //-------------------------------------- + + /** + * Ensure that all calls to a serializer with identical data produce identical results + */ + public function test_determinism():void + { + //first instance + + m_json1 = m_serializer1.serialize(m_base1); + m_json2 = m_serializer1.serialize(m_base1); + assertEquals(m_json1, m_json2); + + m_json1 = m_serializer2.serialize(m_base1); + m_json2 = m_serializer2.serialize(m_base1); + assertEquals(m_json1, m_json2); + + m_json1 = m_serializer1.serialize(m_base1); + m_json2 = m_serializer2.serialize(m_base1); + assertEquals(m_json1, m_json2); + + //second instance + + m_json1 = m_serializer1.serialize(m_base2); + m_json2 = m_serializer1.serialize(m_base2); + assertEquals(m_json1, m_json2); + + m_json1 = m_serializer2.serialize(m_base2); + m_json2 = m_serializer2.serialize(m_base2); + assertEquals(m_json1, m_json2); + + m_json1 = m_serializer1.serialize(m_base2); + m_json2 = m_serializer2.serialize(m_base2); + assertEquals(m_json1, m_json2); + + //both instances + + m_json1 = m_serializer1.serialize(m_base1); + m_json2 = m_serializer1.serialize(m_base2); + assertEquals(m_json1, m_json2); + + m_json1 = m_serializer2.serialize(m_base1); + m_json2 = m_serializer2.serialize(m_base2); + assertEquals(m_json1, m_json2); + + m_json1 = m_serializer1.serialize(m_base1); + m_json2 = m_serializer2.serialize(m_base2); + assertEquals(m_json1, m_json2); + + m_json1 = m_serializer1.serialize(m_base2); + m_json2 = m_serializer2.serialize(m_base1); + assertEquals(m_json1, m_json2); + } + + /** + * Repeatedly serialize and deserialize the same data to insure integrity + */ + public function test_integrity():void + { + internal_testIntegrity(false); + } + + /** + * Ensure serializing with a namespace is different than without (where m_base1 has namespaced fields) + */ + public function test_namespace1():void + { + m_serializer1.includeNamespace(testing_namespace); + + m_json1 = m_serializer1.serialize(m_base1); + m_json2 = m_serializer2.serialize(m_base1); + assertTrue(m_json1 != m_json2); + } + + /** + * Repeatedly serialize and deserialize the same data, including a namespace, to insure integrity + */ + public function test_namespaceIntegrity():void + { + //internal_testIntegrity(true); + } + + /** + * serialize a typed object with a namespaced field and then deserialize into a typed object + */ + public function test_namespace3():void + { + //TODO: This is really a test of ObjectUtils + m_serializer1.includeNamespace(testing_namespace); + + m_json1 = m_serializer1.serialize(m_base1); + m_base2 = m_serializer1.deserialize(m_json1, BaseClass) as BaseClass; + m_json2 = m_serializer1.serialize(m_base2); + assertEquals(m_json1, m_json2); + } + + /** + * Add a bunch of extra values to the deserialized object and create an instance of it + */ + public function test_dynamic():void + { + var deserialized : Object; + + m_serializer1.includeNamespace(testing_namespace); + + m_json1 = m_serializer1.serialize(m_base1); + deserialized = m_serializer1.deserialize(m_json1); + deserialized["extra.foo::field"] = "blah blah"; + deserialized["http://mock.testing_namespace::var"] = "foo"; + m_base2 = ObjectUtils.createTypedObjectFromNativeObject(BaseClass, deserialized) as BaseClass; + m_json2 = m_serializer1.serialize(m_base2); + assertEquals(m_json1, m_json2); + } + + public function test_IJsonSerializable():void + { + var custom : CustomSerializationClass = new CustomSerializationClass(); + var id : int = CustomSerializationClass.id; + + m_json1 = m_serializer1.serialize(custom); + assertEquals("\"CustomSerializationClass" + id + "\"", m_json1); + + custom = m_serializer1.deserialize(m_json1, CustomSerializationClass) as CustomSerializationClass; + assertEquals("CustomSerializationClass" + id, custom.baseString); + } public function test_circular():void { @@ -216,33 +216,33 @@ public class JsonSerializerTest extends TestCase m_json1 = m_serializer1.serialize(m_sub1); } - - //-------------------------------------- - // PRIVATE INSTANCE METHODS - //-------------------------------------- - - private function internal_testIntegrity(includeTestingNamespace:Boolean):void - { - var deserialized : Object; - - if(includeTestingNamespace) - { - m_serializer1.includeNamespace(testing_namespace); - } - - m_json1 = m_serializer1.serialize(m_base1); - deserialized = m_serializer1.deserialize(m_json1); - m_json2 = m_serializer1.serialize(deserialized); - assertEquals(m_json1, m_json2); - - deserialized = m_serializer2.deserialize(m_json2); - m_json1 = m_serializer2.serialize(deserialized); - assertEquals(m_json1, m_json2); - - deserialized = m_serializer1.deserialize(m_json1); - m_json2 = m_serializer1.serialize(deserialized); - assertEquals(m_json1, m_json2); - } + + //-------------------------------------- + // PRIVATE INSTANCE METHODS + //-------------------------------------- + + private function internal_testIntegrity(includeTestingNamespace:Boolean):void + { + var deserialized : Object; + + if(includeTestingNamespace) + { + m_serializer1.includeNamespace(testing_namespace); + } + + m_json1 = m_serializer1.serialize(m_base1); + deserialized = m_serializer1.deserialize(m_json1); + m_json2 = m_serializer1.serialize(deserialized); + assertEquals(m_json1, m_json2); + + deserialized = m_serializer2.deserialize(m_json2); + m_json1 = m_serializer2.serialize(deserialized); + assertEquals(m_json1, m_json2); + + deserialized = m_serializer1.deserialize(m_json1); + m_json2 = m_serializer1.serialize(deserialized); + assertEquals(m_json1, m_json2); + } } -} \ No newline at end of file +}