예제 #1
0
        public void EqualsWithSamePropertiesAndMemberNameArrayInstancesIsTrue()
        {
            ASClass class1 = new ASClass("abc", ASClassLayout.Normal, EmptyArray <string> .Instance);
            ASClass class2 = new ASClass("abc", ASClassLayout.Normal, EmptyArray <string> .Instance);

            Assert.AreNotEqual(class1, class2);
        }
예제 #2
0
        protected virtual void WriteClassHashData(BinaryWriter hashInput, ASClass asClass)
        {
            ABCFile abc = asClass.ABC;

            WriteTraitsHashData(hashInput, asClass);
            WriteMethodHashData(hashInput, asClass.Constructor, true);

            WriteTraitsHashData(hashInput, asClass.Instance);
            WriteMethodHashData(hashInput, asClass.Instance.Constructor, true);

            string superClassObjName = asClass.Instance.SuperType?.ObjName;

            if (!string.IsNullOrWhiteSpace(superClassObjName) && superClassObjName != "Object")
            {
                ASClass superClass = abc
                                     .FindClassByName(superClassObjName);

                if (superClass != null)
                {
                    WriteMultinameHashData(hashInput, asClass.Instance.SuperType);
                    WriteClassHashData(hashInput, superClass);
                }
            }

            hashInput.Write((byte)asClass.Instance.ClassInfo);
            hashInput.Write((byte)asClass.Instance.Type.MultinameType);
            hashInput.Write((byte)asClass.Instance.ProtectedNamespace.NamespaceType);
        }
예제 #3
0
        public void WriteObject_Objects_ClassDefinitionCaching_AMF3()
        {
            // Write out two untyped dynamic objects and two typed normal
            // objects and ensure the class definition is reused.
            ASObject untyped1 = new ASObject();
            ASObject untyped2 = new ASObject();
            ASClass  @class   = new ASClass("class", ASClassLayout.Normal, EmptyArray <string> .Instance);
            ASObject typed1   = new ASObject(@class);
            ASObject typed2   = new ASObject(@class);

            Mocks.ReplayAll();

            output.ObjectEncoding = AMFObjectEncoding.AMF3;
            output.BeginObjectStream();
            output.WriteObject(untyped1);
            output.WriteObject(typed1);
            output.WriteObject(untyped2);
            output.WriteObject(typed2);
            output.EndObjectStream();

            byte[] expected = new byte[] { (byte)AMF0ObjectTypeCode.AMF3Data,
                                           (byte)AMF3ObjectTypeCode.Object, 0x0b, 0x01, 0x01,                         // untyped1
                                           (byte)AMF3ObjectTypeCode.Object, 0x03, 0x0b, 0x63, 0x6c, 0x61, 0x73, 0x73, // typed1
                                           (byte)AMF3ObjectTypeCode.Object, 0x01, 0x01,                               // untyped2 using cached class definition
                                           (byte)AMF3ObjectTypeCode.Object, 0x05,                                     // typed2 using cached class definition
            };

            CollectionAssert.AreElementsEqual(expected, stream.ToArray());
        }
예제 #4
0
        static IList <Tuple <ushort, string, ASInstance> > OrganizeByHash(IDictionary <ushort, ASClass> messages, HFlash flash, bool isOutgoing)
        {
            var organizedMessages = new List <Tuple <ushort, string, ASInstance> >(messages.Count);
            var hashedMessages    = new Dictionary <string, List <Tuple <ushort, string, ASInstance> > >();

            foreach (ushort header in messages.Keys)
            {
                ASClass messageClass = messages[header];
                string  hash         = flash.GetHash(messageClass, ReferenceScan, isOutgoing);

                var messageData = new Tuple <ushort, string, ASInstance>(
                    header, hash, messageClass.Instance);

                if (!hashedMessages.ContainsKey(hash))
                {
                    hashedMessages[hash] =
                        new List <Tuple <ushort, string, ASInstance> >();
                }
                hashedMessages[hash].Add(messageData);
            }

            return(hashedMessages.Values
                   .OrderBy(l => l.Count)
                   .SelectMany(l => l).ToList());
        }
예제 #5
0
        public void EqualsWithDifferentMemberOrderIsFalse()
        {
            ASClass class1 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" });
            ASClass class2 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "def", "abc" });

            Assert.AreNotEqual(class1, class2);
        }
예제 #6
0
            protected override object MapObjectToNative(IActionScriptSerializer serializer, Type nativeType,
                                                        ASClass @class, IEnumerable <IASValue> memberValues,
                                                        IEnumerable <KeyValuePair <string, IASValue> > dynamicProperties,
                                                        IExternalizable externalizableValue)
            {
                IDictionary <TKey, TValue> dict = CreateDictionaryInstance(@class.MemberNames.Count);

                // Add members.
                int memberIndex = 0;

                foreach (IASValue memberValue in memberValues)
                {
                    TKey   key   = (TKey)Convert.ChangeType(@class.MemberNames[memberIndex], typeof(TKey));
                    TValue value = (TValue)serializer.ToNative(memberValue, typeof(TValue));
                    dict.Add(key, value);

                    memberIndex += 1;
                }

                // Add dynamic properties.
                foreach (KeyValuePair <string, IASValue> pair in dynamicProperties)
                {
                    TKey   key   = (TKey)Convert.ChangeType(pair.Key, typeof(TKey));
                    TValue value = (TValue)serializer.ToNative(pair.Value, typeof(TValue));
                    dict.Add(key, value);
                }

                return(dict);
            }
예제 #7
0
        public void EqualsWithIdenticalInstancesIsTrue()
        {
            ASClass class1 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" });
            ASClass class2 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" });

            Assert.AreEqual(class1, class2);
        }
예제 #8
0
        /// <summary>
        /// Retrieves a parsed class from its name
        /// </summary>
        /// <param name="cname">Class (short or full) name</param>
        /// <param name="inClass">Current class</param>
        /// <returns>A parsed class or an empty ASClass if the class is not found</returns>
        public ASClass GetClassByName(string cname, ASClass inClass)
        {
            ASClass aClass = new ASClass();

            aClass.ClassName = cname;
            return(aClass);
        }
예제 #9
0
        public override void SetUp()
        {
            base.SetUp();

            externalizableClass = new ASClass("extern", ASClassLayout.Externalizable, EmptyArray <string> .Instance);
            externalizable      = Mocks.CreateMock <IExternalizable>();
        }
예제 #10
0
        /// <summary>
        /// Retrieves a parsed class from its filename
        /// </summary>
        /// <param name="fileName">Class' file name</param>
        /// <returns>A parsed class or an empty ASClass if the class is not found or invalid</returns>
        public ASClass GetClassByFile(string fileName)
        {
            ASClass aClass = new ASClass();

            aClass.FileName = fileName;
            return(aClass);
        }
예제 #11
0
        public string GetHash(ASClass asClass, bool referenceScan, bool isOutgoing)
        {
            using (var hashStream = new MemoryStream())
                using (var hashInput = new BinaryWriter(hashStream))
                {
                    hashInput.Write(isOutgoing);
                    WriteHashData(hashInput, asClass, isOutgoing);

                    if (referenceScan)
                    {
                        ScanForMessageReferences(asClass.ABC);
                        if (_messageReferencesCache.ContainsKey(asClass))
                        {
                            List <Tuple <ASMethod, int> > messageReferences = _messageReferencesCache[asClass];
                            if (asClass.Instance.Type.ObjName == "RenderRoomMessageComposer")
                            {
                            }
                            foreach (Tuple <ASMethod, int> messageReference in messageReferences)
                            {
                                ASMethod referencingMethod = messageReference.Item1;
                                int      referenceId       = messageReference.Item2;

                                WriteMethodHashData(hashInput, referencingMethod, false);
                                hashInput.Write(referenceId);
                            }
                        }
                    }
                    return(GetHash(hashStream.ToArray()));
                }
        }
예제 #12
0
        public void WriteObject_Objects_Externalizable_AMF3()
        {
            IExternalizable externalizableValue = Mocks.CreateMock <IExternalizable>();

            externalizableValue.WriteExternal(output);
            LastCall.Do((WriteExternalDelegate) delegate(IDataOutput outputToUse)
            {
                // Note: outputToUse will be the same instance as output which we've already
                // tested so we don't need to try all combinations here.  Just a few as a sanity check.
                outputToUse.WriteUTF("abc");
                outputToUse.WriteInt(10);
                outputToUse.WriteObject(new ASString("def"));
            });

            ASClass @class             = new ASClass("class", ASClassLayout.Externalizable, EmptyArray <string> .Instance);
            ASExternalizableObject obj = new ASExternalizableObject(@class, externalizableValue);

            Mocks.ReplayAll();

            output.ObjectEncoding = AMFObjectEncoding.AMF3;
            output.BeginObjectStream();
            output.WriteObject(obj);
            output.EndObjectStream();

            byte[] expected = new byte[] { (byte)AMF0ObjectTypeCode.AMF3Data, (byte)AMF3ObjectTypeCode.Object, 0x07,
                                           0x0b, 0x63, 0x6c, 0x61, 0x73, 0x73,                     // class def
                                           0x00, 0x03, 0x61, 0x62, 0x63,                           // write utf "abc"
                                           0x00, 0x00, 0x00, 0x0a,                                 // write int 10
                                           (byte)AMF3ObjectTypeCode.String, 0x07, 0x64, 0x65, 0x66 // write object "def"
            };

            CollectionAssert.AreElementsEqual(expected, stream.ToArray());
        }
예제 #13
0
        protected virtual void WriteHashData(BinaryWriter hashInput, ASClass asClass, bool isOutgoing)
        {
            if (isOutgoing)
            {
                string outgoingTypeName =
                    asClass.Instance.Type.ObjName;

                if (outgoingTypeName.EndsWith("Composer"))
                {
                    hashInput.Write(outgoingTypeName);
                    return;
                }
            }
            else
            {
                ASClass parserClass =
                    GetIncomingParser(asClass.Instance);

                if (parserClass != null)
                {
                    WriteClassHashData(hashInput, parserClass);
                }
            }
            WriteClassHashData(hashInput, asClass);
        }
예제 #14
0
        static string DumpMessages(string type, IDictionary <ushort, ASClass> messages)
        {
            string headerDump = string.Empty;
            bool   isOutgoing = (type == "Outgoing");
            IList <Tuple <ushort, string, ASInstance> > organizedMessages = OrganizeByHash(messages, Client, isOutgoing);

            foreach (Tuple <ushort, string, ASInstance> organizedMessage in organizedMessages)
            {
                ushort     header   = organizedMessage.Item1;
                string     hash     = organizedMessage.Item2;
                ASInstance instance = organizedMessage.Item3;

                string ctorSignature = instance.Constructor.ToString();
                if (!isOutgoing)
                {
                    ASClass parserClass =
                        Client.GetIncomingParser(instance);

                    ctorSignature += (", Parser: " +
                                      parserClass.Instance.Type.ObjName);
                }

                headerDump += $"{type}[{header}]({hash}): {instance.Type.ObjName}{ctorSignature}\r\n";
                CountDuplicates(isOutgoing, hash);
            }
            return(headerDump.Trim());
        }
예제 #15
0
        private PacketValue[] GetOutgoingStructure(ASCode code, Local getLocal)
        {
            List <PacketValue> structure = new List <PacketValue>();

            for (int i = 0; i < code.Count; i++)
            {
                ASInstruction instruction = code[i];
                if (instruction == getLocal)
                {
                    break;
                }
                if (!Local.IsGetLocal(instruction.OP))
                {
                    continue;
                }

                Local local = (Local)instruction;
                if (local.Register != getLocal.Register)
                {
                    continue;
                }

                for (i += 1; i < code.Count; i++)
                {
                    ASInstruction next = code[i];
                    if (next.OP != OPCode.CallPropVoid)
                    {
                        continue;
                    }

                    CallPropVoidIns callPropVoid = (CallPropVoidIns)next;
                    if (callPropVoid.PropertyName.Name != "push")
                    {
                        continue;
                    }

                    ASInstruction previous = code[i - 1];
                    if (previous.OP == OPCode.GetProperty)
                    {
                        ASClass        classToCheck = Class;
                        GetPropertyIns getProperty  = (GetPropertyIns)previous;
                        ASMultiname    propertyName = getProperty.PropertyName;

                        ASInstruction beforeGetProp = code[i - 2];
                        if (beforeGetProp.OP == OPCode.GetLex)
                        {
                            GetLexIns getLex = (GetLexIns)beforeGetProp;
                            classToCheck = classToCheck.GetABC().GetClass(getLex.TypeName);
                        }

                        if (!TryGetPacketValue(propertyName, classToCheck, out PacketValue piece))
                        {
                            return(null);
                        }
                        structure.Add(piece);
                    }
                }
            }
            return(structure.Count == 0 ? null : structure.ToArray());
        }
예제 #16
0
        private string GetOutgoingStructure(ASCode code, Local getLocal)
        {
            string structure = null;

            for (int i = 0; i < code.Count; i++)
            {
                ASInstruction instruction = code[i];
                if (instruction == getLocal)
                {
                    break;
                }
                if (!Local.IsGetLocal(instruction.OP))
                {
                    continue;
                }

                var local = (Local)instruction;
                if (local.Register != getLocal.Register)
                {
                    continue;
                }

                for (i += 1; i < code.Count; i++)
                {
                    ASInstruction next = code[i];
                    if (next.OP != OPCode.CallPropVoid)
                    {
                        continue;
                    }

                    var callPropVoid = (CallPropVoidIns)next;
                    if (callPropVoid.PropertyName.Name != "push")
                    {
                        continue;
                    }

                    ASInstruction previous = code[i - 1];
                    if (previous.OP == OPCode.GetProperty)
                    {
                        ASClass     classToCheck = Class;
                        var         getProperty  = (GetPropertyIns)previous;
                        ASMultiname propertyName = getProperty.PropertyName;

                        ASInstruction beforeGetProp = code[i - 2];
                        if (beforeGetProp.OP == OPCode.GetLex)
                        {
                            var getLex = (GetLexIns)beforeGetProp;
                            classToCheck = classToCheck.GetABC().GetClass(getLex.TypeName);
                        }

                        if (!TryGetStructurePiece(propertyName, classToCheck, out char piece))
                        {
                            return(null);
                        }
                        structure += piece;
                    }
                }
            }
            return(structure);
        }
예제 #17
0
        /// <summary>
        /// Retrieves a parsed class from its filename
        /// </summary>
        /// <param name="fileName">Class' file name</param>
        /// <returns>A parsed class or an empty ASClass if the class is not found or invalid</returns>
        public ASClass FindClassFromFile(string fileName)
        {
            ASClass aClass = new ASClass();

            aClass.FileName = fileName;
            return(aClass);
        }
예제 #18
0
        /// <summary>
        /// Retrieves a parsed class from its name
        /// </summary>
        /// <param name="cname">Class (short or full) name</param>
        /// <param name="inClass">Current class</param>
        /// <returns>A parsed class or an empty ASClass if the class is not found</returns>
        public ASClass FindClassFromName(string cname, ASClass inClass)
        {
            ASClass aClass = new ASClass();

            aClass.ClassName = cname;
            return(aClass);
        }
예제 #19
0
        public void GetHashCodeIsSane()
        {
            // Compare hashcodes of two identical classes.
            ASClass class1 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" });
            ASClass class2 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" });

            Assert.AreEqual(class1.GetHashCode(), class2.GetHashCode());
        }
예제 #20
0
        public void Constructor(string className, ASClassLayout classLayout, string[] memberNames)
        {
            ASClass @class = new ASClass(className, classLayout, memberNames);

            Assert.AreSame(className, @class.ClassAlias);
            Assert.AreEqual(classLayout, @class.Layout);
            Assert.AreSame(memberNames, @class.MemberNames);
        }
예제 #21
0
        static string DumpHeaders(HGame game, bool isDumpingOutgoing)
        {
            IReadOnlyDictionary <ushort, ASClass> messageClasses =
                (isDumpingOutgoing ? game.OutgoingMessages : game.IncomingMessages);

            IOrderedEnumerable <KeyValuePair <string, List <ushort> > > organizedHeaders =
                GetOrganizedHeadersByHashCount(game, messageClasses);

            string headersDump       = string.Empty;
            string unusedHeadersDump = string.Empty;
            string messageType       = (isDumpingOutgoing ? "Outgoing" : "Incoming");
            var    unusedHeaders     = new List <KeyValuePair <string, List <ushort> > >();

            foreach (KeyValuePair <string, List <ushort> > organizedHeader in organizedHeaders)
            {
                if (organizedHeader.Value.Count == 1)
                {
                    if (isDumpingOutgoing)
                    {
                        UniqueOutMessageHashCount++;
                    }
                    else
                    {
                        UniqueInMessageHashCount++;
                    }
                }
                string messageHash = organizedHeader.Key;
                foreach (ushort header in organizedHeader.Value)
                {
                    ASClass  messageClass = messageClasses[header];
                    string   messageName  = messageClass.Instance.QualifiedName.Name;
                    ASMethod messageCtor  = messageClass.Instance.Constructor;

                    string dump = $"{messageType}[{header}, {messageHash}] = {messageName}{messageCtor}";
                    if (!isDumpingOutgoing)
                    {
                        ASClass inMsgParser = game.GetIncomingMessageParser(messageClass);
                        dump += ($", Parser: {inMsgParser.Instance.QualifiedName.Name}");
                    }
                    dump += "\r\n";
                    if (!game.IsMessageReferenced(messageClass))
                    {
                        unusedHeadersDump += ("[Dead]" + dump);
                    }
                    else
                    {
                        headersDump += dump;
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(unusedHeadersDump))
            {
                headersDump += unusedHeadersDump;
            }

            return(headersDump.Trim());
        }
예제 #22
0
파일: HGame.cs 프로젝트: makinit/Tanji
        /// <summary>
        /// Returns an enumerable containing references for the specified message class.
        /// </summary>
        /// <param name="messageClass">The message class being referenced.</param>
        /// <returns></returns>
        public IEnumerable <ASReference> GetMessageReferences(ASClass messageClass)
        {
            if (_messageReferences.ContainsKey(messageClass))
            {
                return(_messageReferences[messageClass]);
            }

            return(null);
        }
예제 #23
0
파일: HGame.cs 프로젝트: makinit/Tanji
        /// <summary>
        /// Returns a value that determines whether the specified message class is an Outgoing type message class.
        /// </summary>
        /// <param name="messageClass">The message class to check whether it is an Outoing message class type.</param>
        /// <returns></returns>
        public bool IsMessageOutgoing(ASClass messageClass)
        {
            if (_isMessageOutgoing.ContainsKey(messageClass))
            {
                return(_isMessageOutgoing[messageClass]);
            }

            return(false);
        }
예제 #24
0
 public string GetHash(ASClass asClass)
 {
     using (var hashStream = new MemoryStream())
         using (var hashInput = new BinaryWriter(hashStream))
         {
             WriteClassHashData(hashInput, asClass);
             return(GetHash(hashStream.ToArray()));
         }
 }
예제 #25
0
        private void LoadMessages()
        {
            ABCFile abc = ABCFiles.Last();
            ASClass habboMessagesClass = abc.GetClass("HabboMessages");

            if (habboMessagesClass == null)
            {
                IsPostShuffle = false;
                foreach (ASClass @class in abc.Classes)
                {
                    if (@class.Traits.Count != 2 || @class.Traits[0].Type?.Name != "Map" || @class.Traits[1].Type?.Name != "Map")
                    {
                        continue;
                    }
                    if (@class.Instance.Traits.Count != 2)
                    {
                        continue;
                    }

                    habboMessagesClass = @class;
                    break;
                }
                if (habboMessagesClass == null)
                {
                    return;
                }
            }

            ASCode code            = habboMessagesClass.Constructor.Body.ParseCode();
            int    outMapTypeIndex = habboMessagesClass.Traits[1].QNameIndex;

            ASInstruction[] instructions = code
                                           .Where(i => i.OP == OPCode.GetLex ||
                                                  i.OP == OPCode.PushShort ||
                                                  i.OP == OPCode.PushByte).ToArray();

            for (int i = 0; i < instructions.Length; i += 3)
            {
                GetLexIns getLexInst = instructions[i + 0] as GetLexIns;
                bool      isOutgoing = getLexInst?.TypeNameIndex == outMapTypeIndex;

                Primitive primitive = instructions[i + 1] as Primitive;
                ushort    id        = Convert.ToUInt16(primitive?.Value);

                getLexInst = instructions[i + 2] as GetLexIns;
                ASClass messageClass = abc.GetClass(getLexInst?.TypeName.Name);

                HMessage message = new HMessage(id, isOutgoing, messageClass);
                (isOutgoing ? OutMessages : InMessages).Add(id, message);

                if (!_messages.ContainsKey(messageClass))
                {
                    _messages.Add(messageClass, message);
                }
            }
        }
예제 #26
0
        public void GetClassCachesInstances()
        {
            ASClass @class = ASClassCache.GetClass("abc", ASClassLayout.Dynamic, EmptyArray <string> .Instance);

            Assert.AreEqual("abc", @class.ClassAlias);
            Assert.AreEqual(ASClassLayout.Dynamic, @class.Layout);
            Assert.AreEqual(0, @class.MemberNames.Count);
            Assert.IsTrue(@class.MemberNames.IsReadOnly);

            Assert.AreSame(@class, ASClassCache.GetClass("abc", ASClassLayout.Dynamic, EmptyArray <string> .Instance));
        }
예제 #27
0
 /// <summary>
 /// Resolve wildcards in imports
 /// </summary>
 /// <param name="package">Package to explore</param>
 /// <param name="inClass">Current class</param>
 /// <param name="known">Packages already added</param>
 public void ResolveImports(string package, ASClass inClass, ArrayList known)
 {
     if (!known.Contains(package))
     {
         known.Add(package);
         ASMember pMember = new ASMember();
         pMember.Name = package + "*";
         pMember.Type = package + "*";
         inClass.Imports.Add(pMember);
     }
 }
예제 #28
0
        /// <summary>
        /// Recursively convert classes
        /// </summary>
        /// <param name="path">folder to convert</param>
        static void ExploreFolder(string path)
        {
            currentFile = path;
            known.Add(path);

            // convert classes
            string[] files = Directory.GetFiles(path, "*.as");
            ASClass  fClass;
            string   destFile;
            DateTime timestamp;
            int      codepage;

            foreach (string file in files)
            {
                currentFile = file;
                destFile    = destPath + file.Substring(srcPath.Length);
                // not modified: ignore
                timestamp = File.GetLastWriteTime(file);
                if (File.Exists(destFile) && File.GetLastWriteTime(destFile) == timestamp)
                {
                    continue;
                }

                // parse class
                codepage        = GetFileCodepage(file);
                fClass          = new ASClass();
                fClass.FileName = file;
                ASClassParser.ParseClass(fClass);
                if (fClass.IsVoid())
                {
                    continue;
                }

                // create intrinsic
                Directory.CreateDirectory(Path.GetDirectoryName(destFile));
                Write(destFile, fClass.GenerateIntrinsic(), Encoding.GetEncoding(codepage));
                File.SetCreationTime(destFile, timestamp);
                File.SetLastWriteTime(destFile, timestamp);
                total++;
            }

            // explore subfolders
            currentFile = path;
            string[] dirs = Directory.GetDirectories(path);
            foreach (string dir in dirs)
            {
                if (!known.Contains(dir))
                {
                    ExploreFolder(dir);
                }
            }
        }
예제 #29
0
        public void Indexer()
        {
            ASClass  @class = new ASClass("class", ASClassLayout.Dynamic, new string[] { "member" });
            ASObject obj    = new ASObject(@class);

            obj["member"] = new ASInt29(1);
            Assert.AreEqual(new ASInt29(1), obj["member"]);
            Assert.AreEqual(new ASInt29(1), obj.MemberValues[0]);

            obj["nonmember"] = new ASInt29(2);
            Assert.AreEqual(new ASInt29(2), obj["nonmember"]);
            Assert.AreEqual(new ASInt29(2), obj.DynamicProperties["nonmember"]);
        }
예제 #30
0
        public void ConstructorWithClassAndMemberValues(ASClassLayout classLayout, string[] memberNames, int[] memberValues)
        {
            IASValue[] asMemberValues = WrapInts(memberValues);

            ASClass  @class = new ASClass("class", classLayout, memberNames);
            ASObject obj    = new ASObject(@class, asMemberValues);

            Assert.AreSame(@class, obj.Class);
            Assert.AreSame(asMemberValues, obj.MemberValues);
            Assert.AreEqual(0, obj.DynamicProperties.Count);

            Assert.AreEqual(classLayout == ASClassLayout.Normal, obj.DynamicProperties.IsReadOnly);
        }