Serialization.cpp 361 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "FileIOBaseTestTypes.h"
  9. #include <AzCore/Asset/AssetManager.h>
  10. #include <AzCore/Asset/AssetSerializer.h>
  11. #include <AzCore/Component/ComponentApplicationBus.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. #include <AzCore/Serialization/EditContext.h>
  14. #include <AzCore/Serialization/DataOverlayProviderMsgs.h>
  15. #include <AzCore/Serialization/DataOverlayInstanceMsgs.h>
  16. #include <AzCore/Serialization/DynamicSerializableField.h>
  17. #include <AzCore/Serialization/Utils.h>
  18. #include <AzCore/Serialization/ObjectStream.h>
  19. #include <AzCore/Serialization/DataPatch.h>
  20. #include <AzCore/std/containers/vector.h>
  21. #include <AzCore/std/containers/fixed_vector.h>
  22. #include <AzCore/std/containers/array.h>
  23. #include <AzCore/std/containers/list.h>
  24. #include <AzCore/std/containers/forward_list.h>
  25. #include <AzCore/std/containers/set.h>
  26. #include <AzCore/std/containers/unordered_set.h>
  27. #include <AzCore/std/containers/unordered_map.h>
  28. #include <AzCore/std/containers/bitset.h>
  29. #include <AzCore/std/containers/array.h>
  30. #include <AzCore/std/functional.h>
  31. #include <AzCore/std/smart_ptr/intrusive_ptr.h>
  32. #include <AzCore/std/smart_ptr/shared_ptr.h>
  33. #include <AzCore/std/smart_ptr/unique_ptr.h>
  34. #include <AzCore/std/smart_ptr/make_shared.h>
  35. #include <AzCore/std/optional.h>
  36. #include <AzCore/std/tuple.h>
  37. #include <AzCore/Component/ComponentApplication.h>
  38. #include <AzCore/Component/ComponentBus.h>
  39. #include <AzCore/Math/Crc.h>
  40. #include <AzCore/Math/Uuid.h>
  41. #include <AzCore/Math/Vector2.h>
  42. #include <AzCore/Math/Vector3.h>
  43. #include <AzCore/Math/Vector4.h>
  44. #include <AzCore/Math/Transform.h>
  45. #include <AzCore/Math/Matrix3x3.h>
  46. #include <AzCore/Math/Matrix4x4.h>
  47. #include <AzCore/Math/Quaternion.h>
  48. #include <AzCore/Math/Aabb.h>
  49. #include <AzCore/Math/Plane.h>
  50. #include <AzCore/IO/GenericStreams.h>
  51. #include <AzCore/IO/Streamer/Streamer.h>
  52. #include <AzCore/IO/SystemFile.h>
  53. #include <AzCore/IO/ByteContainerStream.h>
  54. #include <AzCore/IO/Streamer/StreamerComponent.h>
  55. #include <AzCore/RTTI/AttributeReader.h>
  56. #include <AzCore/std/string/conversions.h>
  57. #include <AzCore/UnitTest/TestTypes.h>
  58. #include <AZTestShared/Utils/Utils.h>
  59. #include <locale.h>
  60. namespace SerializeTestClasses {
  61. class MyClassBase1
  62. {
  63. public:
  64. AZ_RTTI(MyClassBase1, "{AA882C72-C7FB-4D19-A167-44BAF96C7D79}");
  65. static void Reflect(AZ::SerializeContext& sc)
  66. {
  67. sc.Class<MyClassBase1>()->
  68. Version(1)->
  69. Field("data", &MyClassBase1::m_data);
  70. }
  71. virtual ~MyClassBase1() {}
  72. virtual void Set(float v) = 0;
  73. float m_data{ 0.0f };
  74. };
  75. class MyClassBase2
  76. {
  77. public:
  78. AZ_RTTI(MyClassBase2, "{E2DE87D8-15FD-417B-B7E4-5BDF05EA7088}");
  79. static void Reflect(AZ::SerializeContext& sc)
  80. {
  81. sc.Class<MyClassBase2>()->
  82. Version(1)->
  83. Field("data", &MyClassBase2::m_data);
  84. }
  85. virtual ~MyClassBase2() {}
  86. virtual void Set(float v) = 0;
  87. float m_data{ 0.0f };
  88. };
  89. class MyClassBase3
  90. {
  91. public:
  92. AZ_RTTI(MyClassBase3, "{E9308B39-14B9-4760-A141-EBECFE8891D5}");
  93. // enum class EnumField : char // Test C++11
  94. enum EnumField
  95. {
  96. Option1,
  97. Option2,
  98. Option3,
  99. };
  100. static void Reflect(AZ::SerializeContext& sc)
  101. {
  102. sc.Class<MyClassBase3>()->
  103. Version(1)->
  104. Field("data", &MyClassBase3::m_data)->
  105. Field("enum", &MyClassBase3::m_enum);
  106. }
  107. virtual ~MyClassBase3() {}
  108. virtual void Set(float v) = 0;
  109. float m_data{ 0.f };
  110. EnumField m_enum{ Option1 };
  111. };
  112. class MyClassMix
  113. : public MyClassBase1
  114. , public MyClassBase2
  115. , public MyClassBase3
  116. {
  117. public:
  118. AZ_RTTI(MyClassMix, "{A15003C6-797A-41BB-9D21-716DF0678D02}", MyClassBase1, MyClassBase2, MyClassBase3);
  119. AZ_CLASS_ALLOCATOR(MyClassMix, AZ::SystemAllocator);
  120. static void Reflect(AZ::SerializeContext& sc)
  121. {
  122. sc.Class<MyClassMix, MyClassBase1, MyClassBase2, MyClassBase3>()->
  123. Field("dataMix", &MyClassMix::m_dataMix);
  124. }
  125. void Set(float v) override
  126. {
  127. m_dataMix = v;
  128. MyClassBase1::m_data = v * 2;
  129. MyClassBase2::m_data = v * 3;
  130. MyClassBase3::m_data = v * 4;
  131. }
  132. bool operator==(const MyClassMix& rhs) const
  133. {
  134. return m_dataMix == rhs.m_dataMix
  135. && MyClassBase1::m_data == rhs.MyClassBase1::m_data
  136. && MyClassBase2::m_data == rhs.MyClassBase2::m_data
  137. && MyClassBase3::m_data == rhs.MyClassBase3::m_data;
  138. }
  139. double m_dataMix{ 0. };
  140. };
  141. class MyClassMixNew
  142. : public MyClassBase1
  143. , public MyClassBase2
  144. , public MyClassBase3
  145. {
  146. public:
  147. AZ_RTTI(MyClassMixNew, "{A15003C6-797A-41BB-9D21-716DF0678D02}", MyClassBase1, MyClassBase2, MyClassBase3); // Use the same UUID as MyClassMix for conversion test
  148. AZ_CLASS_ALLOCATOR(MyClassMixNew, AZ::SystemAllocator);
  149. static bool ConvertOldVersions(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  150. {
  151. if (classElement.GetVersion() == 0)
  152. {
  153. // convert from version 0
  154. float sum = 0.f;
  155. for (int i = 0; i < classElement.GetNumSubElements(); )
  156. {
  157. AZ::SerializeContext::DataElementNode& elementNode = classElement.GetSubElement(i);
  158. if (elementNode.GetName() == AZ_CRC_CE("dataMix"))
  159. {
  160. classElement.RemoveElement(i);
  161. continue;
  162. }
  163. else
  164. {
  165. // go through our base classes adding their data members
  166. for (int j = 0; j < elementNode.GetNumSubElements(); ++j)
  167. {
  168. AZ::SerializeContext::DataElementNode& dataNode = elementNode.GetSubElement(j);
  169. if (dataNode.GetName() == AZ_CRC_CE("data"))
  170. {
  171. float data;
  172. bool result = dataNode.GetData(data);
  173. EXPECT_TRUE(result);
  174. sum += data;
  175. break;
  176. }
  177. }
  178. }
  179. ++i;
  180. }
  181. // add a new element
  182. int newElement = classElement.AddElement(context, "baseSum", AZ::SerializeTypeInfo<float>::GetUuid());
  183. if (newElement != -1)
  184. {
  185. classElement.GetSubElement(newElement).SetData(context, sum);
  186. }
  187. return true;
  188. }
  189. return false; // just discard unknown versions
  190. }
  191. static void Reflect(AZ::SerializeContext& sc)
  192. {
  193. sc.Class<MyClassMixNew, MyClassBase1, MyClassBase2, MyClassBase3>()->
  194. Version(1, &MyClassMixNew::ConvertOldVersions)->
  195. Field("baseSum", &MyClassMixNew::m_baseSum);
  196. }
  197. void Set(float v) override
  198. {
  199. MyClassBase1::m_data = v * 2;
  200. MyClassBase2::m_data = v * 3;
  201. MyClassBase3::m_data = v * 4;
  202. m_baseSum = v * 2 + v * 3 + v * 4;
  203. }
  204. bool operator==(const MyClassMixNew& rhs)
  205. {
  206. return m_baseSum == rhs.m_baseSum
  207. && MyClassBase1::m_data == rhs.MyClassBase1::m_data
  208. && MyClassBase2::m_data == rhs.MyClassBase2::m_data
  209. && MyClassBase3::m_data == rhs.MyClassBase3::m_data;
  210. }
  211. float m_baseSum;
  212. };
  213. class MyClassMix2
  214. : public MyClassBase2
  215. , public MyClassBase3
  216. , public MyClassBase1
  217. {
  218. public:
  219. AZ_RTTI(MyClassMix2, "{D402F58C-812C-4c20-ABE5-E4AF43D66A71}", MyClassBase2, MyClassBase3, MyClassBase1);
  220. AZ_CLASS_ALLOCATOR(MyClassMix2, AZ::SystemAllocator);
  221. static void Reflect(AZ::SerializeContext& sc)
  222. {
  223. sc.Class<MyClassMix2, MyClassBase2, MyClassBase3, MyClassBase1>()->
  224. Field("dataMix", &MyClassMix2::m_dataMix);
  225. }
  226. void Set(float v) override
  227. {
  228. m_dataMix = v;
  229. MyClassBase1::m_data = v * 2;
  230. MyClassBase2::m_data = v * 3;
  231. MyClassBase3::m_data = v * 4;
  232. }
  233. bool operator==(const MyClassMix2& rhs)
  234. {
  235. return m_dataMix == rhs.m_dataMix
  236. && MyClassBase1::m_data == rhs.MyClassBase1::m_data
  237. && MyClassBase2::m_data == rhs.MyClassBase2::m_data
  238. && MyClassBase3::m_data == rhs.MyClassBase3::m_data;
  239. }
  240. double m_dataMix;
  241. };
  242. class MyClassMix3
  243. : public MyClassBase3
  244. , public MyClassBase1
  245. , public MyClassBase2
  246. {
  247. public:
  248. AZ_RTTI(MyClassMix3, "{4179331A-F4AB-49D2-A14B-06B80CE5952C}", MyClassBase3, MyClassBase1, MyClassBase2);
  249. AZ_CLASS_ALLOCATOR(MyClassMix3, AZ::SystemAllocator);
  250. static void Reflect(AZ::SerializeContext& sc)
  251. {
  252. sc.Class<MyClassMix3, MyClassBase3, MyClassBase1, MyClassBase2>()->
  253. Field("dataMix", &MyClassMix3::m_dataMix);
  254. }
  255. void Set(float v) override
  256. {
  257. m_dataMix = v;
  258. MyClassBase1::m_data = v * 2;
  259. MyClassBase2::m_data = v * 3;
  260. MyClassBase3::m_data = v * 4;
  261. }
  262. bool operator==(const MyClassMix3& rhs)
  263. {
  264. return m_dataMix == rhs.m_dataMix
  265. && MyClassBase1::m_data == rhs.MyClassBase1::m_data
  266. && MyClassBase2::m_data == rhs.MyClassBase2::m_data
  267. && MyClassBase3::m_data == rhs.MyClassBase3::m_data;
  268. }
  269. double m_dataMix;
  270. };
  271. struct UnregisteredBaseClass
  272. {
  273. AZ_RTTI(UnregisteredBaseClass, "{19C26D43-4512-40D8-B5F5-1A69872252D4}");
  274. virtual ~UnregisteredBaseClass() {}
  275. virtual void Func() = 0;
  276. };
  277. struct ChildOfUndeclaredBase
  278. : public UnregisteredBaseClass
  279. {
  280. AZ_CLASS_ALLOCATOR(ChildOfUndeclaredBase, AZ::SystemAllocator);
  281. AZ_RTTI(ChildOfUndeclaredBase, "{85268A9C-1CC1-49C6-9E65-9B5089EBC4CD}", UnregisteredBaseClass);
  282. ChildOfUndeclaredBase()
  283. : m_data(0) {}
  284. static void Reflect(AZ::SerializeContext& sc)
  285. {
  286. sc.Class<ChildOfUndeclaredBase>()->
  287. Field("data", &ChildOfUndeclaredBase::m_data);
  288. }
  289. void Func() override {}
  290. int m_data;
  291. };
  292. struct PolymorphicMemberPointers
  293. {
  294. AZ_CLASS_ALLOCATOR(PolymorphicMemberPointers, AZ::SystemAllocator);
  295. AZ_TYPE_INFO(PolymorphicMemberPointers, "{06864A72-A2E2-40E1-A8F9-CC6C59BFBF2D}")
  296. static void Reflect(AZ::SerializeContext& sc)
  297. {
  298. sc.Class<PolymorphicMemberPointers>()->
  299. Field("base1Mix", &PolymorphicMemberPointers::m_pBase1MyClassMix)->
  300. Field("base1Mix2", &PolymorphicMemberPointers::m_pBase1MyClassMix2)->
  301. Field("base1Mix3", &PolymorphicMemberPointers::m_pBase1MyClassMix3)->
  302. Field("base2Mix", &PolymorphicMemberPointers::m_pBase2MyClassMix)->
  303. Field("base2Mix2", &PolymorphicMemberPointers::m_pBase2MyClassMix2)->
  304. Field("base2Mix3", &PolymorphicMemberPointers::m_pBase2MyClassMix3)->
  305. Field("base3Mix", &PolymorphicMemberPointers::m_pBase3MyClassMix)->
  306. Field("base3Mix2", &PolymorphicMemberPointers::m_pBase3MyClassMix2)->
  307. Field("base3Mix3", &PolymorphicMemberPointers::m_pBase3MyClassMix3)->
  308. Field("memberWithUndeclaredBase", &PolymorphicMemberPointers::m_pMemberWithUndeclaredBase);
  309. }
  310. PolymorphicMemberPointers()
  311. {
  312. m_pBase1MyClassMix = nullptr;
  313. m_pBase1MyClassMix2 = nullptr;
  314. m_pBase1MyClassMix3 = nullptr;
  315. m_pBase2MyClassMix = nullptr;
  316. m_pBase2MyClassMix2 = nullptr;
  317. m_pBase2MyClassMix3 = nullptr;
  318. m_pBase3MyClassMix = nullptr;
  319. m_pBase3MyClassMix2 = nullptr;
  320. m_pBase3MyClassMix3 = nullptr;
  321. m_pMemberWithUndeclaredBase = nullptr;
  322. }
  323. virtual ~PolymorphicMemberPointers()
  324. {
  325. if (m_pBase1MyClassMix)
  326. {
  327. Unset();
  328. }
  329. }
  330. void Set()
  331. {
  332. (m_pBase1MyClassMix = aznew MyClassMix)->Set(10.f);
  333. (m_pBase1MyClassMix2 = aznew MyClassMix2)->Set(20.f);
  334. (m_pBase1MyClassMix3 = aznew MyClassMix3)->Set(30.f);
  335. (m_pBase2MyClassMix = aznew MyClassMix)->Set(100.f);
  336. (m_pBase2MyClassMix2 = aznew MyClassMix2)->Set(200.f);
  337. (m_pBase2MyClassMix3 = aznew MyClassMix3)->Set(300.f);
  338. (m_pBase3MyClassMix = aznew MyClassMix)->Set(1000.f);
  339. (m_pBase3MyClassMix2 = aznew MyClassMix2)->Set(2000.f);
  340. (m_pBase3MyClassMix3 = aznew MyClassMix3)->Set(3000.f);
  341. (m_pMemberWithUndeclaredBase = aznew ChildOfUndeclaredBase)->m_data = 1234;
  342. }
  343. void Unset()
  344. {
  345. delete m_pBase1MyClassMix; m_pBase1MyClassMix = nullptr;
  346. delete m_pBase1MyClassMix2;
  347. delete m_pBase1MyClassMix3;
  348. delete m_pBase2MyClassMix;
  349. delete m_pBase2MyClassMix2;
  350. delete m_pBase2MyClassMix3;
  351. delete m_pBase3MyClassMix;
  352. delete m_pBase3MyClassMix2;
  353. delete m_pBase3MyClassMix3;
  354. delete m_pMemberWithUndeclaredBase;
  355. }
  356. MyClassBase1* m_pBase1MyClassMix;
  357. MyClassBase1* m_pBase1MyClassMix2;
  358. MyClassBase1* m_pBase1MyClassMix3;
  359. MyClassBase2* m_pBase2MyClassMix;
  360. MyClassBase2* m_pBase2MyClassMix2;
  361. MyClassBase2* m_pBase2MyClassMix3;
  362. MyClassBase2* m_pBase3MyClassMix;
  363. MyClassBase2* m_pBase3MyClassMix2;
  364. MyClassBase2* m_pBase3MyClassMix3;
  365. ChildOfUndeclaredBase* m_pMemberWithUndeclaredBase;
  366. };
  367. struct BaseNoRtti
  368. {
  369. AZ_CLASS_ALLOCATOR(BaseNoRtti, AZ::SystemAllocator);
  370. AZ_TYPE_INFO(BaseNoRtti, "{E57A19BA-EF68-4AFF-A534-2C90B9583781}")
  371. static void Reflect(AZ::SerializeContext& sc)
  372. {
  373. sc.Class<BaseNoRtti>()->
  374. Field("data", &BaseNoRtti::m_data);
  375. }
  376. void Set() { m_data = false; }
  377. bool operator==(const BaseNoRtti& rhs) const { return m_data == rhs.m_data; }
  378. bool m_data;
  379. };
  380. struct BaseRtti
  381. {
  382. AZ_RTTI(BaseRtti, "{2581047D-26EC-4969-8354-BA0A4510C51A}");
  383. AZ_CLASS_ALLOCATOR(BaseRtti, AZ::SystemAllocator);
  384. static void Reflect(AZ::SerializeContext& sc)
  385. {
  386. sc.Class<BaseRtti>()->
  387. Field("data", &BaseRtti::m_data);
  388. }
  389. virtual ~BaseRtti() {}
  390. void Set() { m_data = true; }
  391. bool operator==(const BaseRtti& rhs) const { return m_data == rhs.m_data; }
  392. bool m_data;
  393. };
  394. struct DerivedNoRtti
  395. : public BaseNoRtti
  396. {
  397. AZ_CLASS_ALLOCATOR(DerivedNoRtti, AZ::SystemAllocator);
  398. AZ_TYPE_INFO(DerivedNoRtti, "{B5E77A22-9C6F-4755-A074-FEFD8AC2C971}")
  399. static void Reflect(AZ::SerializeContext& sc)
  400. {
  401. sc.Class<DerivedNoRtti, BaseNoRtti>()->
  402. Field("basesRtti", &DerivedNoRtti::m_basesRtti)->
  403. Field("basesNoRtti", &DerivedNoRtti::m_basesNoRtti);
  404. }
  405. void Set() { m_basesRtti = 0; m_basesNoRtti = 1; BaseNoRtti::Set(); }
  406. bool operator==(const DerivedNoRtti& rhs) const { return m_basesRtti == rhs.m_basesRtti && m_basesNoRtti == rhs.m_basesNoRtti && BaseNoRtti::operator==(static_cast<const BaseNoRtti&>(rhs)); }
  407. int m_basesRtti;
  408. int m_basesNoRtti;
  409. };
  410. struct DerivedRtti
  411. : public BaseRtti
  412. {
  413. AZ_RTTI(DerivedRtti, "{A14C419C-6F25-46A6-8D17-7777893073EF}", BaseRtti);
  414. AZ_CLASS_ALLOCATOR(DerivedRtti, AZ::SystemAllocator);
  415. static void Reflect(AZ::SerializeContext& sc)
  416. {
  417. sc.Class<DerivedRtti, BaseRtti>()->
  418. Field("basesRtti", &DerivedRtti::m_basesRtti)->
  419. Field("basesNoRtti", &DerivedRtti::m_basesNoRtti);
  420. }
  421. void Set() { m_basesRtti = 1; m_basesNoRtti = 0; BaseRtti::Set(); }
  422. bool operator==(const DerivedRtti& rhs) const { return m_basesRtti == rhs.m_basesRtti && m_basesNoRtti == rhs.m_basesNoRtti && BaseRtti::operator==(static_cast<const BaseRtti&>(rhs)); }
  423. int m_basesRtti;
  424. int m_basesNoRtti;
  425. };
  426. struct DerivedMix
  427. : public BaseNoRtti
  428. , public BaseRtti
  429. {
  430. AZ_RTTI(DerivedMix, "{BED5293B-3B80-4CEC-BB0F-2E56F921F550}", BaseRtti);
  431. AZ_CLASS_ALLOCATOR(DerivedMix, AZ::SystemAllocator);
  432. static void Reflect(AZ::SerializeContext& sc)
  433. {
  434. sc.Class<DerivedMix, BaseNoRtti, BaseRtti>()->
  435. Field("basesRtti", &DerivedMix::m_basesRtti)->
  436. Field("basesNoRtti", &DerivedMix::m_basesNoRtti);
  437. }
  438. void Set() { m_basesRtti = 1; m_basesNoRtti = 1; BaseNoRtti::Set(); BaseRtti::Set(); }
  439. bool operator==(const DerivedMix& rhs) const { return m_basesRtti == rhs.m_basesRtti && m_basesNoRtti == rhs.m_basesNoRtti && BaseNoRtti::operator==(static_cast<const BaseNoRtti&>(rhs)) && BaseRtti::operator==(static_cast<const BaseRtti&>(rhs)); }
  440. int m_basesRtti;
  441. int m_basesNoRtti;
  442. };
  443. struct BaseProtected
  444. {
  445. AZ_TYPE_INFO(BaseProtected, "{c6e244d8-ffd8-4710-900b-1d3dc4043ffe}");
  446. int m_pad; // Make sure there is no offset assumptions, for base members and we offset properly with in the base class.
  447. int m_data;
  448. protected:
  449. BaseProtected(int data = 0)
  450. : m_data(data) {}
  451. };
  452. struct DerivedWithProtectedBase
  453. : public BaseProtected
  454. {
  455. AZ_TYPE_INFO(DerivedWithProtectedBase, "{ad736023-a491-440a-84e3-5c507c969673}");
  456. AZ_CLASS_ALLOCATOR(DerivedWithProtectedBase, AZ::SystemAllocator);
  457. DerivedWithProtectedBase(int data = 0)
  458. : BaseProtected(data)
  459. {}
  460. static void Reflect(AZ::SerializeContext& context)
  461. {
  462. // Expose base class field without reflecting the class
  463. context.Class<DerivedWithProtectedBase>()
  464. ->FieldFromBase<DerivedWithProtectedBase>("m_data", &DerivedWithProtectedBase::m_data);
  465. }
  466. };
  467. struct SmartPtrClass
  468. {
  469. AZ_CLASS_ALLOCATOR(SmartPtrClass, AZ::SystemAllocator);
  470. AZ_TYPE_INFO(SmartPtrClass, "{A0A2D0A8-8D5D-454D-BE92-684C92C05B06}")
  471. SmartPtrClass(int data = 0)
  472. : m_counter(0)
  473. , m_data(data) {}
  474. static void Reflect(AZ::SerializeContext& sc)
  475. {
  476. sc.Class<SmartPtrClass>()->
  477. Field("data", &SmartPtrClass::m_data);
  478. }
  479. //////////////////////////////////////////////////////////////////////////
  480. // For intrusive pointers
  481. void add_ref() { ++m_counter; }
  482. void release()
  483. {
  484. --m_counter;
  485. if (m_counter == 0)
  486. {
  487. delete this;
  488. }
  489. }
  490. int m_counter;
  491. //////////////////////////////////////////////////////////////////////////
  492. int m_data;
  493. };
  494. struct Generics
  495. {
  496. AZ_CLASS_ALLOCATOR(Generics, AZ::SystemAllocator);
  497. AZ_TYPE_INFO(Generics, "{ACA50B82-D04B-4ACF-9FF6-F780040C9EB9}")
  498. enum class GenericEnum
  499. {
  500. Value1 = 0x01,
  501. Value2 = 0x02,
  502. Value3 = 0x04,
  503. };
  504. static void Reflect(AZ::SerializeContext& sc)
  505. {
  506. sc.Class<Generics>()->
  507. Field("emptyTextData", &Generics::m_emptyTextData)->
  508. Field("textData", &Generics::m_textData)->
  509. Field("vectorInt", &Generics::m_vectorInt)->
  510. Field("vectorIntVector", &Generics::m_vectorIntVector)->
  511. Field("vectorEnum", &Generics::m_vectorEnum)->
  512. Field("fixedVectorInt", &Generics::m_fixedVectorInt)->
  513. Field("listInt", &Generics::m_listInt)->
  514. Field("forwardListInt", &Generics::m_forwardListInt)->
  515. Field("setInt", &Generics::m_setInt)->
  516. Field("usetInt", &Generics::m_usetInt)->
  517. Field("umultisetInt", &Generics::m_umultisetInt)->
  518. Field("mapIntFloat", &Generics::m_mapIntFloat)->
  519. Field("umapIntFloat", &Generics::m_umapIntFloat)->
  520. Field("umultimapIntFloat", &Generics::m_umultimapIntFloat)->
  521. Field("umapPolymorphic", &Generics::m_umapPolymorphic)->
  522. Field("byteStream", &Generics::m_byteStream)->
  523. Field("bitSet", &Generics::m_bitSet)->
  524. Field("sharedPtr", &Generics::m_sharedPtr)->
  525. Field("intrusivePtr", &Generics::m_intrusivePtr)->
  526. Field("uniquePtr", &Generics::m_uniquePtr)->
  527. Field("emptyInitTextData", &Generics::m_emptyInitTextData);
  528. }
  529. Generics()
  530. {
  531. m_emptyInitTextData = "Some init text";
  532. }
  533. ~Generics()
  534. {
  535. if (m_umapPolymorphic.size() > 0)
  536. {
  537. Unset();
  538. }
  539. }
  540. public:
  541. void Set()
  542. {
  543. m_emptyInitTextData = ""; // data was initialized, we set it to nothing (make sure we write empty strings)
  544. m_textData = "Random Text";
  545. m_vectorInt.push_back(1);
  546. m_vectorInt.push_back(2);
  547. m_vectorIntVector.emplace_back();
  548. m_vectorIntVector.back().push_back(5);
  549. m_vectorEnum.push_back(GenericEnum::Value3);
  550. m_vectorEnum.push_back(GenericEnum::Value1);
  551. m_vectorEnum.push_back(GenericEnum::Value3);
  552. m_vectorEnum.push_back(GenericEnum::Value2);
  553. m_fixedVectorInt.push_back(1000);
  554. m_fixedVectorInt.push_back(2000);
  555. m_fixedVectorInt.push_back(3000);
  556. m_fixedVectorInt.push_back(4000);
  557. m_fixedVectorInt.push_back(5000);
  558. m_listInt.push_back(10);
  559. m_forwardListInt.push_front(15);
  560. m_setInt.insert(20);
  561. m_usetInt.insert(20);
  562. m_umultisetInt.insert(20);
  563. m_umultisetInt.insert(20);
  564. m_mapIntFloat.insert(AZStd::make_pair(1, 5.f));
  565. m_mapIntFloat.insert(AZStd::make_pair(2, 10.f));
  566. m_umapIntFloat.insert(AZStd::make_pair(1, 5.f));
  567. m_umapIntFloat.insert(AZStd::make_pair(2, 10.f));
  568. m_umultimapIntFloat.insert(AZStd::make_pair(1, 5.f));
  569. m_umultimapIntFloat.insert(AZStd::make_pair(2, 10.f));
  570. m_umultimapIntFloat.insert(AZStd::make_pair(2, 20.f));
  571. m_umapPolymorphic.insert(AZStd::make_pair(1, aznew MyClassMix)).first->second->Set(100.f);
  572. m_umapPolymorphic.insert(AZStd::make_pair(2, aznew MyClassMix2)).first->second->Set(200.f);
  573. m_umapPolymorphic.insert(AZStd::make_pair(3, aznew MyClassMix3)).first->second->Set(300.f);
  574. AZ::u32 binaryData = 0xbad0f00d;
  575. m_byteStream.assign((AZ::u8*)&binaryData, (AZ::u8*)(&binaryData + 1));
  576. m_bitSet = AZStd::bitset<32>(AZStd::string("01011"));
  577. m_sharedPtr = AZStd::shared_ptr<SmartPtrClass>(aznew SmartPtrClass(122));
  578. m_intrusivePtr = AZStd::intrusive_ptr<SmartPtrClass>(aznew SmartPtrClass(233));
  579. m_uniquePtr = AZStd::unique_ptr<SmartPtrClass>(aznew SmartPtrClass(4242));
  580. }
  581. void Unset()
  582. {
  583. m_emptyTextData.set_capacity(0);
  584. m_emptyInitTextData.set_capacity(0);
  585. m_textData.set_capacity(0);
  586. m_vectorInt.set_capacity(0);
  587. m_vectorIntVector.set_capacity(0);
  588. m_vectorEnum.set_capacity(0);
  589. m_listInt.clear();
  590. m_forwardListInt.clear();
  591. m_setInt.clear();
  592. m_mapIntFloat.clear();
  593. for (AZStd::unordered_map<int, MyClassBase1*>::iterator it = m_umapPolymorphic.begin(); it != m_umapPolymorphic.end(); ++it)
  594. {
  595. delete it->second;
  596. }
  597. m_umapPolymorphic.clear();
  598. m_byteStream.set_capacity(0);
  599. m_bitSet.reset();
  600. m_sharedPtr.reset();
  601. m_intrusivePtr.reset();
  602. m_uniquePtr.reset();
  603. }
  604. AZStd::string m_emptyTextData;
  605. AZStd::string m_emptyInitTextData;
  606. AZStd::string m_textData;
  607. AZStd::vector<int> m_vectorInt;
  608. AZStd::vector<AZStd::vector<int> > m_vectorIntVector;
  609. AZStd::vector<GenericEnum> m_vectorEnum;
  610. AZStd::fixed_vector<int, 5> m_fixedVectorInt;
  611. AZStd::list<int> m_listInt;
  612. AZStd::forward_list<int> m_forwardListInt;
  613. AZStd::set<int> m_setInt;
  614. AZStd::map<int, float> m_mapIntFloat;
  615. AZStd::unordered_set<int> m_usetInt;
  616. AZStd::unordered_multiset<int> m_umultisetInt;
  617. AZStd::unordered_map<int, float> m_umapIntFloat;
  618. AZStd::unordered_map<int, MyClassBase1*> m_umapPolymorphic;
  619. AZStd::unordered_multimap<int, float> m_umultimapIntFloat;
  620. AZStd::vector<AZ::u8> m_byteStream;
  621. AZStd::bitset<32> m_bitSet;
  622. AZStd::shared_ptr<SmartPtrClass> m_sharedPtr;
  623. AZStd::intrusive_ptr<SmartPtrClass> m_intrusivePtr;
  624. AZStd::unique_ptr<SmartPtrClass> m_uniquePtr;
  625. };
  626. struct ElementOverrideType
  627. {
  628. AZ_RTTI(ElementOverrideType, "{BAA18B6C-3CB3-476C-8B41-21EA7CE1F4CF}");
  629. AZ_CLASS_ALLOCATOR(ElementOverrideType, AZ::SystemAllocator);
  630. virtual ~ElementOverrideType() = default;
  631. static AZ::ObjectStreamWriteOverrideResponse Writer(
  632. AZ::SerializeContext::EnumerateInstanceCallContext& callContext,
  633. const void* object,
  634. const AZ::SerializeContext::ClassData&,
  635. const AZ::SerializeContext::ClassElement*)
  636. {
  637. auto ptr = static_cast<const ElementOverrideType*>(object);
  638. if(ptr)
  639. {
  640. switch(ptr->m_field)
  641. {
  642. case 0:
  643. {
  644. float output{};
  645. callContext.m_context->EnumerateInstanceConst(&callContext, &output, azrtti_typeid<decltype(output)>(), nullptr, nullptr);
  646. return AZ::ObjectStreamWriteOverrideResponse::CompletedWrite;
  647. }
  648. case 1:
  649. return AZ::ObjectStreamWriteOverrideResponse::FallbackToDefaultWrite;
  650. }
  651. }
  652. return AZ::ObjectStreamWriteOverrideResponse::AbortWrite;
  653. }
  654. static void Reflect(AZ::SerializeContext& sc)
  655. {
  656. sc.Class<ElementOverrideType>()
  657. ->Attribute(AZ::SerializeContextAttributes::ObjectStreamWriteElementOverride, &ElementOverrideType::Writer)
  658. ->Field("field", &ElementOverrideType::m_field);
  659. }
  660. int m_field = 0;
  661. };
  662. } //SerializeTestClasses
  663. namespace AZ
  664. {
  665. AZ_TYPE_INFO_SPECIALIZE(SerializeTestClasses::Generics::GenericEnum, "{1D382230-EF25-4583-812B-7576334AB1A9}");
  666. }
  667. namespace SerializeTestClasses
  668. {
  669. struct GenericsNew
  670. {
  671. AZ_CLASS_ALLOCATOR(GenericsNew, AZ::SystemAllocator);
  672. AZ_TYPE_INFO(GenericsNew, "{ACA50B82-D04B-4ACF-9FF6-F780040C9EB9}") // Match Generics ID for conversion test
  673. static bool ConvertOldVersions(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  674. {
  675. if (classElement.GetVersion() == 0)
  676. {
  677. // convert from version 0
  678. for (int i = 0; i < classElement.GetNumSubElements(); )
  679. {
  680. AZ::SerializeContext::DataElementNode& elementNode = classElement.GetSubElement(i);
  681. if (elementNode.GetName() == AZ_CRC_CE("textData"))
  682. {
  683. AZStd::string text;
  684. bool result = elementNode.GetData(text);
  685. EXPECT_TRUE(result);
  686. int memberIdx = classElement.AddElement<AZStd::string>(context, "string");
  687. if (memberIdx != -1)
  688. {
  689. AZ::SerializeContext::DataElementNode& memberNode = classElement.GetSubElement(memberIdx);
  690. memberNode.SetData(context, text);
  691. }
  692. classElement.RemoveElement(i);
  693. }
  694. else if (elementNode.GetName() == AZ_CRC_CE("emptyTextData"))
  695. {
  696. AZStd::string text;
  697. bool result = elementNode.GetData(text);
  698. EXPECT_TRUE(result);
  699. EXPECT_TRUE(text.empty()); // this should be empty
  700. classElement.RemoveElement(i);
  701. }
  702. else if (elementNode.GetName() == AZ_CRC_CE("vectorInt"))
  703. {
  704. int memberIdx = classElement.AddElement<AZStd::vector<int> >(context, "vectorInt2");
  705. if (memberIdx != -1)
  706. {
  707. AZ::SerializeContext::DataElementNode& memberNode = classElement.GetSubElement(memberIdx);
  708. for (int j = 0; j < elementNode.GetNumSubElements(); ++j)
  709. {
  710. AZ::SerializeContext::DataElementNode& vecElemNode = elementNode.GetSubElement(j);
  711. int val;
  712. bool result = vecElemNode.GetData(val);
  713. EXPECT_TRUE(result);
  714. int elemIdx = memberNode.AddElement<int>(context, AZ::SerializeContext::IDataContainer::GetDefaultElementName());
  715. if (elemIdx != -1)
  716. {
  717. memberNode.GetSubElement(elemIdx).SetData(context, val * 2);
  718. }
  719. }
  720. }
  721. classElement.RemoveElement(i);
  722. }
  723. else if (elementNode.GetName() == AZ_CRC_CE("vectorIntVector"))
  724. {
  725. // add a new element
  726. int newListIntList = classElement.AddElement<AZStd::list<AZStd::list<int> > >(context, "listIntList");
  727. if (newListIntList != -1)
  728. {
  729. AZ::SerializeContext::DataElementNode& listIntListNode = classElement.GetSubElement(newListIntList);
  730. for (int j = 0; j < elementNode.GetNumSubElements(); ++j)
  731. {
  732. AZ::SerializeContext::DataElementNode& subVecNode = elementNode.GetSubElement(j);
  733. int newListInt = listIntListNode.AddElement<AZStd::list<int> >(context, AZ::SerializeContext::IDataContainer::GetDefaultElementName());
  734. if (newListInt != -1)
  735. {
  736. AZ::SerializeContext::DataElementNode& listIntNode = listIntListNode.GetSubElement(newListInt);
  737. for (int k = 0; k < subVecNode.GetNumSubElements(); ++k)
  738. {
  739. AZ::SerializeContext::DataElementNode& intNode = subVecNode.GetSubElement(k);
  740. int val;
  741. bool result = intNode.GetData(val);
  742. EXPECT_TRUE(result);
  743. int newInt = listIntNode.AddElement<int>(context, AZ::SerializeContext::IDataContainer::GetDefaultElementName());
  744. if (newInt != -1)
  745. {
  746. listIntNode.GetSubElement(newInt).SetData(context, val);
  747. }
  748. }
  749. }
  750. }
  751. }
  752. classElement.RemoveElement(i);
  753. }
  754. else if (elementNode.GetName() == AZ_CRC_CE("emptyInitTextData")
  755. || elementNode.GetName() == AZ_CRC_CE("listInt")
  756. || elementNode.GetName() == AZ_CRC_CE("setInt")
  757. || elementNode.GetName() == AZ_CRC_CE("usetInt")
  758. || elementNode.GetName() == AZ_CRC_CE("umultisetInt")
  759. || elementNode.GetName() == AZ_CRC_CE("mapIntFloat")
  760. || elementNode.GetName() == AZ_CRC_CE("umapIntFloat")
  761. || elementNode.GetName() == AZ_CRC_CE("umultimapIntFloat")
  762. || elementNode.GetName() == AZ_CRC_CE("byteStream")
  763. || elementNode.GetName() == AZ_CRC_CE("bitSet")
  764. || elementNode.GetName() == AZ_CRC_CE("sharedPtr")
  765. || elementNode.GetName() == AZ_CRC_CE("intrusivePtr")
  766. || elementNode.GetName() == AZ_CRC_CE("uniquePtr")
  767. || elementNode.GetName() == AZ_CRC_CE("forwardListInt")
  768. || elementNode.GetName() == AZ_CRC_CE("fixedVectorInt")
  769. || elementNode.GetName() == AZ_CRC_CE("vectorEnum"))
  770. {
  771. classElement.RemoveElement(i);
  772. }
  773. else
  774. {
  775. ++i;
  776. }
  777. }
  778. // add a new element
  779. int newElement = classElement.AddElement(context, "newInt", AZ::SerializeTypeInfo<int>::GetUuid());
  780. if (newElement != -1)
  781. {
  782. classElement.GetSubElement(newElement).SetData(context, 50);
  783. }
  784. return true;
  785. }
  786. return false; // just discard unknown versions
  787. }
  788. static void Reflect(AZ::SerializeContext& sc)
  789. {
  790. sc.Class<GenericsNew>()->
  791. Version(1, &GenericsNew::ConvertOldVersions)->
  792. Field("string", &GenericsNew::m_string)->
  793. Field("vectorInt2", &GenericsNew::m_vectorInt2)->
  794. Field("listIntList", &GenericsNew::m_listIntList)->
  795. Field("umapPolymorphic", &GenericsNew::m_umapPolymorphic)->
  796. Field("newInt", &GenericsNew::m_newInt);
  797. }
  798. ~GenericsNew()
  799. {
  800. if (m_umapPolymorphic.size() > 0)
  801. {
  802. Unset();
  803. }
  804. }
  805. void Set()
  806. {
  807. m_string = "Random Text";
  808. m_vectorInt2.push_back(1 * 2);
  809. m_vectorInt2.push_back(2 * 2);
  810. m_listIntList.emplace_back();
  811. m_listIntList.back().push_back(5);
  812. m_umapPolymorphic.insert(AZStd::make_pair(1, aznew MyClassMixNew)).first->second->Set(100.f);
  813. m_umapPolymorphic.insert(AZStd::make_pair(2, aznew MyClassMix2)).first->second->Set(200.f);
  814. m_umapPolymorphic.insert(AZStd::make_pair(3, aznew MyClassMix3)).first->second->Set(300.f);
  815. m_newInt = 50;
  816. }
  817. void Unset()
  818. {
  819. m_string.set_capacity(0);
  820. m_vectorInt2.set_capacity(0);
  821. m_listIntList.clear();
  822. for (AZStd::unordered_map<int, MyClassBase1*>::iterator it = m_umapPolymorphic.begin(); it != m_umapPolymorphic.end(); ++it)
  823. {
  824. delete it->second;
  825. }
  826. m_umapPolymorphic.clear();
  827. }
  828. AZStd::string m_string; // rename m_textData to m_string
  829. AZStd::vector<int> m_vectorInt2; // rename m_vectorInt to m_vectorInt2 and multiply all values by 2
  830. AZStd::list<AZStd::list<int> > m_listIntList; // convert vector<vector<int>> to list<list<int>>
  831. AZStd::unordered_map<int, MyClassBase1*> m_umapPolymorphic; // using new version of MyClassMix
  832. int m_newInt; // added new member
  833. };
  834. class ClassThatAllocatesMemoryInDefaultCtor final
  835. {
  836. public:
  837. AZ_RTTI(ClassThatAllocatesMemoryInDefaultCtor, "{CF9B593D-A19E-467B-8370-28AF68D2F345}")
  838. AZ_CLASS_ALLOCATOR(ClassThatAllocatesMemoryInDefaultCtor, AZ::SystemAllocator)
  839. ClassThatAllocatesMemoryInDefaultCtor()
  840. : m_data(aznew InstanceTracker)
  841. {
  842. }
  843. ~ClassThatAllocatesMemoryInDefaultCtor()
  844. {
  845. delete m_data;
  846. }
  847. static void Reflect(AZ::SerializeContext& sc)
  848. {
  849. sc.Class<InstanceTracker>();
  850. sc.Class<ClassThatAllocatesMemoryInDefaultCtor>()->
  851. Field("data", &ClassThatAllocatesMemoryInDefaultCtor::m_data)
  852. ;
  853. }
  854. class InstanceTracker final
  855. {
  856. public:
  857. AZ_RTTI(InstanceTracker, "{DED6003B-11E0-454C-B170-4889697815A0}");
  858. AZ_CLASS_ALLOCATOR(InstanceTracker, AZ::SystemAllocator);
  859. InstanceTracker()
  860. {
  861. ++s_instanceCount;
  862. }
  863. ~InstanceTracker()
  864. {
  865. --s_instanceCount;
  866. }
  867. InstanceTracker(const InstanceTracker&) = delete;
  868. InstanceTracker(InstanceTracker&&) = delete;
  869. static AZStd::atomic_int s_instanceCount;
  870. };
  871. private:
  872. const InstanceTracker* m_data;
  873. };
  874. AZStd::atomic_int ClassThatAllocatesMemoryInDefaultCtor::InstanceTracker::s_instanceCount(0);
  875. } // namespace SerializeTestClasses
  876. namespace ContainerElementDeprecationTestData
  877. {
  878. using namespace AZ;
  879. // utility classes for testing what happens to container elements, when they are deprecated.
  880. class BaseClass
  881. {
  882. public:
  883. AZ_RTTI(BaseClass, "{B736AD73-E627-467D-A779-7B942D2B5359}");
  884. AZ_CLASS_ALLOCATOR(BaseClass, SystemAllocator);
  885. virtual ~BaseClass() {}
  886. static void Reflect(ReflectContext* context)
  887. {
  888. if (auto serializeContext = azrtti_cast<SerializeContext*>(context))
  889. {
  890. serializeContext->Class<BaseClass>();
  891. }
  892. }
  893. };
  894. class DerivedClass1 : public BaseClass
  895. {
  896. public:
  897. AZ_RTTI(DerivedClass1, "{E55D26B8-96B9-4918-94F0-5ABCA29F2508}", BaseClass);
  898. AZ_CLASS_ALLOCATOR(DerivedClass1, SystemAllocator);
  899. static void Reflect(ReflectContext* context)
  900. {
  901. if (auto serializeContext = azrtti_cast<SerializeContext*>(context))
  902. {
  903. serializeContext->Class<DerivedClass1, BaseClass>();
  904. }
  905. }
  906. };
  907. class DerivedClass2 : public BaseClass
  908. {
  909. public:
  910. AZ_RTTI(DerivedClass2, "{91F6C9A1-1EB1-477E-99FC-41A35FE9CF0B}", BaseClass);
  911. AZ_CLASS_ALLOCATOR(DerivedClass2, SystemAllocator);
  912. static void Reflect(ReflectContext* context)
  913. {
  914. if (auto serializeContext = azrtti_cast<SerializeContext*>(context))
  915. {
  916. serializeContext->Class<DerivedClass2, BaseClass>();
  917. }
  918. }
  919. };
  920. class DerivedClass3 : public BaseClass
  921. {
  922. public:
  923. AZ_RTTI(DerivedClass3, "{1399CC2D-D525-4061-B190-5FCD82FCC161}", BaseClass);
  924. AZ_CLASS_ALLOCATOR(DerivedClass3, AZ::SystemAllocator);
  925. static void Reflect(ReflectContext* context)
  926. {
  927. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  928. {
  929. serializeContext->Class<DerivedClass3, BaseClass>();
  930. }
  931. }
  932. };
  933. static bool ConvertDerivedClass2ToDerivedClass3(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  934. {
  935. classElement.Convert(context, AZ::AzTypeInfo<DerivedClass3>::Uuid());
  936. return true;
  937. }
  938. class ClassWithAVectorOfBaseClasses final
  939. {
  940. public:
  941. AZ_RTTI(ClassWithAVectorOfBaseClasses, "{B62A3327-8BEE-43BD-BA2C-32BAE9EE5455}");
  942. AZ_CLASS_ALLOCATOR(ClassWithAVectorOfBaseClasses, AZ::SystemAllocator);
  943. AZStd::vector<BaseClass*> m_vectorOfBaseClasses;
  944. ~ClassWithAVectorOfBaseClasses()
  945. {
  946. for (auto base : m_vectorOfBaseClasses)
  947. {
  948. delete base;
  949. }
  950. m_vectorOfBaseClasses = {};
  951. }
  952. static void Reflect(ReflectContext* context)
  953. {
  954. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  955. {
  956. BaseClass::Reflect(context);
  957. DerivedClass1::Reflect(context);
  958. DerivedClass2::Reflect(context);
  959. DerivedClass3::Reflect(context);
  960. serializeContext->Class<ClassWithAVectorOfBaseClasses>()
  961. ->Field("m_vectorOfBaseClasses", &ClassWithAVectorOfBaseClasses::m_vectorOfBaseClasses);
  962. }
  963. }
  964. };
  965. } // End of namespace ContainerElementDeprecationTestData
  966. namespace AZ {
  967. struct GenericClass
  968. {
  969. AZ_RTTI(GenericClass, "{F2DAA5D8-CA20-4DD4-8942-356458AF23A1}");
  970. virtual ~GenericClass() {}
  971. };
  972. class NullFactory
  973. : public SerializeContext::IObjectFactory
  974. {
  975. public:
  976. void* Create(const char* name) override
  977. {
  978. (void)name;
  979. AZ_Assert(false, "We cannot 'new' %s class, it should be used by value in a parent class!", name);
  980. return nullptr;
  981. }
  982. void Destroy(void*) override
  983. {
  984. // do nothing...
  985. }
  986. };
  987. template<>
  988. struct SerializeGenericTypeInfo<GenericClass>
  989. {
  990. class GenericClassGenericInfo
  991. : public GenericClassInfo
  992. {
  993. public:
  994. AZ_TYPE_INFO(GenericClassGenericInfo, "{7A26F864-DADC-4bdf-8C4C-A162349031C6}");
  995. GenericClassGenericInfo()
  996. : m_classData{ SerializeContext::ClassData::Create<GenericClass>("GenericClass", GetSpecializedTypeId(), &m_factory) }
  997. {
  998. }
  999. SerializeContext::ClassData* GetClassData() override
  1000. {
  1001. return &m_classData;
  1002. }
  1003. size_t GetNumTemplatedArguments() override
  1004. {
  1005. return 1;
  1006. }
  1007. AZ::TypeId GetTemplatedTypeId(size_t element) override
  1008. {
  1009. (void)element;
  1010. return SerializeGenericTypeInfo<GenericClass>::GetClassTypeId();
  1011. }
  1012. AZ::TypeId GetSpecializedTypeId() const override
  1013. {
  1014. return azrtti_typeid<GenericClass>();
  1015. }
  1016. AZ::TypeId GetGenericTypeId() const override
  1017. {
  1018. return TYPEINFO_Uuid();
  1019. }
  1020. void Reflect(SerializeContext*) override {}
  1021. NullFactory m_factory;
  1022. SerializeContext::ClassData m_classData;
  1023. };
  1024. using ClassInfoType = GenericClassGenericInfo;
  1025. static ClassInfoType* GetGenericInfo()
  1026. {
  1027. return static_cast<ClassInfoType*>(GetGlobalSerializeContextModule().CreateGenericClassInfo<GenericClass>());
  1028. }
  1029. static AZ::TypeId GetClassTypeId()
  1030. {
  1031. return GetGenericInfo()->GetClassData()->m_typeId;
  1032. }
  1033. };
  1034. struct GenericChild
  1035. : public GenericClass
  1036. {
  1037. AZ_RTTI(GenericChild, "{086E933D-F3F9-41EA-9AA9-BA80D3DCF90A}", GenericClass);
  1038. ~GenericChild() override {}
  1039. };
  1040. template<>
  1041. struct SerializeGenericTypeInfo<GenericChild>
  1042. {
  1043. class GenericClassGenericInfo
  1044. : public GenericClassInfo
  1045. {
  1046. public:
  1047. AZ_TYPE_INFO(GenericClassGenericInfo, "{D1E1ACC0-7B90-48e9-999B-5825D4D4E397}");
  1048. GenericClassGenericInfo()
  1049. : m_classData{ SerializeContext::ClassData::Create<GenericChild>("GenericChild", GetSpecializedTypeId(), &m_factory) }
  1050. {
  1051. }
  1052. SerializeContext::ClassData* GetClassData() override
  1053. {
  1054. return &m_classData;
  1055. }
  1056. size_t GetNumTemplatedArguments() override
  1057. {
  1058. return 1;
  1059. }
  1060. AZ::TypeId GetTemplatedTypeId(size_t element) override
  1061. {
  1062. (void)element;
  1063. return SerializeGenericTypeInfo<GenericClass>::GetClassTypeId();
  1064. }
  1065. AZ::TypeId GetSpecializedTypeId() const override
  1066. {
  1067. return azrtti_typeid<GenericChild>();
  1068. }
  1069. AZ::TypeId GetGenericTypeId() const override
  1070. {
  1071. return TYPEINFO_Uuid();
  1072. }
  1073. void Reflect(SerializeContext*) override;
  1074. NullFactory m_factory;
  1075. SerializeContext::ClassData m_classData;
  1076. };
  1077. using ClassInfoType = GenericClassGenericInfo;
  1078. static ClassInfoType* GetGenericInfo()
  1079. {
  1080. return static_cast<ClassInfoType*>(GetGlobalSerializeContextModule().CreateGenericClassInfo<GenericChild>());
  1081. }
  1082. static AZ::TypeId GetClassTypeId()
  1083. {
  1084. return GetGenericInfo()->GetClassData()->m_typeId;
  1085. }
  1086. };
  1087. }
  1088. using namespace SerializeTestClasses;
  1089. using namespace AZ;
  1090. namespace UnitTest
  1091. {
  1092. /*
  1093. * Base class for all serialization unit tests
  1094. */
  1095. class Serialization
  1096. : public LeakDetectionFixture
  1097. , public ComponentApplicationBus::Handler
  1098. {
  1099. public:
  1100. //////////////////////////////////////////////////////////////////////////
  1101. // ComponentApplicationMessages
  1102. ComponentApplication* GetApplication() override { return nullptr; }
  1103. void RegisterComponentDescriptor(const ComponentDescriptor*) override { }
  1104. void UnregisterComponentDescriptor(const ComponentDescriptor*) override { }
  1105. void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { }
  1106. void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { }
  1107. void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { }
  1108. void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { }
  1109. void SignalEntityActivated(Entity*) override { }
  1110. void SignalEntityDeactivated(Entity*) override { }
  1111. bool AddEntity(Entity*) override { return false; }
  1112. bool RemoveEntity(Entity*) override { return false; }
  1113. bool DeleteEntity(const EntityId&) override { return false; }
  1114. Entity* FindEntity(const EntityId&) override { return nullptr; }
  1115. SerializeContext* GetSerializeContext() override { return m_serializeContext.get(); }
  1116. BehaviorContext* GetBehaviorContext() override { return nullptr; }
  1117. JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; }
  1118. const char* GetEngineRoot() const override { return nullptr; }
  1119. const char* GetExecutableFolder() const override { return nullptr; }
  1120. void EnumerateEntities(const EntityCallback& /*callback*/) override {}
  1121. void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
  1122. //////////////////////////////////////////////////////////////////////////
  1123. void SetUp() override
  1124. {
  1125. m_serializeContext.reset(aznew AZ::SerializeContext());
  1126. ComponentApplicationBus::Handler::BusConnect();
  1127. AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
  1128. m_streamer = AZStd::make_unique<IO::Streamer>(AZStd::thread_desc{}, AZ::StreamerComponent::CreateStreamerStack());
  1129. Interface<IO::IStreamer>::Register(m_streamer.get());
  1130. }
  1131. void TearDown() override
  1132. {
  1133. m_serializeContext.reset();
  1134. Interface<IO::IStreamer>::Unregister(m_streamer.get());
  1135. m_streamer.reset();
  1136. AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
  1137. ComponentApplicationBus::Handler::BusDisconnect();
  1138. }
  1139. template<typename Container>
  1140. void ReserveAndFreeWithoutMemLeaks()
  1141. {
  1142. Container instance;
  1143. GenericClassInfo* containerInfo = SerializeGenericTypeInfo<decltype(instance)>::GetGenericInfo();
  1144. EXPECT_NE(nullptr, containerInfo);
  1145. EXPECT_NE(nullptr, containerInfo->GetClassData());
  1146. SerializeContext::IDataContainer* container = containerInfo->GetClassData()->m_container;
  1147. EXPECT_NE(nullptr, container);
  1148. SerializeContext::IEventHandler* eventHandler = containerInfo->GetClassData()->m_eventHandler;
  1149. if (eventHandler)
  1150. {
  1151. eventHandler->OnWriteBegin(&container);
  1152. }
  1153. void* element = container->ReserveElement(&instance, nullptr);
  1154. EXPECT_NE(nullptr, element);
  1155. *reinterpret_cast<float*>(element) = 42.0f;
  1156. container->FreeReservedElement(&instance, element, nullptr);
  1157. if (eventHandler)
  1158. {
  1159. eventHandler->OnWriteEnd(&container);
  1160. }
  1161. }
  1162. protected:
  1163. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  1164. AZStd::unique_ptr<AZ::IO::Streamer> m_streamer;
  1165. };
  1166. /*
  1167. * Test serialization of built-in types
  1168. */
  1169. class SerializeBasicTest
  1170. : public Serialization
  1171. {
  1172. protected:
  1173. enum ClassicEnum
  1174. {
  1175. CE_A = 0,
  1176. CR_B = 1,
  1177. };
  1178. enum class ClassEnum : char
  1179. {
  1180. A = 0,
  1181. B = 1,
  1182. };
  1183. AZStd::unique_ptr<SerializeContext> m_context;
  1184. char m_char;
  1185. short m_short;
  1186. int m_int;
  1187. long m_long;
  1188. AZ::s64 m_s64;
  1189. unsigned char m_uchar;
  1190. unsigned short m_ushort;
  1191. unsigned int m_uint;
  1192. unsigned long m_ulong;
  1193. AZ::u64 m_u64;
  1194. float m_float;
  1195. double m_double;
  1196. bool m_true;
  1197. bool m_false;
  1198. // Math
  1199. AZ::Uuid m_uuid;
  1200. Vector2 m_vector2;
  1201. Vector3 m_vector3;
  1202. Vector4 m_vector4;
  1203. Transform m_transform;
  1204. Matrix3x3 m_matrix3x3;
  1205. Matrix4x4 m_matrix4x4;
  1206. Quaternion m_quaternion;
  1207. Aabb m_aabb;
  1208. Plane m_plane;
  1209. ClassicEnum m_classicEnum;
  1210. ClassEnum m_classEnum;
  1211. public:
  1212. void SetUp() override
  1213. {
  1214. Serialization::SetUp();
  1215. setlocale(LC_NUMERIC, "en-US");
  1216. m_context.reset(aznew SerializeContext());
  1217. }
  1218. void TearDown() override
  1219. {
  1220. setlocale(LC_NUMERIC, "en-US");
  1221. m_context.reset();
  1222. Serialization::TearDown();
  1223. }
  1224. void InitializeValues()
  1225. {
  1226. m_char = -1;
  1227. m_short = -2;
  1228. m_int = -3;
  1229. m_long = -4;
  1230. m_s64 = -5;
  1231. m_uchar = 1;
  1232. m_ushort = 2;
  1233. m_uint = 3;
  1234. m_ulong = 4;
  1235. m_u64 = 5;
  1236. m_float = 2.f;
  1237. m_double = 20.0000005;
  1238. m_true = true;
  1239. m_false = false;
  1240. // Math
  1241. m_uuid = AZ::Uuid::CreateString("{16490FB4-A7CE-4a8a-A882-F98DDA6A788F}");
  1242. m_vector2 = Vector2(1.0f, 2.0f);
  1243. m_vector3 = Vector3(3.0f, 4.0f, 5.0f);
  1244. m_vector4 = Vector4(6.0f, 7.0f, 8.0f, 9.0f);
  1245. m_quaternion = Quaternion::CreateRotationZ(0.7f);
  1246. m_transform = Transform::CreateRotationX(1.1f);
  1247. m_matrix3x3 = Matrix3x3::CreateRotationY(0.5f);
  1248. m_matrix4x4 = Matrix4x4::CreateFromQuaternionAndTranslation(m_quaternion, m_vector3);
  1249. m_aabb.Set(-m_vector3, m_vector3);
  1250. m_plane.Set(m_vector4);
  1251. m_classicEnum = CE_A;
  1252. m_classEnum = ClassEnum::B;
  1253. }
  1254. void OnLoadedClassReady(void* classPtr, const Uuid& classId, int* callCount)
  1255. {
  1256. switch ((*callCount)++)
  1257. {
  1258. case 0:
  1259. EXPECT_EQ( SerializeTypeInfo<char>::GetUuid(), classId );
  1260. EXPECT_EQ( m_char, *reinterpret_cast<char*>(classPtr) );
  1261. azdestroy(classPtr, AZ::SystemAllocator, char);
  1262. break;
  1263. case 1:
  1264. EXPECT_EQ( SerializeTypeInfo<short>::GetUuid(), classId );
  1265. EXPECT_EQ( m_short, *reinterpret_cast<short*>(classPtr) );
  1266. azdestroy(classPtr, AZ::SystemAllocator, short);
  1267. break;
  1268. case 2:
  1269. EXPECT_EQ( SerializeTypeInfo<int>::GetUuid(), classId );
  1270. EXPECT_EQ( m_int, *reinterpret_cast<int*>(classPtr) );
  1271. azdestroy(classPtr, AZ::SystemAllocator, int);
  1272. break;
  1273. case 3:
  1274. EXPECT_EQ( SerializeTypeInfo<long>::GetUuid(), classId );
  1275. EXPECT_EQ( m_long, *reinterpret_cast<long*>(classPtr) );
  1276. azdestroy(classPtr, AZ::SystemAllocator, long);
  1277. break;
  1278. case 4:
  1279. EXPECT_EQ( SerializeTypeInfo<AZ::s64>::GetUuid(), classId );
  1280. EXPECT_EQ( m_s64, *reinterpret_cast<AZ::s64*>(classPtr) );
  1281. azdestroy(classPtr, AZ::SystemAllocator, AZ::s64);
  1282. break;
  1283. case 5:
  1284. EXPECT_EQ( SerializeTypeInfo<unsigned char>::GetUuid(), classId );
  1285. EXPECT_EQ( m_uchar, *reinterpret_cast<unsigned char*>(classPtr) );
  1286. azdestroy(classPtr, AZ::SystemAllocator, unsigned char);
  1287. break;
  1288. case 6:
  1289. EXPECT_EQ( SerializeTypeInfo<unsigned short>::GetUuid(), classId );
  1290. EXPECT_EQ( m_ushort, *reinterpret_cast<unsigned short*>(classPtr) );
  1291. azdestroy(classPtr, AZ::SystemAllocator, unsigned short);
  1292. break;
  1293. case 7:
  1294. EXPECT_EQ( SerializeTypeInfo<unsigned int>::GetUuid(), classId );
  1295. EXPECT_EQ( m_uint, *reinterpret_cast<unsigned int*>(classPtr) );
  1296. azdestroy(classPtr, AZ::SystemAllocator, unsigned int);
  1297. break;
  1298. case 8:
  1299. EXPECT_EQ( SerializeTypeInfo<unsigned long>::GetUuid(), classId );
  1300. EXPECT_EQ( m_ulong, *reinterpret_cast<unsigned long*>(classPtr) );
  1301. azdestroy(classPtr, AZ::SystemAllocator, unsigned long);
  1302. break;
  1303. case 9:
  1304. EXPECT_EQ( SerializeTypeInfo<AZ::u64>::GetUuid(), classId );
  1305. EXPECT_EQ( m_u64, *reinterpret_cast<AZ::u64*>(classPtr) );
  1306. azdestroy(classPtr, AZ::SystemAllocator, AZ::u64);
  1307. break;
  1308. case 10:
  1309. EXPECT_EQ( SerializeTypeInfo<float>::GetUuid(), classId );
  1310. EXPECT_TRUE(fabsf(*reinterpret_cast<float*>(classPtr) - m_float) < 0.001f);
  1311. azdestroy(classPtr, AZ::SystemAllocator, float);
  1312. break;
  1313. case 11:
  1314. EXPECT_EQ( SerializeTypeInfo<double>::GetUuid(), classId );
  1315. EXPECT_TRUE(fabs(*reinterpret_cast<double*>(classPtr) - m_double) < 0.00000001);
  1316. azdestroy(classPtr, AZ::SystemAllocator, double);
  1317. break;
  1318. case 12:
  1319. EXPECT_EQ( SerializeTypeInfo<bool>::GetUuid(), classId );
  1320. EXPECT_EQ( m_true, *reinterpret_cast<bool*>(classPtr) );
  1321. azdestroy(classPtr, AZ::SystemAllocator, bool);
  1322. break;
  1323. case 13:
  1324. EXPECT_EQ( SerializeTypeInfo<bool>::GetUuid(), classId );
  1325. EXPECT_EQ( m_false, *reinterpret_cast<bool*>(classPtr) );
  1326. azdestroy(classPtr, AZ::SystemAllocator, bool);
  1327. break;
  1328. case 14:
  1329. EXPECT_EQ( SerializeTypeInfo<AZ::Uuid>::GetUuid(), classId );
  1330. EXPECT_EQ( m_uuid, *reinterpret_cast<AZ::Uuid*>(classPtr) );
  1331. azdestroy(classPtr, AZ::SystemAllocator, AZ::Uuid);
  1332. break;
  1333. case 15:
  1334. EXPECT_EQ( SerializeTypeInfo<AZ::Vector2>::GetUuid(), classId );
  1335. EXPECT_TRUE(reinterpret_cast<AZ::Vector2*>(classPtr)->IsClose(m_vector2, Constants::FloatEpsilon));
  1336. azdestroy(classPtr, AZ::SystemAllocator, AZ::Vector2);
  1337. break;
  1338. case 16:
  1339. EXPECT_EQ( SerializeTypeInfo<AZ::Vector3>::GetUuid(), classId );
  1340. EXPECT_TRUE(reinterpret_cast<AZ::Vector3*>(classPtr)->IsClose(m_vector3, Constants::FloatEpsilon));
  1341. azdestroy(classPtr, AZ::SystemAllocator, AZ::Vector3);
  1342. break;
  1343. case 17:
  1344. EXPECT_EQ( SerializeTypeInfo<AZ::Vector4>::GetUuid(), classId );
  1345. EXPECT_TRUE(reinterpret_cast<AZ::Vector4*>(classPtr)->IsClose(m_vector4, Constants::FloatEpsilon));
  1346. azdestroy(classPtr, AZ::SystemAllocator, AZ::Vector4);
  1347. break;
  1348. case 18:
  1349. EXPECT_EQ( SerializeTypeInfo<AZ::Transform>::GetUuid(), classId );
  1350. EXPECT_TRUE(reinterpret_cast<AZ::Transform*>(classPtr)->IsClose(m_transform, Constants::FloatEpsilon));
  1351. azdestroy(classPtr, AZ::SystemAllocator, AZ::Transform);
  1352. break;
  1353. case 19:
  1354. EXPECT_EQ( SerializeTypeInfo<AZ::Matrix3x3>::GetUuid(), classId );
  1355. EXPECT_TRUE(reinterpret_cast<AZ::Matrix3x3*>(classPtr)->IsClose(m_matrix3x3, Constants::FloatEpsilon));
  1356. azdestroy(classPtr, AZ::SystemAllocator, AZ::Matrix3x3);
  1357. break;
  1358. case 20:
  1359. EXPECT_EQ( SerializeTypeInfo<AZ::Matrix4x4>::GetUuid(), classId );
  1360. EXPECT_TRUE(reinterpret_cast<AZ::Matrix4x4*>(classPtr)->IsClose(m_matrix4x4, Constants::FloatEpsilon));
  1361. azdestroy(classPtr, AZ::SystemAllocator, AZ::Matrix4x4);
  1362. break;
  1363. case 21:
  1364. EXPECT_EQ( SerializeTypeInfo<AZ::Quaternion>::GetUuid(), classId );
  1365. EXPECT_TRUE(reinterpret_cast<AZ::Quaternion*>(classPtr)->IsClose(m_quaternion, Constants::FloatEpsilon));
  1366. azdestroy(classPtr, AZ::SystemAllocator, AZ::Quaternion);
  1367. break;
  1368. case 22:
  1369. EXPECT_EQ( SerializeTypeInfo<AZ::Aabb>::GetUuid(), classId );
  1370. EXPECT_TRUE(reinterpret_cast<AZ::Aabb*>(classPtr)->GetMin().IsClose(m_aabb.GetMin(), Constants::FloatEpsilon));
  1371. EXPECT_TRUE(reinterpret_cast<AZ::Aabb*>(classPtr)->GetMax().IsClose(m_aabb.GetMax(), Constants::FloatEpsilon));
  1372. azdestroy(classPtr, AZ::SystemAllocator, AZ::Aabb);
  1373. break;
  1374. case 23:
  1375. EXPECT_EQ( SerializeTypeInfo<AZ::Plane>::GetUuid(), classId );
  1376. EXPECT_TRUE(reinterpret_cast<AZ::Plane*>(classPtr)->GetPlaneEquationCoefficients().IsClose(m_plane.GetPlaneEquationCoefficients(), Constants::FloatEpsilon));
  1377. azdestroy(classPtr, AZ::SystemAllocator, AZ::Plane);
  1378. break;
  1379. case 24:
  1380. EXPECT_EQ( SerializeTypeInfo<ClassicEnum>::GetUuid(), classId );
  1381. EXPECT_EQ( CE_A, *reinterpret_cast<ClassicEnum*>(classPtr) );
  1382. azdestroy(classPtr, AZ::SystemAllocator, ClassicEnum);
  1383. break;
  1384. case 25:
  1385. EXPECT_EQ( SerializeTypeInfo<ClassEnum>::GetUuid(), classId );
  1386. EXPECT_EQ( ClassEnum::B, *reinterpret_cast<ClassEnum*>(classPtr) );
  1387. azdestroy(classPtr, AZ::SystemAllocator, ClassEnum);
  1388. break;
  1389. }
  1390. }
  1391. void SaveObjects(ObjectStream* writer)
  1392. {
  1393. bool success = true;
  1394. success = writer->WriteClass(&m_char);
  1395. EXPECT_TRUE(success);
  1396. success = writer->WriteClass(&m_short);
  1397. EXPECT_TRUE(success);
  1398. success = writer->WriteClass(&m_int);
  1399. EXPECT_TRUE(success);
  1400. success = writer->WriteClass(&m_long);
  1401. EXPECT_TRUE(success);
  1402. success = writer->WriteClass(&m_s64);
  1403. EXPECT_TRUE(success);
  1404. success = writer->WriteClass(&m_uchar);
  1405. EXPECT_TRUE(success);
  1406. success = writer->WriteClass(&m_ushort);
  1407. EXPECT_TRUE(success);
  1408. success = writer->WriteClass(&m_uint);
  1409. EXPECT_TRUE(success);
  1410. success = writer->WriteClass(&m_ulong);
  1411. EXPECT_TRUE(success);
  1412. success = writer->WriteClass(&m_u64);
  1413. EXPECT_TRUE(success);
  1414. success = writer->WriteClass(&m_float);
  1415. EXPECT_TRUE(success);
  1416. success = writer->WriteClass(&m_double);
  1417. EXPECT_TRUE(success);
  1418. success = writer->WriteClass(&m_true);
  1419. EXPECT_TRUE(success);
  1420. success = writer->WriteClass(&m_false);
  1421. EXPECT_TRUE(success);
  1422. success = writer->WriteClass(&m_uuid);
  1423. EXPECT_TRUE(success);
  1424. success = writer->WriteClass(&m_vector2);
  1425. EXPECT_TRUE(success);
  1426. success = writer->WriteClass(&m_vector3);
  1427. EXPECT_TRUE(success);
  1428. success = writer->WriteClass(&m_vector4);
  1429. EXPECT_TRUE(success);
  1430. success = writer->WriteClass(&m_transform);
  1431. EXPECT_TRUE(success);
  1432. success = writer->WriteClass(&m_matrix3x3);
  1433. EXPECT_TRUE(success);
  1434. success = writer->WriteClass(&m_matrix4x4);
  1435. EXPECT_TRUE(success);
  1436. success = writer->WriteClass(&m_quaternion);
  1437. EXPECT_TRUE(success);
  1438. success = writer->WriteClass(&m_aabb);
  1439. EXPECT_TRUE(success);
  1440. success = writer->WriteClass(&m_plane);
  1441. EXPECT_TRUE(success);
  1442. success = writer->WriteClass(&m_classicEnum);
  1443. EXPECT_TRUE(success);
  1444. success = writer->WriteClass(&m_classEnum);
  1445. EXPECT_TRUE(success);
  1446. }
  1447. void OnDone(ObjectStream::Handle handle, bool success, bool* done)
  1448. {
  1449. (void)handle;
  1450. EXPECT_TRUE(success);
  1451. *done = true;
  1452. }
  1453. void TestSave(IO::GenericStream* stream, ObjectStream::StreamType format)
  1454. {
  1455. ObjectStream* objStream = ObjectStream::Create(stream, *m_context, format);
  1456. SaveObjects(objStream);
  1457. bool done = objStream->Finalize();
  1458. EXPECT_TRUE(done);
  1459. }
  1460. void TestLoad(IO::GenericStream* stream)
  1461. {
  1462. int cbCount = 0;
  1463. bool done = false;
  1464. ObjectStream::ClassReadyCB readyCB(AZStd::bind(&SerializeBasicTest::OnLoadedClassReady, this, AZStd::placeholders::_1, AZStd::placeholders::_2, &cbCount));
  1465. ObjectStream::CompletionCB doneCB(AZStd::bind(&SerializeBasicTest::OnDone, this, AZStd::placeholders::_1, AZStd::placeholders::_2, &done));
  1466. ObjectStream::LoadBlocking(stream, *m_context, readyCB);
  1467. EXPECT_EQ( 26, cbCount );
  1468. }
  1469. };
  1470. namespace AdvancedTest
  1471. {
  1472. class EmptyClass
  1473. {
  1474. public:
  1475. AZ_CLASS_ALLOCATOR(EmptyClass, SystemAllocator);
  1476. AZ_TYPE_INFO(EmptyClass, "{7B2AA956-80A9-4996-B750-7CE8F7F79A29}")
  1477. EmptyClass()
  1478. : m_data(101)
  1479. {
  1480. }
  1481. static void Reflect(SerializeContext& context)
  1482. {
  1483. context.Class<EmptyClass>()
  1484. ->Version(1)
  1485. ->SerializeWithNoData();
  1486. }
  1487. int m_data;
  1488. };
  1489. // We don't recommend using this pattern as it can be tricky to track why some objects are stored, we
  1490. // wecommend that you have fully symetrical save/load.
  1491. class ConditionalSave
  1492. {
  1493. public:
  1494. AZ_CLASS_ALLOCATOR(ConditionalSave, SystemAllocator);
  1495. AZ_TYPE_INFO(ConditionalSave, "{E1E6910F-C029-492A-8163-026F6F69FC53}");
  1496. ConditionalSave()
  1497. : m_doSave(true)
  1498. , m_data(201)
  1499. {
  1500. }
  1501. static void Reflect(SerializeContext& context)
  1502. {
  1503. context.Class<ConditionalSave>()->
  1504. Version(1)->
  1505. SerializerDoSave([](const void* instance) { return reinterpret_cast<const ConditionalSave*>(instance)->m_doSave; })->
  1506. Field("m_data", &ConditionalSave::m_data);
  1507. }
  1508. bool m_doSave;
  1509. int m_data;
  1510. };
  1511. }
  1512. namespace ContainersTest
  1513. {
  1514. struct ContainersStruct
  1515. {
  1516. AZ_TYPE_INFO(ContainersStruct, "{E88A592D-5221-49DE-9DFD-6E25B39C65C7}");
  1517. AZ_CLASS_ALLOCATOR(ContainersStruct, AZ::SystemAllocator);
  1518. AZStd::vector<int> m_vector;
  1519. AZStd::fixed_vector<int, 5> m_fixedVector;
  1520. AZStd::array<int, 5> m_array;
  1521. AZStd::list<int> m_list;
  1522. AZStd::forward_list<int> m_forwardList;
  1523. AZStd::unordered_set<int> m_unorderedSet;
  1524. AZStd::unordered_map<int, float> m_unorderedMap;
  1525. AZStd::bitset<10> m_bitset;
  1526. };
  1527. struct AssociativePtrContainer
  1528. {
  1529. AZ_TYPE_INFO(AssociativePtrContainer, "{02223E23-9B9C-4196-84C2-77D3A57BFF87}");
  1530. AZ_CLASS_ALLOCATOR(AssociativePtrContainer, AZ::SystemAllocator);
  1531. static void Reflect(SerializeContext& serializeContext)
  1532. {
  1533. serializeContext.Class<AssociativePtrContainer>()
  1534. ->Field("m_setOfPointers", &AssociativePtrContainer::m_setOfPointers)
  1535. ->Field("m_mapOfFloatPointers", &AssociativePtrContainer::m_mapOfFloatPointers)
  1536. ->Field("m_sharedEntityPointer", &AssociativePtrContainer::m_sharedEntityPointer)
  1537. ;
  1538. }
  1539. AZStd::unordered_set<AZ::Entity*> m_setOfPointers;
  1540. AZStd::unordered_map<int, float*> m_mapOfFloatPointers;
  1541. AZStd::shared_ptr<AZ::Entity> m_sharedEntityPointer;
  1542. };
  1543. void ReflectVectorOfInts(AZ::SerializeContext* serializeContext)
  1544. {
  1545. AZ::GenericClassInfo* genericClassInfo = AZ::SerializeGenericTypeInfo<AZStd::vector<int>>::GetGenericInfo();
  1546. if (genericClassInfo)
  1547. {
  1548. genericClassInfo->Reflect(serializeContext);
  1549. }
  1550. genericClassInfo = AZ::SerializeGenericTypeInfo<AZStd::vector<int*>>::GetGenericInfo();
  1551. if (genericClassInfo)
  1552. {
  1553. genericClassInfo->Reflect(serializeContext);
  1554. }
  1555. }
  1556. }
  1557. TEST_F(Serialization, ElementOverrideTest_DefaultSerializationWorks)
  1558. {
  1559. ElementOverrideType::Reflect(*m_serializeContext);
  1560. ElementOverrideType testType;
  1561. testType.m_field = 1; // Our custom serializer will use the default output when this value is 1
  1562. AZStd::vector<char> buffer;
  1563. IO::ByteContainerStream<AZStd::vector<char>> stream(&buffer);
  1564. ASSERT_TRUE(Utils::SaveObjectToStream(stream, DataStream::ST_XML, &testType, m_serializeContext.get()));
  1565. constexpr const char* expectedValue =
  1566. R"(<ObjectStream version="3">)" "\n"
  1567. "\t" R"(<Class name="ElementOverrideType" type="{BAA18B6C-3CB3-476C-8B41-21EA7CE1F4CF}">)" "\n"
  1568. "\t\t" R"(<Class name="int" field="field" value="1" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>)" "\n"
  1569. "\t" R"(</Class>)" "\n"
  1570. R"(</ObjectStream>)";
  1571. AZStd::string result(buffer.data(), stream.GetLength());
  1572. AZ::StringFunc::TrimWhiteSpace(result, true, true);
  1573. EXPECT_STREQ(result.c_str(), expectedValue);
  1574. }
  1575. TEST_F(Serialization, ElementOverrideTest_CustomSerializationWorks)
  1576. {
  1577. ElementOverrideType::Reflect(*m_serializeContext);
  1578. ElementOverrideType testType;
  1579. testType.m_field = 0; // Our custom serializer will do its own output when this value is 0
  1580. AZStd::vector<char> buffer;
  1581. IO::ByteContainerStream<AZStd::vector<char>> stream(&buffer);
  1582. ASSERT_TRUE(Utils::SaveObjectToStream(stream, DataStream::ST_XML, &testType, m_serializeContext.get()));
  1583. constexpr const char* expectedValue =
  1584. R"(<ObjectStream version="3">)" "\n"
  1585. "\t" R"(<Class name="float" value="0.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>)" "\n"
  1586. R"(</ObjectStream>)";
  1587. AZStd::string result(buffer.data(), stream.GetLength());
  1588. AZ::StringFunc::TrimWhiteSpace(result, true, true);
  1589. EXPECT_STREQ(result.c_str(), expectedValue);
  1590. }
  1591. TEST_F(Serialization, ElementOverrideTest_FailureCase)
  1592. {
  1593. ElementOverrideType::Reflect(*m_serializeContext);
  1594. ElementOverrideType testType;
  1595. testType.m_field = 2; // Our custom serializer will report a failure when this value is not 0/1
  1596. AZStd::vector<char> buffer;
  1597. IO::ByteContainerStream<AZStd::vector<char>> stream(&buffer);
  1598. AZ_TEST_START_TRACE_SUPPRESSION;
  1599. ASSERT_FALSE(Utils::SaveObjectToStream(stream, DataStream::ST_XML, &testType, m_serializeContext.get()));
  1600. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  1601. }
  1602. TEST_F(Serialization, ContainerTypeContainedTypeDiffersByPointer)
  1603. {
  1604. ContainersTest::ReflectVectorOfInts(m_serializeContext.get());
  1605. AZStd::vector<int> vectorOfInts;
  1606. AZStd::vector<int*> vectorOfIntPointers;
  1607. vectorOfInts.push_back(5);
  1608. vectorOfIntPointers.push_back(azcreate(int, (5), AZ::SystemAllocator));
  1609. // Write Vector of Int to object stream
  1610. AZStd::vector<char> vectorIntBuffer;
  1611. IO::ByteContainerStream<AZStd::vector<char> > vectorIntStream(&vectorIntBuffer);
  1612. {
  1613. ObjectStream* objStream = ObjectStream::Create(&vectorIntStream, *m_serializeContext, ObjectStream::ST_XML);
  1614. objStream->WriteClass(&vectorOfInts);
  1615. objStream->Finalize();
  1616. }
  1617. AZStd::vector<char> vectorIntPointerBuffer;
  1618. IO::ByteContainerStream<AZStd::vector<char> > vectorIntPointerStream(&vectorIntPointerBuffer);
  1619. {
  1620. /*
  1621. * The vectorIntPointerBuffer.data() function call should be examined in the debugger after this block
  1622. * This will write out an the address of the integer 5 stored in the vectorOfIntPointers instead of 5 to the xml data
  1623. */
  1624. ObjectStream* objStream = ObjectStream::Create(&vectorIntPointerStream, *m_serializeContext, ObjectStream::ST_XML);
  1625. objStream->WriteClass(&vectorOfIntPointers);
  1626. objStream->Finalize();
  1627. }
  1628. vectorIntStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  1629. vectorIntPointerStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  1630. AZStd::vector<int> loadIntVector;
  1631. AZStd::vector<int*> loadIntPtrVector;
  1632. bool loadResult = AZ::Utils::LoadObjectFromStreamInPlace(vectorIntStream, loadIntVector, m_serializeContext.get());
  1633. EXPECT_TRUE(loadResult);
  1634. loadResult = AZ::Utils::LoadObjectFromStreamInPlace(vectorIntPointerStream, loadIntPtrVector, m_serializeContext.get());
  1635. EXPECT_TRUE(loadResult);
  1636. /*
  1637. * As the vector to int pointer class was reflected second, it would not get placed into the SerializeContext GenericClassInfoMap
  1638. * Therefore the write of the AZStd::vector<int*> to vectorIntPointerStream will output bad data as it reinterpret_cast
  1639. * the supplied AZStd::vector<int*> to an AZStd::vector<int>
  1640. */
  1641. ASSERT_EQ(1, loadIntVector.size());
  1642. EXPECT_EQ(vectorOfInts[0], loadIntVector[0]);
  1643. ASSERT_EQ(1, loadIntPtrVector.size());
  1644. ASSERT_NE(nullptr, loadIntPtrVector[0]);
  1645. EXPECT_NE(vectorOfIntPointers[0], loadIntPtrVector[0]);
  1646. EXPECT_EQ(*vectorOfIntPointers[0], *loadIntPtrVector[0]);
  1647. for (int* intPtr : vectorOfIntPointers)
  1648. {
  1649. azdestroy(intPtr);
  1650. }
  1651. for (int* intPtr : loadIntPtrVector)
  1652. {
  1653. // NOTE: This will crash if loadIntPtrVector uses the incorrect GenericClassInfo to serialize its data
  1654. azdestroy(intPtr);
  1655. }
  1656. m_serializeContext->EnableRemoveReflection();
  1657. ContainersTest::ReflectVectorOfInts(m_serializeContext.get());
  1658. m_serializeContext->DisableRemoveReflection();
  1659. }
  1660. #if AZ_TRAIT_DISABLE_FAILED_SERIALIZE_BASIC_TEST
  1661. TEST_F(SerializeBasicTest, DISABLED_BasicTypeTest_Succeed)
  1662. #else
  1663. TEST_F(SerializeBasicTest, BasicTypeTest_Succeed)
  1664. #endif
  1665. {
  1666. InitializeValues();
  1667. TestFileIOBase fileIO;
  1668. SetRestoreFileIOBaseRAII restoreFileIOScope(fileIO);
  1669. // Store test files within a temporary directory that is deleted
  1670. // when the variable goes out of scope
  1671. AZ::Test::ScopedAutoTempDirectory tempDirectory;
  1672. AZ::IO::Path serializeTestFilePath = tempDirectory.GetDirectory();
  1673. // XML version
  1674. AZ::IO::Path testXmlFilePath = serializeTestFilePath / "serializebasictest.xml";
  1675. {
  1676. AZ_TracePrintf("SerializeBasicTest", "\nWriting as XML...\n");
  1677. IO::FileIOStream stream(testXmlFilePath.c_str(), IO::OpenMode::ModeWrite);
  1678. TestSave(&stream, ObjectStream::ST_XML);
  1679. }
  1680. {
  1681. AZ_TracePrintf("SerializeBasicTest", "Loading as XML...\n");
  1682. IO::FileIOStream stream(testXmlFilePath.c_str(), IO::OpenMode::ModeRead);
  1683. TestLoad(&stream);
  1684. }
  1685. // JSON version
  1686. AZ::IO::Path testJsonFilePath = serializeTestFilePath / "serializebasictest.json";
  1687. {
  1688. AZ_TracePrintf("SerializeBasicTest", "\nWriting as JSON...\n");
  1689. IO::FileIOStream stream(testJsonFilePath.c_str(), IO::OpenMode::ModeWrite);
  1690. TestSave(&stream, ObjectStream::ST_JSON);
  1691. }
  1692. {
  1693. AZ_TracePrintf("SerializeBasicTest", "Loading as JSON...\n");
  1694. IO::FileIOStream stream(testJsonFilePath.c_str(), IO::OpenMode::ModeRead);
  1695. TestLoad(&stream);
  1696. }
  1697. // Binary version
  1698. AZ::IO::Path testBinFilePath = serializeTestFilePath / "serializebasictest.bin";
  1699. {
  1700. AZ_TracePrintf("SerializeBasicTest", "Writing as Binary...\n");
  1701. IO::FileIOStream stream(testBinFilePath.c_str(), IO::OpenMode::ModeWrite);
  1702. TestSave(&stream, ObjectStream::ST_BINARY);
  1703. }
  1704. {
  1705. AZ_TracePrintf("SerializeBasicTest", "Loading as Binary...\n");
  1706. IO::FileIOStream stream(testBinFilePath.c_str(), IO::OpenMode::ModeRead);
  1707. TestLoad(&stream);
  1708. }
  1709. }
  1710. TEST_F(SerializeBasicTest, BasicTypeTest_LocaleIndependent)
  1711. {
  1712. InitializeValues();
  1713. m_s64 = -50000; // ensure that the number is large enough so that if the locale inserts commas, they are there
  1714. m_float = 20000.5f;
  1715. m_double = 20000.5; // the number has values after the decimal point and is large enough that it would be formatted with a comma
  1716. TestFileIOBase fileIO;
  1717. SetRestoreFileIOBaseRAII restoreFileIOScope(fileIO);
  1718. // Store test files within a temporary directory that is deleted
  1719. // when the variable goes out of scope
  1720. AZ::Test::ScopedAutoTempDirectory tempDirectory;
  1721. AZ::IO::Path serializeTestFilePath = tempDirectory.GetDirectory();
  1722. auto readwriteFn = [&](AZ::IO::Path testFilePath, const char* localewrite, const char* localeread, AZ::DataStream::StreamType streamType)
  1723. {
  1724. {
  1725. setlocale(LC_ALL, localewrite);
  1726. AZ_TracePrintf("SerializeBasicTest", "\nWriting as XML with global locale %s...\n", localewrite);
  1727. IO::FileIOStream stream(testFilePath.c_str(), IO::OpenMode::ModeWrite);
  1728. TestSave(&stream, streamType);
  1729. }
  1730. {
  1731. setlocale(LC_ALL, localeread);
  1732. AZ_TracePrintf("SerializeBasicTest", "Loading as XML with global locale %s...\n", localeread);
  1733. IO::FileIOStream stream(testFilePath.c_str(), IO::OpenMode::ModeRead);
  1734. TestLoad(&stream);
  1735. }
  1736. };
  1737. // XML version
  1738. AZ::IO::Path testXmlFilePath = serializeTestFilePath / "serializebasictest_localeindependent.xml";
  1739. readwriteFn(testXmlFilePath, "en-US", "pl-PL", ObjectStream::ST_XML);
  1740. readwriteFn(testXmlFilePath, "pl-PL", "en-US", ObjectStream::ST_XML);
  1741. // JSON version
  1742. AZ::IO::Path testJsonFilePath = serializeTestFilePath / "serializebasictest_localeindependent.json";
  1743. readwriteFn(testJsonFilePath, "en-US", "pl-PL", ObjectStream::ST_JSON);
  1744. readwriteFn(testJsonFilePath, "pl-PL", "en-US", ObjectStream::ST_XML);
  1745. // Binary version
  1746. AZ::IO::Path testBinFilePath = serializeTestFilePath / "serializebasictest_localeindependent.bin";
  1747. readwriteFn(testJsonFilePath, "en-US", "pl-PL", ObjectStream::ST_BINARY);
  1748. readwriteFn(testJsonFilePath, "pl-PL", "en-US", ObjectStream::ST_BINARY);
  1749. }
  1750. /*
  1751. * Test serialization of built-in container types
  1752. */
  1753. TEST_F(Serialization, ContainersTest)
  1754. {
  1755. using namespace ContainersTest;
  1756. class ContainersTest
  1757. {
  1758. public:
  1759. void VerifyLoad(void* classPtr, const Uuid& classId, ContainersStruct* controlData)
  1760. {
  1761. EXPECT_EQ( SerializeTypeInfo<ContainersStruct>::GetUuid(), classId );
  1762. ContainersStruct* data = reinterpret_cast<ContainersStruct*>(classPtr);
  1763. EXPECT_EQ( controlData->m_vector, data->m_vector );
  1764. EXPECT_EQ( controlData->m_fixedVector, data->m_fixedVector );
  1765. EXPECT_EQ( controlData->m_array[0], data->m_array[0] );
  1766. EXPECT_EQ( controlData->m_array[1], data->m_array[1] );
  1767. EXPECT_EQ( controlData->m_list, data->m_list );
  1768. EXPECT_EQ( controlData->m_forwardList, data->m_forwardList );
  1769. EXPECT_EQ( controlData->m_unorderedSet.size(), data->m_unorderedSet.size() );
  1770. for (AZStd::unordered_set<int>::const_iterator it = data->m_unorderedSet.begin(), ctrlIt = controlData->m_unorderedSet.begin(); it != data->m_unorderedSet.end(); ++it, ++ctrlIt)
  1771. {
  1772. EXPECT_EQ( *ctrlIt, *it );
  1773. }
  1774. EXPECT_EQ( controlData->m_unorderedMap.size(), data->m_unorderedMap.size() );
  1775. for (AZStd::unordered_map<int, float>::const_iterator it = data->m_unorderedMap.begin(), ctrlIt = controlData->m_unorderedMap.begin(); it != data->m_unorderedMap.end(); ++it, ++ctrlIt)
  1776. {
  1777. EXPECT_EQ( *ctrlIt, *it );
  1778. }
  1779. EXPECT_EQ( controlData->m_bitset, data->m_bitset );
  1780. delete data;
  1781. }
  1782. void run()
  1783. {
  1784. SerializeContext serializeContext;
  1785. serializeContext.Class<ContainersStruct>()
  1786. ->Field("m_vector", &ContainersStruct::m_vector)
  1787. ->Field("m_fixedVector", &ContainersStruct::m_fixedVector)
  1788. ->Field("m_array", &ContainersStruct::m_array)
  1789. ->Field("m_list", &ContainersStruct::m_list)
  1790. ->Field("m_forwardList", &ContainersStruct::m_forwardList)
  1791. ->Field("m_unorderedSet", &ContainersStruct::m_unorderedSet)
  1792. ->Field("m_unorderedMap", &ContainersStruct::m_unorderedMap)
  1793. ->Field("m_bitset", &ContainersStruct::m_bitset);
  1794. ContainersStruct testData;
  1795. testData.m_vector.push_back(1);
  1796. testData.m_vector.push_back(2);
  1797. testData.m_fixedVector.push_back(3);
  1798. testData.m_fixedVector.push_back(4);
  1799. testData.m_array[0] = 5;
  1800. testData.m_array[1] = 6;
  1801. testData.m_list.push_back(7);
  1802. testData.m_list.push_back(8);
  1803. auto forwardListIt = testData.m_forwardList.emplace_after(testData.m_forwardList.before_begin(), 9);
  1804. testData.m_forwardList.emplace_after(forwardListIt, 10);
  1805. testData.m_unorderedSet.insert(11);
  1806. testData.m_unorderedSet.insert(12);
  1807. testData.m_unorderedMap.insert(AZStd::make_pair(13, 13.f));
  1808. testData.m_unorderedMap.insert(AZStd::make_pair(14, 14.f));
  1809. testData.m_bitset.set(0);
  1810. testData.m_bitset.set(9);
  1811. // XML
  1812. AZStd::vector<char> xmlBuffer;
  1813. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&xmlBuffer);
  1814. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, serializeContext, ObjectStream::ST_XML);
  1815. xmlObjStream->WriteClass(&testData);
  1816. xmlObjStream->Finalize();
  1817. xmlStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  1818. ObjectStream::ClassReadyCB readyCB(AZStd::bind(&ContainersTest::VerifyLoad, this, AZStd::placeholders::_1, AZStd::placeholders::_2, &testData));
  1819. ObjectStream::LoadBlocking(&xmlStream, serializeContext, readyCB);
  1820. }
  1821. };
  1822. ContainersTest test;
  1823. test.run();
  1824. }
  1825. TEST_F(Serialization, AssociativeContainerPtrTest)
  1826. {
  1827. using namespace ContainersTest;
  1828. // We must expose the class for serialization first.
  1829. AZ::Entity::Reflect(m_serializeContext.get());
  1830. AssociativePtrContainer::Reflect(*m_serializeContext);
  1831. AssociativePtrContainer testObj;
  1832. testObj.m_setOfPointers.insert(aznew AZ::Entity("Entity1"));
  1833. testObj.m_setOfPointers.insert(aznew AZ::Entity("Entity2"));
  1834. testObj.m_mapOfFloatPointers.emplace(5, azcreate(float, (3.14f), AZ::SystemAllocator));
  1835. testObj.m_sharedEntityPointer.reset(aznew AZ::Entity("Entity3"));
  1836. // XML
  1837. AZStd::vector<char> xmlBuffer;
  1838. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&xmlBuffer);
  1839. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, *m_serializeContext, ObjectStream::ST_XML);
  1840. xmlObjStream->WriteClass(&testObj);
  1841. xmlObjStream->Finalize();
  1842. xmlStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  1843. bool result = ObjectStream::LoadBlocking(&xmlStream, *m_serializeContext, [&testObj](void* classPtr, const AZ::Uuid& classId, SerializeContext*)
  1844. {
  1845. EXPECT_EQ(SerializeTypeInfo<AssociativePtrContainer>::GetUuid(), classId);
  1846. auto loadObj = reinterpret_cast<AssociativePtrContainer*>(classPtr);
  1847. EXPECT_EQ(testObj.m_setOfPointers.size(), loadObj->m_setOfPointers.size());
  1848. auto testObjSetBeginIt = testObj.m_setOfPointers.begin();
  1849. auto loadObjSetBeginIt = loadObj->m_setOfPointers.begin();
  1850. for (; testObjSetBeginIt != testObj.m_setOfPointers.end(); ++testObjSetBeginIt, ++loadObjSetBeginIt)
  1851. {
  1852. EXPECT_EQ((*testObjSetBeginIt)->GetId(), (*loadObjSetBeginIt)->GetId());
  1853. }
  1854. EXPECT_EQ(testObj.m_mapOfFloatPointers.size(), loadObj->m_mapOfFloatPointers.size());
  1855. auto testObjMapBeginIt = testObj.m_mapOfFloatPointers.begin();
  1856. auto loadObjMapBeginIt = loadObj->m_mapOfFloatPointers.begin();
  1857. for (; testObjMapBeginIt != testObj.m_mapOfFloatPointers.end(); ++testObjMapBeginIt, ++loadObjMapBeginIt)
  1858. {
  1859. EXPECT_EQ(*(testObjMapBeginIt->second), *(loadObjMapBeginIt->second));
  1860. }
  1861. EXPECT_NE(nullptr, loadObj->m_sharedEntityPointer.get());
  1862. EXPECT_EQ(testObj.m_sharedEntityPointer->GetId(), loadObj->m_sharedEntityPointer->GetId());
  1863. //Free the allocated memory
  1864. for (auto& entitySet : { testObj.m_setOfPointers, loadObj->m_setOfPointers })
  1865. {
  1866. for (AZ::Entity* entityPtr : entitySet)
  1867. {
  1868. delete entityPtr;
  1869. }
  1870. }
  1871. for (auto& intFloatPtrMap : { testObj.m_mapOfFloatPointers, loadObj->m_mapOfFloatPointers })
  1872. {
  1873. for (auto& intFloatPtrPair : intFloatPtrMap)
  1874. {
  1875. azdestroy(intFloatPtrPair.second);
  1876. }
  1877. }
  1878. delete loadObj;
  1879. });
  1880. EXPECT_TRUE(result);
  1881. }
  1882. /*
  1883. This test will dynamic cast (azrtti_cast) between incompatible types, which should always result in nullptr.
  1884. If this test fails, the RTTI declaration for the relevant type is incorrect.
  1885. */
  1886. TEST_F(Serialization, AttributeRTTI)
  1887. {
  1888. {
  1889. AttributeInvocable<AZStd::function<AZStd::string(AZStd::string)>> fn([](AZStd::string x) { return x + x; });
  1890. Attribute* fnDownCast = &fn;
  1891. auto fnUpCast = azrtti_cast<AttributeInvocable<AZStd::function<int(int)>>*>(fnDownCast);
  1892. EXPECT_EQ(fnUpCast, nullptr);
  1893. }
  1894. {
  1895. AttributeFunction<AZStd::string(AZStd::string)> fn([](AZStd::string x) { return x + x; });
  1896. Attribute* fnDownCast = &fn;
  1897. auto fnUpCast = azrtti_cast<AttributeFunction<int(int)>*>(fnDownCast);
  1898. EXPECT_EQ(fnUpCast, nullptr);
  1899. }
  1900. }
  1901. /*
  1902. * Deprecation
  1903. */
  1904. namespace Deprecation
  1905. {
  1906. struct DeprecatedClass
  1907. {
  1908. AZ_CLASS_ALLOCATOR(DeprecatedClass, AZ::SystemAllocator);
  1909. AZ_TYPE_INFO(DeprecatedClass, "{893CA46E-6D1A-4D27-94F7-09E26DE5AE4B}")
  1910. DeprecatedClass()
  1911. : m_data(0) {}
  1912. int m_data;
  1913. };
  1914. struct DeprecationTestClass
  1915. {
  1916. AZ_CLASS_ALLOCATOR(DeprecationTestClass, AZ::SystemAllocator);
  1917. AZ_TYPE_INFO(DeprecationTestClass, "{54E27F53-EF3F-4436-9378-E9AF56A9FA4C}")
  1918. DeprecationTestClass()
  1919. : m_deprecatedPtr(nullptr)
  1920. , m_oldClassData(0)
  1921. , m_newClassData(0.f)
  1922. , m_missingMember(0)
  1923. , m_data(0)
  1924. {}
  1925. ~DeprecationTestClass() { Clear(); }
  1926. void Clear()
  1927. {
  1928. if (m_deprecatedPtr)
  1929. {
  1930. delete m_deprecatedPtr;
  1931. m_deprecatedPtr = nullptr;
  1932. }
  1933. }
  1934. DeprecatedClass m_deprecated;
  1935. DeprecatedClass* m_deprecatedPtr;
  1936. int m_oldClassData;
  1937. float m_newClassData;
  1938. int m_missingMember;
  1939. int m_data;
  1940. };
  1941. struct SimpleBaseClass
  1942. {
  1943. AZ_CLASS_ALLOCATOR(SimpleBaseClass, AZ::SystemAllocator);
  1944. AZ_RTTI(SimpleBaseClass, "{829F6E24-AAEF-4C97-9003-0BC22CB64786}")
  1945. SimpleBaseClass()
  1946. : m_data(0.f) {}
  1947. virtual ~SimpleBaseClass() {}
  1948. float m_data;
  1949. };
  1950. struct SimpleDerivedClass1 : public SimpleBaseClass
  1951. {
  1952. AZ_CLASS_ALLOCATOR(SimpleDerivedClass1, AZ::SystemAllocator);
  1953. AZ_RTTI(SimpleDerivedClass1, "{78632262-C303-49BC-ABAD-88B088098311}", SimpleBaseClass)
  1954. SimpleDerivedClass1() {}
  1955. };
  1956. struct SimpleDerivedClass2 : public SimpleBaseClass
  1957. {
  1958. AZ_CLASS_ALLOCATOR(SimpleDerivedClass2, AZ::SystemAllocator);
  1959. AZ_RTTI(SimpleDerivedClass2, "{4932DF7C-0482-4846-AAE5-BED7D03F9E02}", SimpleBaseClass)
  1960. SimpleDerivedClass2() {}
  1961. };
  1962. struct OwnerClass
  1963. {
  1964. AZ_CLASS_ALLOCATOR(OwnerClass, AZ::SystemAllocator);
  1965. AZ_TYPE_INFO(OwnerClass, "{3F305C77-4BE1-49E6-9C51-9F1284F18CCE}");
  1966. OwnerClass() {}
  1967. SimpleBaseClass* m_pointer = nullptr;
  1968. };
  1969. }
  1970. TEST_F(Serialization, TestDeprecatedClassAtRootLevel_Succeeds)
  1971. {
  1972. using namespace Deprecation;
  1973. // Test a deprecated class at the root level.
  1974. SerializeContext sc;
  1975. SimpleDerivedClass1 simpleDerivedClass1;
  1976. sc.Class<SimpleBaseClass>()
  1977. ->Version(1)
  1978. ->Field("m_data", &SimpleBaseClass::m_data);
  1979. sc.Class<SimpleDerivedClass1, SimpleBaseClass>()
  1980. ->Version(1);
  1981. sc.Class<SimpleDerivedClass2, SimpleBaseClass>()
  1982. ->Version(1);
  1983. AZStd::vector<char> xmlBufferRootTest;
  1984. AZStd::vector<char> jsonBufferRootTest;
  1985. AZStd::vector<char> binaryBufferRootTest;
  1986. {
  1987. // XML
  1988. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&xmlBufferRootTest);
  1989. AZ_TracePrintf("SerializeDeprecationTest", "Writing XML\n");
  1990. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, sc, ObjectStream::ST_XML);
  1991. xmlObjStream->WriteClass(&simpleDerivedClass1);
  1992. bool success = xmlObjStream->Finalize();
  1993. EXPECT_TRUE(success);
  1994. // JSON
  1995. IO::ByteContainerStream<AZStd::vector<char> > jsonStream(&jsonBufferRootTest);
  1996. AZ_TracePrintf("SerializeDeprecationTest", "Writing JSON\n");
  1997. ObjectStream* jsonObjStream = ObjectStream::Create(&jsonStream, sc, ObjectStream::ST_JSON);
  1998. jsonObjStream->WriteClass(&simpleDerivedClass1);
  1999. success = jsonObjStream->Finalize();
  2000. EXPECT_TRUE(success);
  2001. // Binary
  2002. IO::ByteContainerStream<AZStd::vector<char> > binaryStream(&binaryBufferRootTest);
  2003. AZ_TracePrintf("SerializeDeprecationTest", "Writing Binary\n");
  2004. ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  2005. binaryObjStream->WriteClass(&simpleDerivedClass1);
  2006. success = binaryObjStream->Finalize();
  2007. EXPECT_TRUE(success);
  2008. }
  2009. sc.EnableRemoveReflection();
  2010. sc.Class<SimpleDerivedClass1>();
  2011. sc.DisableRemoveReflection();
  2012. AZ::SerializeContext::VersionConverter converter = [](AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) -> bool
  2013. {
  2014. return classElement.Convert<SimpleDerivedClass2>(context);
  2015. };
  2016. sc.ClassDeprecate("SimpleDerivedClass1", AZ::Uuid("{78632262-C303-49BC-ABAD-88B088098311}"), converter);
  2017. auto cb = [](void* classPtr, const Uuid& classId, SerializeContext* /*context*/) -> void
  2018. {
  2019. EXPECT_EQ(AzTypeInfo<SimpleDerivedClass2>::Uuid(), classId);
  2020. delete static_cast<SimpleDerivedClass2*>(classPtr);
  2021. };
  2022. ObjectStream::ClassReadyCB readyCBTest(cb);
  2023. // XML
  2024. AZ_TracePrintf("SerializeDeprecationTest", "Loading XML with deprecated class\n");
  2025. IO::ByteContainerStream<const AZStd::vector<char> > xmlStreamUuidTest(&xmlBufferRootTest);
  2026. xmlStreamUuidTest.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2027. EXPECT_TRUE(ObjectStream::LoadBlocking(&xmlStreamUuidTest, sc, readyCBTest));
  2028. // JSON
  2029. AZ_TracePrintf("SerializeDeprecationTest", "Loading JSON with deprecated class\n");
  2030. IO::ByteContainerStream<const AZStd::vector<char> > jsonStream(&jsonBufferRootTest);
  2031. jsonStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2032. ObjectStream::LoadBlocking(&jsonStream, sc, readyCBTest);
  2033. // Binary
  2034. AZ_TracePrintf("SerializeDeprecationTest", "Loading Binary with deprecated class\n");
  2035. IO::ByteContainerStream<const AZStd::vector<char> > binaryStream(&binaryBufferRootTest);
  2036. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2037. ObjectStream::LoadBlocking(&binaryStream, sc, readyCBTest);
  2038. }
  2039. TEST_F(Serialization, DeprecationRulesTest)
  2040. {
  2041. using namespace Deprecation;
  2042. class DeprecationTest
  2043. {
  2044. public:
  2045. DeprecatedClass m_deprecated;
  2046. DeprecationTestClass m_deprecationTestClass;
  2047. void WriteDeprecated(ObjectStream* writer)
  2048. {
  2049. bool success = writer->WriteClass(&m_deprecated);
  2050. EXPECT_TRUE(success);
  2051. }
  2052. void WriteDeprecationTestClass(ObjectStream* writer)
  2053. {
  2054. bool success = writer->WriteClass(&m_deprecationTestClass);
  2055. EXPECT_TRUE(success);
  2056. }
  2057. void CheckDeprecated(void* classPtr, const Uuid& classId)
  2058. {
  2059. (void)classPtr;
  2060. (void)classId;
  2061. // We should never hit here since our class was deprecated
  2062. EXPECT_TRUE(false);
  2063. }
  2064. void CheckMemberDeprecation(void* classPtr, const Uuid& classId)
  2065. {
  2066. (void)classId;
  2067. DeprecationTestClass* obj = reinterpret_cast<DeprecationTestClass*>(classPtr);
  2068. EXPECT_EQ( 0, obj->m_deprecated.m_data );
  2069. EXPECT_EQ( nullptr, obj->m_deprecatedPtr );
  2070. EXPECT_EQ( 0, obj->m_oldClassData );
  2071. EXPECT_EQ( 0.f, obj->m_newClassData );
  2072. EXPECT_EQ( 0, obj->m_missingMember );
  2073. EXPECT_EQ( m_deprecationTestClass.m_data, obj->m_data );
  2074. delete obj;
  2075. }
  2076. void run()
  2077. {
  2078. m_deprecated.m_data = 10;
  2079. m_deprecationTestClass.m_deprecated.m_data = 10;
  2080. m_deprecationTestClass.m_deprecatedPtr = aznew DeprecatedClass;
  2081. m_deprecationTestClass.m_oldClassData = 10;
  2082. m_deprecationTestClass.m_missingMember = 10;
  2083. m_deprecationTestClass.m_data = 10;
  2084. // Test new version without conversion.
  2085. // -Member types without reflection should be silently dropped.
  2086. // -Members whose reflection data don't match should be silently dropped.
  2087. // -Members whose names don't match should be silently dropped.
  2088. // -The converted class itself should still be accepted.
  2089. AZ_TracePrintf("SerializeDeprecationTest", "\nTesting dropped/deprecated members:\n");
  2090. {
  2091. // Write original data
  2092. AZStd::vector<char> xmlBuffer;
  2093. AZStd::vector<char> jsonBuffer;
  2094. AZStd::vector<char> binaryBuffer;
  2095. {
  2096. SerializeContext sc;
  2097. sc.Class<DeprecatedClass>()
  2098. ->Field("m_data", &DeprecatedClass::m_data);
  2099. sc.Class<DeprecationTestClass>()
  2100. ->Field("m_deprecated", &DeprecationTestClass::m_deprecated)
  2101. ->Field("m_deprecatedPtr", &DeprecationTestClass::m_deprecatedPtr)
  2102. ->Field("m_oldClassData", &DeprecationTestClass::m_oldClassData)
  2103. ->Field("m_missingMember", &DeprecationTestClass::m_missingMember)
  2104. ->Field("m_data", &DeprecationTestClass::m_data);
  2105. // XML
  2106. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&xmlBuffer);
  2107. AZ_TracePrintf("SerializeDeprecationTest", "Writing XML\n");
  2108. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, sc, ObjectStream::ST_XML);
  2109. WriteDeprecationTestClass(xmlObjStream);
  2110. bool success = xmlObjStream->Finalize();
  2111. EXPECT_TRUE(success);
  2112. // JSON
  2113. IO::ByteContainerStream<AZStd::vector<char> > jsonStream(&jsonBuffer);
  2114. AZ_TracePrintf("SerializeDeprecationTest", "Writing JSON\n");
  2115. ObjectStream* jsonObjStream = ObjectStream::Create(&jsonStream, sc, ObjectStream::ST_JSON);
  2116. WriteDeprecationTestClass(jsonObjStream);
  2117. success = jsonObjStream->Finalize();
  2118. EXPECT_TRUE(success);
  2119. // Binary
  2120. IO::ByteContainerStream<AZStd::vector<char> > binaryStream(&binaryBuffer);
  2121. AZ_TracePrintf("SerializeDeprecationTest", "Writing Binary\n");
  2122. ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  2123. WriteDeprecationTestClass(binaryObjStream);
  2124. success = binaryObjStream->Finalize();
  2125. EXPECT_TRUE(success);
  2126. }
  2127. ObjectStream::ClassReadyCB readyCB(AZStd::bind(&DeprecationTest::CheckMemberDeprecation, this, AZStd::placeholders::_1, AZStd::placeholders::_2));
  2128. // Test deprecation with one member class not reflected at all
  2129. {
  2130. SerializeContext sc;
  2131. sc.Class<DeprecationTestClass>()
  2132. ->Version(2)
  2133. ->Field("m_deprecated", &DeprecationTestClass::m_deprecated)
  2134. ->Field("m_deprecatedPtr", &DeprecationTestClass::m_deprecatedPtr)
  2135. ->Field("m_oldClassData", &DeprecationTestClass::m_newClassData)
  2136. ->Field("m_data", &DeprecationTestClass::m_data);
  2137. // XML
  2138. AZ_TracePrintf("SerializeDeprecationTest", "Loading XML with dropped class\n");
  2139. IO::ByteContainerStream<const AZStd::vector<char> > xmlStream(&xmlBuffer);
  2140. xmlStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2141. ObjectStream::LoadBlocking(&xmlStream, sc, readyCB);
  2142. // JSON
  2143. AZ_TracePrintf("SerializeDeprecationTest", "Loading JSON with dropped class\n");
  2144. IO::ByteContainerStream<const AZStd::vector<char> > jsonStream(&jsonBuffer);
  2145. jsonStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2146. ObjectStream::LoadBlocking(&jsonStream, sc, readyCB);
  2147. // Binary
  2148. AZ_TracePrintf("SerializeDeprecationTest", "Loading Binary with dropped class\n");
  2149. IO::ByteContainerStream<const AZStd::vector<char> > binaryStream(&binaryBuffer);
  2150. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2151. ObjectStream::LoadBlocking(&binaryStream, sc, readyCB);
  2152. }
  2153. // Test deprecation with one member class marked as deprecated
  2154. {
  2155. SerializeContext sc;
  2156. sc.ClassDeprecate("DeprecatedClass", AZ::Uuid("{893CA46E-6D1A-4D27-94F7-09E26DE5AE4B}"));
  2157. sc.Class<DeprecationTestClass>()
  2158. ->Version(2)
  2159. ->Field("m_deprecated", &DeprecationTestClass::m_deprecated)
  2160. ->Field("m_deprecatedPtr", &DeprecationTestClass::m_deprecatedPtr)
  2161. ->Field("m_oldClassData", &DeprecationTestClass::m_newClassData)
  2162. ->Field("m_data", &DeprecationTestClass::m_data);
  2163. // XML
  2164. AZ_TracePrintf("SerializeDeprecationTest", "Loading XML with deprecated class\n");
  2165. IO::ByteContainerStream<const AZStd::vector<char> > xmlStream(&xmlBuffer);
  2166. xmlStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2167. ObjectStream::LoadBlocking(&xmlStream, sc, readyCB);
  2168. // JSON
  2169. AZ_TracePrintf("SerializeDeprecationTest", "Loading JSON with deprecated class\n");
  2170. IO::ByteContainerStream<const AZStd::vector<char> > jsonStream(&jsonBuffer);
  2171. jsonStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2172. ObjectStream::LoadBlocking(&jsonStream, sc, readyCB);
  2173. // Binary
  2174. AZ_TracePrintf("SerializeDeprecationTest", "Loading Binary with deprecated class\n");
  2175. IO::ByteContainerStream<const AZStd::vector<char> > binaryStream(&binaryBuffer);
  2176. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2177. ObjectStream::LoadBlocking(&binaryStream, sc, readyCB);
  2178. }
  2179. // Test deprecation with a converter to an entirely new type.
  2180. {
  2181. SerializeContext sc;
  2182. sc.Class<DeprecationTestClass>()
  2183. ->Version(2)
  2184. ->Field("m_deprecated", &DeprecationTestClass::m_deprecated)
  2185. ->Field("m_deprecatedPtr", &DeprecationTestClass::m_deprecatedPtr)
  2186. ->Field("m_oldClassData", &DeprecationTestClass::m_newClassData)
  2187. ->Field("m_data", &DeprecationTestClass::m_data);
  2188. AZ::SerializeContext::VersionConverter converter = [](AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) -> bool
  2189. {
  2190. return classElement.Convert<DeprecationTestClass>(context);
  2191. };
  2192. sc.ClassDeprecate("DeprecatedClass", AZ::Uuid("{893CA46E-6D1A-4D27-94F7-09E26DE5AE4B}"), converter);
  2193. // XML
  2194. AZ_TracePrintf("SerializeDeprecationTest", "Loading XML with deprecated class\n");
  2195. IO::ByteContainerStream<const AZStd::vector<char> > xmlStream(&xmlBuffer);
  2196. xmlStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2197. ObjectStream::LoadBlocking(&xmlStream, sc, readyCB);
  2198. // JSON
  2199. AZ_TracePrintf("SerializeDeprecationTest", "Loading JSON with deprecated class\n");
  2200. IO::ByteContainerStream<const AZStd::vector<char> > jsonStream(&jsonBuffer);
  2201. jsonStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2202. ObjectStream::LoadBlocking(&jsonStream, sc, readyCB);
  2203. // Binary
  2204. AZ_TracePrintf("SerializeDeprecationTest", "Loading Binary with deprecated class\n");
  2205. IO::ByteContainerStream<const AZStd::vector<char> > binaryStream(&binaryBuffer);
  2206. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2207. ObjectStream::LoadBlocking(&binaryStream, sc, readyCB);
  2208. }
  2209. // Test a converter that completely swaps uuid.
  2210. // This test should FAIL, because the uuid cannot be swapped in non-deprecation cases.
  2211. {
  2212. SerializeContext sc;
  2213. sc.Class<SimpleBaseClass>()
  2214. ->Version(1)
  2215. ->Field("m_data", &SimpleBaseClass::m_data);
  2216. AZ::SerializeContext::VersionConverter converter = [](AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) -> bool
  2217. {
  2218. return classElement.Convert<SimpleBaseClass>(context);
  2219. };
  2220. sc.Class<DeprecationTestClass>()
  2221. ->Version(3, converter)
  2222. ->Field("m_oldClassData", &DeprecationTestClass::m_newClassData)
  2223. ->Field("m_data", &DeprecationTestClass::m_data);
  2224. // XML
  2225. AZ_TracePrintf("SerializeDeprecationTest", "Loading XML with deprecated class\n");
  2226. IO::ByteContainerStream<const AZStd::vector<char> > xmlStream(&xmlBuffer);
  2227. xmlStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2228. // This should fail!
  2229. AZ_TEST_START_TRACE_SUPPRESSION;
  2230. ObjectStream::LoadBlocking(&xmlStream, sc, readyCB);
  2231. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  2232. }
  2233. // Test a converter that swaps uuid to a castable/compatible type in a deprecation converter.
  2234. {
  2235. SimpleDerivedClass1 simpleDerivedClass1;
  2236. OwnerClass ownerClass;
  2237. ownerClass.m_pointer = &simpleDerivedClass1;
  2238. SerializeContext sc;
  2239. sc.Class<SimpleBaseClass>()
  2240. ->Version(1)
  2241. ->Field("m_data", &SimpleBaseClass::m_data);
  2242. sc.Class<SimpleDerivedClass1, SimpleBaseClass>()
  2243. ->Version(1);
  2244. sc.Class<SimpleDerivedClass2, SimpleBaseClass>()
  2245. ->Version(1);
  2246. sc.Class<OwnerClass>()
  2247. ->Version(1)
  2248. ->Field("Pointer", &OwnerClass::m_pointer);
  2249. AZStd::vector<char> xmlBufferUuidTest;
  2250. AZStd::vector<char> jsonBufferUuidTest;
  2251. AZStd::vector<char> binaryBufferUuidTest;
  2252. {
  2253. // XML
  2254. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&xmlBufferUuidTest);
  2255. AZ_TracePrintf("SerializeDeprecationTest", "Writing XML\n");
  2256. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, sc, ObjectStream::ST_XML);
  2257. xmlObjStream->WriteClass(&ownerClass);
  2258. bool success = xmlObjStream->Finalize();
  2259. EXPECT_TRUE(success);
  2260. // JSON
  2261. IO::ByteContainerStream<AZStd::vector<char> > jsonStream(&jsonBufferUuidTest);
  2262. AZ_TracePrintf("SerializeDeprecationTest", "Writing JSON\n");
  2263. ObjectStream* jsonObjStream = ObjectStream::Create(&jsonStream, sc, ObjectStream::ST_JSON);
  2264. jsonObjStream->WriteClass(&ownerClass);
  2265. success = jsonObjStream->Finalize();
  2266. EXPECT_TRUE(success);
  2267. // Binary
  2268. IO::ByteContainerStream<AZStd::vector<char> > binaryStream(&binaryBufferUuidTest);
  2269. AZ_TracePrintf("SerializeDeprecationTest", "Writing Binary\n");
  2270. ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  2271. binaryObjStream->WriteClass(&ownerClass);
  2272. success = binaryObjStream->Finalize();
  2273. EXPECT_TRUE(success);
  2274. }
  2275. sc.EnableRemoveReflection();
  2276. sc.Class<OwnerClass>();
  2277. sc.DisableRemoveReflection();
  2278. AZ::SerializeContext::VersionConverter converter = [](AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) -> bool
  2279. {
  2280. const int idx = classElement.FindElement(AZ_CRC_CE("Pointer"));
  2281. classElement.GetSubElement(idx).Convert<SimpleDerivedClass2>(context);
  2282. return true;
  2283. };
  2284. sc.Class<OwnerClass>()
  2285. ->Version(2, converter)
  2286. ->Field("Pointer", &OwnerClass::m_pointer);
  2287. auto cb = [](void* classPtr, const Uuid& classId, SerializeContext* /*context*/) -> void
  2288. {
  2289. EXPECT_EQ( AzTypeInfo<OwnerClass>::Uuid(), classId );
  2290. EXPECT_TRUE(static_cast<OwnerClass*>(classPtr)->m_pointer);
  2291. EXPECT_EQ( AzTypeInfo<SimpleDerivedClass2>::Uuid(), static_cast<OwnerClass*>(classPtr)->m_pointer->RTTI_GetType() );
  2292. delete static_cast<OwnerClass*>(classPtr)->m_pointer;
  2293. delete static_cast<OwnerClass*>(classPtr);
  2294. };
  2295. ObjectStream::ClassReadyCB readyCBTest(cb);
  2296. // XML
  2297. AZ_TracePrintf("SerializeDeprecationTest", "Loading XML with deprecated class\n");
  2298. IO::ByteContainerStream<const AZStd::vector<char> > xmlStreamUuidTest(&xmlBufferUuidTest);
  2299. xmlStreamUuidTest.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2300. EXPECT_TRUE(ObjectStream::LoadBlocking(&xmlStreamUuidTest, sc, readyCBTest));
  2301. // JSON
  2302. AZ_TracePrintf("SerializeDeprecationTest", "Loading JSON with deprecated class\n");
  2303. IO::ByteContainerStream<const AZStd::vector<char> > jsonStream(&jsonBufferUuidTest);
  2304. jsonStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2305. ObjectStream::LoadBlocking(&jsonStream, sc, readyCBTest);
  2306. // Binary
  2307. AZ_TracePrintf("SerializeDeprecationTest", "Loading Binary with deprecated class\n");
  2308. IO::ByteContainerStream<const AZStd::vector<char> > binaryStream(&binaryBufferUuidTest);
  2309. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2310. ObjectStream::LoadBlocking(&binaryStream, sc, readyCBTest);
  2311. }
  2312. }
  2313. // Test root objects of deprecated classes.
  2314. // -Classes reflected as deprecated should be silently dropped.
  2315. AZ_TracePrintf("SerializeDeprecationTest", "Testing deprecated root objects:\n");
  2316. {
  2317. AZStd::vector<char> xmlBuffer;
  2318. AZStd::vector<char> jsonBuffer;
  2319. AZStd::vector<char> binaryBuffer;
  2320. // Write original data
  2321. {
  2322. SerializeContext sc;
  2323. sc.Class<DeprecatedClass>()
  2324. ->Field("m_data", &DeprecatedClass::m_data);
  2325. // XML
  2326. AZ_TracePrintf("SerializeDeprecationTest", "Writing XML\n");
  2327. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&xmlBuffer);
  2328. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, sc, ObjectStream::ST_XML);
  2329. WriteDeprecated(xmlObjStream);
  2330. bool success = xmlObjStream->Finalize();
  2331. EXPECT_TRUE(success);
  2332. // JSON
  2333. AZ_TracePrintf("SerializeDeprecationTest", "Writing JSON\n");
  2334. IO::ByteContainerStream<AZStd::vector<char> > jsonStream(&jsonBuffer);
  2335. ObjectStream* jsonObjStream = ObjectStream::Create(&jsonStream, sc, ObjectStream::ST_JSON);
  2336. WriteDeprecated(jsonObjStream);
  2337. success = jsonObjStream->Finalize();
  2338. EXPECT_TRUE(success);
  2339. // Binary
  2340. AZ_TracePrintf("SerializeDeprecationTest", "Writing Binary\n");
  2341. IO::ByteContainerStream<AZStd::vector<char> > binaryStream(&binaryBuffer);
  2342. ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  2343. WriteDeprecated(binaryObjStream);
  2344. success = binaryObjStream->Finalize();
  2345. EXPECT_TRUE(success);
  2346. }
  2347. // Test deprecation
  2348. {
  2349. SerializeContext sc;
  2350. sc.ClassDeprecate("DeprecatedClass", AZ::Uuid("{893CA46E-6D1A-4D27-94F7-09E26DE5AE4B}"));
  2351. ObjectStream::ClassReadyCB readyCB(AZStd::bind(&DeprecationTest::CheckDeprecated, this, AZStd::placeholders::_1, AZStd::placeholders::_2));
  2352. // XML
  2353. AZ_TracePrintf("SerializeDeprecationTest", "Loading XML with deprecated root object\n");
  2354. IO::ByteContainerStream<const AZStd::vector<char> > xmlStream(&xmlBuffer);
  2355. xmlStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2356. ObjectStream::LoadBlocking(&xmlStream, sc, readyCB);
  2357. // JSON
  2358. AZ_TracePrintf("SerializeDeprecationTest", "Loading JSON with deprecated root object\n");
  2359. IO::ByteContainerStream<const AZStd::vector<char> > jsonStream(&jsonBuffer);
  2360. jsonStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2361. ObjectStream::LoadBlocking(&jsonStream, sc, readyCB);
  2362. // Binary
  2363. AZ_TracePrintf("SerializeDeprecationTest", "Loading Binary with deprecated root object\n");
  2364. IO::ByteContainerStream<const AZStd::vector<char> > binaryStream(&binaryBuffer);
  2365. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  2366. ObjectStream::LoadBlocking(&binaryStream, sc, readyCB);
  2367. }
  2368. }
  2369. m_deprecationTestClass.Clear();
  2370. }
  2371. };
  2372. DeprecationTest test;
  2373. test.run();
  2374. }
  2375. /*
  2376. * Test complicated conversion
  2377. */
  2378. namespace Conversion
  2379. {
  2380. struct TestObj
  2381. {
  2382. AZ_TYPE_INFO(TestObj, "{6AE2EE4A-1DB8-41B7-B909-296A10CEF4EA}");
  2383. AZ_CLASS_ALLOCATOR(TestObj, AZ::SystemAllocator);
  2384. TestObj() = default;
  2385. Generics m_dataOld;
  2386. GenericsNew m_dataNew;
  2387. };
  2388. }
  2389. /*
  2390. * Data Overlay Test
  2391. */
  2392. namespace DataOverlay
  2393. {
  2394. struct DataOverlayTestStruct
  2395. {
  2396. AZ_TYPE_INFO(DataOverlayTestStruct, "{AD843B4D-0D08-4CE0-99F9-7E4E1EAD5984}");
  2397. AZ_CLASS_ALLOCATOR(DataOverlayTestStruct, AZ::SystemAllocator);
  2398. DataOverlayTestStruct()
  2399. : m_int(0)
  2400. , m_ptr(nullptr) {}
  2401. int m_int;
  2402. AZStd::vector<int> m_intVector;
  2403. DataOverlayTestStruct* m_ptr;
  2404. };
  2405. }
  2406. TEST_F(Serialization, DataOverlayTest)
  2407. {
  2408. using namespace DataOverlay;
  2409. class DataOverlayTest
  2410. {
  2411. class DataOverlayProviderExample
  2412. : public DataOverlayProviderBus::Handler
  2413. {
  2414. public:
  2415. static DataOverlayProviderId GetProviderId() { return AZ_CRC_CE("DataOverlayProviderExample"); }
  2416. static u32 GetIntToken() { return AZ_CRC_CE("int_data"); }
  2417. static u32 GetVectorToken() { return AZ_CRC_CE("vector_data"); }
  2418. static u32 GetPointerToken() { return AZ_CRC_CE("pointer_data"); }
  2419. DataOverlayProviderExample()
  2420. {
  2421. m_ptrData.m_int = 5;
  2422. m_ptrData.m_intVector.push_back(1);
  2423. m_ptrData.m_ptr = nullptr;
  2424. m_data.m_int = 3;
  2425. m_data.m_intVector.push_back(10);
  2426. m_data.m_intVector.push_back(20);
  2427. m_data.m_intVector.push_back(30);
  2428. m_data.m_ptr = &m_ptrData;
  2429. }
  2430. void FillOverlayData(DataOverlayTarget* dest, const DataOverlayToken& dataToken) override
  2431. {
  2432. if (*reinterpret_cast<const u32*>(dataToken.m_dataUri.data()) == GetIntToken())
  2433. {
  2434. dest->SetData(m_data.m_int);
  2435. }
  2436. else if (*reinterpret_cast<const u32*>(dataToken.m_dataUri.data()) == GetVectorToken())
  2437. {
  2438. dest->SetData(m_data.m_intVector);
  2439. }
  2440. else if (*reinterpret_cast<const u32*>(dataToken.m_dataUri.data()) == GetPointerToken())
  2441. {
  2442. dest->SetData(*m_data.m_ptr);
  2443. }
  2444. }
  2445. DataOverlayTestStruct m_data;
  2446. DataOverlayTestStruct m_ptrData;
  2447. };
  2448. class DataOverlayInstanceEnumeratorExample
  2449. : public DataOverlayInstanceBus::Handler
  2450. {
  2451. public:
  2452. enum InstanceType
  2453. {
  2454. Type_Int,
  2455. Type_Vector,
  2456. Type_Pointer,
  2457. };
  2458. DataOverlayInstanceEnumeratorExample(InstanceType type)
  2459. : m_type(type) {}
  2460. ~DataOverlayInstanceEnumeratorExample() override
  2461. {
  2462. BusDisconnect();
  2463. }
  2464. DataOverlayInfo GetOverlayInfo() override
  2465. {
  2466. DataOverlayInfo info;
  2467. info.m_providerId = DataOverlayProviderExample::GetProviderId();
  2468. u32 token = m_type == Type_Int ? DataOverlayProviderExample::GetIntToken() : m_type == Type_Vector ? DataOverlayProviderExample::GetVectorToken() : DataOverlayProviderExample::GetPointerToken();
  2469. info.m_dataToken.m_dataUri.insert(info.m_dataToken.m_dataUri.end(), reinterpret_cast<u8*>(&token), reinterpret_cast<u8*>(&token) + sizeof(u32));
  2470. return info;
  2471. }
  2472. InstanceType m_type;
  2473. };
  2474. void CheckOverlay(const DataOverlayTestStruct* controlData, void* classPtr, const Uuid& uuid)
  2475. {
  2476. EXPECT_EQ( SerializeTypeInfo<DataOverlayTestStruct>::GetUuid(), uuid );
  2477. DataOverlayTestStruct* newData = reinterpret_cast<DataOverlayTestStruct*>(classPtr);
  2478. EXPECT_EQ( controlData->m_int, newData->m_int );
  2479. EXPECT_EQ( controlData->m_intVector, newData->m_intVector );
  2480. EXPECT_TRUE(newData->m_ptr != nullptr);
  2481. EXPECT_TRUE(newData->m_ptr != controlData->m_ptr);
  2482. EXPECT_EQ( controlData->m_ptr->m_int, newData->m_ptr->m_int );
  2483. EXPECT_EQ( controlData->m_ptr->m_intVector, newData->m_ptr->m_intVector );
  2484. EXPECT_EQ( controlData->m_ptr->m_ptr, newData->m_ptr->m_ptr );
  2485. delete newData->m_ptr;
  2486. delete newData;
  2487. }
  2488. public:
  2489. void run()
  2490. {
  2491. SerializeContext serializeContext;
  2492. // We must expose the class for serialization first.
  2493. serializeContext.Class<DataOverlayTestStruct>()
  2494. ->Field("int", &DataOverlayTestStruct::m_int)
  2495. ->Field("intVector", &DataOverlayTestStruct::m_intVector)
  2496. ->Field("pointer", &DataOverlayTestStruct::m_ptr);
  2497. DataOverlayTestStruct testData;
  2498. testData.m_ptr = &testData;
  2499. DataOverlayInstanceEnumeratorExample intOverlayEnumerator(DataOverlayInstanceEnumeratorExample::Type_Int);
  2500. intOverlayEnumerator.BusConnect(DataOverlayInstanceId(&testData.m_int, SerializeTypeInfo<int>::GetUuid()));
  2501. DataOverlayInstanceEnumeratorExample vectorOverlayEnumerator(DataOverlayInstanceEnumeratorExample::Type_Vector);
  2502. vectorOverlayEnumerator.BusConnect(DataOverlayInstanceId(&testData.m_intVector, SerializeGenericTypeInfo<AZStd::vector<int> >::GetClassTypeId()));
  2503. DataOverlayInstanceEnumeratorExample pointerOverlayEnumerator(DataOverlayInstanceEnumeratorExample::Type_Pointer);
  2504. pointerOverlayEnumerator.BusConnect(DataOverlayInstanceId(&testData.m_ptr, SerializeTypeInfo<DataOverlayTestStruct>::GetUuid()));
  2505. // XML
  2506. AZStd::vector<char> xmlBuffer;
  2507. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&xmlBuffer);
  2508. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, serializeContext, ObjectStream::ST_XML);
  2509. xmlObjStream->WriteClass(&testData);
  2510. xmlObjStream->Finalize();
  2511. DataOverlayProviderExample overlayProvider;
  2512. overlayProvider.BusConnect(DataOverlayProviderExample::GetProviderId());
  2513. xmlStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  2514. ObjectStream::ClassReadyCB readyCB(AZStd::bind(&DataOverlayTest::CheckOverlay, this, &overlayProvider.m_data, AZStd::placeholders::_1, AZStd::placeholders::_2));
  2515. ObjectStream::LoadBlocking(&xmlStream, serializeContext, readyCB);
  2516. }
  2517. };
  2518. DataOverlayTest test;
  2519. test.run();
  2520. }
  2521. /*
  2522. * DynamicSerializableFieldTest
  2523. */
  2524. TEST_F(Serialization, DynamicSerializableFieldTest)
  2525. {
  2526. SerializeContext serializeContext;
  2527. // We must expose the class for serialization first.
  2528. MyClassBase1::Reflect(serializeContext);
  2529. MyClassBase2::Reflect(serializeContext);
  2530. MyClassBase3::Reflect(serializeContext);
  2531. SerializeTestClasses::MyClassMix::Reflect(serializeContext);
  2532. SerializeTestClasses::MyClassMix obj;
  2533. obj.Set(5); // Initialize with some value
  2534. DynamicSerializableField testData;
  2535. testData.m_data = &obj;
  2536. testData.m_typeId = SerializeTypeInfo<SerializeTestClasses::MyClassMix>::GetUuid();
  2537. // XML
  2538. AZStd::vector<char> xmlBuffer;
  2539. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&xmlBuffer);
  2540. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, serializeContext, ObjectStream::ST_XML);
  2541. xmlObjStream->WriteClass(&testData);
  2542. xmlObjStream->Finalize();
  2543. xmlStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  2544. auto verifyLoad = [&testData](void* classPtr, const Uuid& uuid, SerializeContext* sc) -> void
  2545. {
  2546. EXPECT_EQ( SerializeTypeInfo<DynamicSerializableField>::GetUuid(), uuid );
  2547. DynamicSerializableField* newData = reinterpret_cast<DynamicSerializableField*>(classPtr);
  2548. EXPECT_EQ( SerializeTypeInfo<SerializeTestClasses::MyClassMix>::GetUuid(), newData->m_typeId );
  2549. EXPECT_TRUE(newData->m_data != nullptr);
  2550. EXPECT_TRUE( *reinterpret_cast<SerializeTestClasses::MyClassMix*>(testData.m_data) == *reinterpret_cast<SerializeTestClasses::MyClassMix*>(newData->m_data) );
  2551. newData->DestroyData(sc);
  2552. azdestroy(newData, AZ::SystemAllocator, DynamicSerializableField);
  2553. };
  2554. ObjectStream::ClassReadyCB readyCB(verifyLoad);
  2555. ObjectStream::LoadBlocking(&xmlStream, serializeContext, readyCB);
  2556. }
  2557. /*
  2558. * DynamicSerializableFieldTest
  2559. */
  2560. class SerializeDynamicSerializableFieldTest
  2561. : public LeakDetectionFixture
  2562. {
  2563. public:
  2564. // Structure for reflecting Generic Template types to the Serialize context
  2565. // so that they get added to the SerializeContext m_uuidGenericMap
  2566. struct GenericTemplateTypes
  2567. {
  2568. AZ_TYPE_INFO(GenericTemplateTypes, "{24D83563-2AAA-40FE-8C77-0DC8298EDDEA}");
  2569. static void Reflect(AZ::SerializeContext& sc)
  2570. {
  2571. sc.Class<GenericTemplateTypes>()->
  2572. Field("stringToStringMap", &GenericTemplateTypes::m_stringStringMap)
  2573. ;
  2574. }
  2575. AZStd::unordered_map<AZStd::string, AZStd::string> m_stringStringMap;
  2576. };
  2577. };
  2578. TEST_F(SerializeDynamicSerializableFieldTest, NonSerializableTypeTest)
  2579. {
  2580. SerializeContext serializeContext;
  2581. DynamicSerializableField testData;
  2582. EXPECT_EQ(nullptr, testData.m_data);
  2583. EXPECT_EQ(AZ::Uuid::CreateNull(), testData.m_typeId);
  2584. // Write DynamicSerializableField to stream
  2585. AZStd::vector<AZ::u8> buffer;
  2586. AZ::IO::ByteContainerStream<decltype(buffer)> stream(&buffer);
  2587. {
  2588. ObjectStream* binObjectStream = ObjectStream::Create(&stream, serializeContext, ObjectStream::ST_BINARY);
  2589. binObjectStream->WriteClass(&testData);
  2590. binObjectStream->Finalize();
  2591. }
  2592. // Load DynamicSerializableField from stream
  2593. stream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  2594. {
  2595. DynamicSerializableField loadData;
  2596. loadData.m_typeId = AZ::Uuid::CreateRandom();
  2597. // TypeId should be serialized in as a null Uuid and the m_data field should remain unchanged
  2598. AZ::Utils::LoadObjectFromStreamInPlace(stream, loadData, &serializeContext);
  2599. EXPECT_EQ(AZ::Uuid::CreateNull(), loadData.m_typeId);
  2600. }
  2601. }
  2602. TEST_F(SerializeDynamicSerializableFieldTest, TemplateTypeSerializeTest)
  2603. {
  2604. SerializeContext serializeContext;
  2605. GenericTemplateTypes::Reflect(serializeContext);
  2606. DynamicSerializableField testData;
  2607. EXPECT_EQ(nullptr, testData.m_data);
  2608. EXPECT_EQ(AZ::Uuid::CreateNull(), testData.m_typeId);
  2609. AZStd::unordered_map<AZStd::string, AZStd::string> stringMap;
  2610. stringMap.emplace("Key", "Value");
  2611. stringMap.emplace("Lumber", "Yard");
  2612. testData.Set(&stringMap);
  2613. // Write DynamicSerializableField to stream
  2614. AZStd::vector<AZ::u8> buffer;
  2615. AZ::IO::ByteContainerStream<decltype(buffer)> stream(&buffer);
  2616. {
  2617. ObjectStream* binObjectStream = ObjectStream::Create(&stream, serializeContext, ObjectStream::ST_BINARY);
  2618. binObjectStream->WriteClass(&testData);
  2619. binObjectStream->Finalize();
  2620. }
  2621. // Load DynamicSerializableField from stream
  2622. stream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  2623. /* Loaded AZStd::Containers for serialization cannot be pointers, as they use to a NullFactory for heap creation
  2624. {
  2625. DynamicSerializableField loadData;
  2626. loadData.m_typeId = AZ::Uuid::CreateRandom();
  2627. AZ::Utils::LoadObjectFromStreamInPlace(stream, loadData, &serializeContext);
  2628. EXPECT_NE(nullptr, loadData.Get<decltype(stringMap)>());
  2629. auto& loadedStringMap = *loadData.Get<decltype(stringMap)>();
  2630. auto loadedStringIt = loadedStringMap.find("Lumber");
  2631. EXPECT_NE(loadedStringMap.end(), loadedStringIt);
  2632. EXPECT_EQ("Yard", loadedStringIt->second);
  2633. loadData.DestroyData(&serializeContext);
  2634. }
  2635. */
  2636. }
  2637. /*
  2638. * CloneTest
  2639. */
  2640. namespace Clone
  2641. {
  2642. struct RefCounted
  2643. {
  2644. AZ_CLASS_ALLOCATOR(RefCounted, AZ::SystemAllocator);
  2645. AZ_TYPE_INFO(RefCounted, "{ca52979d-b926-461a-b1f5-66bbfdb80639}");
  2646. RefCounted()
  2647. : m_refCount(0)
  2648. , m_data(0)
  2649. {}
  2650. RefCounted(int data)
  2651. : m_refCount(0)
  2652. , m_data(data)
  2653. {}
  2654. virtual ~RefCounted() = default;
  2655. static void Reflect(SerializeContext& serializeContext)
  2656. {
  2657. serializeContext.Class<RefCounted>()
  2658. ->Field("Data", &RefCounted::m_data);
  2659. }
  2660. //////////////////////////////////////////////////////////////////////////
  2661. // For intrusive pointers
  2662. void add_ref() { m_refCount++; }
  2663. void release()
  2664. {
  2665. --m_refCount;
  2666. if (m_refCount == 0)
  2667. {
  2668. delete this;
  2669. }
  2670. }
  2671. int m_refCount;
  2672. //////////////////////////////////////////////////////////////////////////
  2673. int m_data;
  2674. };
  2675. struct Clonable
  2676. {
  2677. Clonable()
  2678. : m_emptyInitText("Some init text!")
  2679. {
  2680. }
  2681. virtual ~Clonable() = default;
  2682. AZ_RTTI(Clonable, "{3E463CC3-CC78-4F21-9BE8-0B0AA10E8E26}");
  2683. AZ_CLASS_ALLOCATOR(Clonable, AZ::SystemAllocator);
  2684. static void Reflect(SerializeContext& serializeContext)
  2685. {
  2686. serializeContext.Class<Clonable>()
  2687. ->Field("m_int", &Clonable::m_int)
  2688. ->Field("m_emptyInitText", &Clonable::m_emptyInitText)
  2689. ->Field("m_map", &Clonable::m_map)
  2690. ->Field("m_fieldValues", &Clonable::m_fieldValues)
  2691. ->Field("m_smartArray", &Clonable::m_smartArray);
  2692. }
  2693. int m_int;
  2694. AZStd::string m_emptyInitText;
  2695. AZStd::unordered_map<int, int> m_map;
  2696. AZStd::vector<DynamicSerializableField> m_fieldValues;
  2697. AZStd::array<AZStd::intrusive_ptr<RefCounted>, 10> m_smartArray;
  2698. };
  2699. struct ClonableMutlipleInheritanceOrderingA
  2700. : public AZ::TickBus::Handler
  2701. , public RefCounted
  2702. , public Clonable
  2703. {
  2704. AZ_RTTI(ClonableMutlipleInheritanceOrderingA, "{4A1FA4E5-48FB-413D-876F-E6633240773A}", Clonable);
  2705. AZ_CLASS_ALLOCATOR(ClonableMutlipleInheritanceOrderingA, AZ::SystemAllocator);
  2706. ClonableMutlipleInheritanceOrderingA() = default;
  2707. ~ClonableMutlipleInheritanceOrderingA() override = default;
  2708. MOCK_METHOD2(OnTick, void (float, AZ::ScriptTimePoint));
  2709. virtual void MyNewVirtualFunction() {}
  2710. static void Reflect(SerializeContext& serializeContext)
  2711. {
  2712. serializeContext.Class<ClonableMutlipleInheritanceOrderingA, Clonable>()
  2713. ->Field("myInt0", &ClonableMutlipleInheritanceOrderingA::m_myInt0)
  2714. ;
  2715. }
  2716. int m_myInt0 = 0;
  2717. };
  2718. struct ClonableMutlipleInheritanceOrderingB
  2719. : public Clonable
  2720. , public RefCounted
  2721. , public AZ::TickBus::Handler
  2722. {
  2723. AZ_RTTI(ClonableMutlipleInheritanceOrderingB, "{169D8A4F-6C8A-4F50-8B7B-3EE81A9948BB}", Clonable);
  2724. AZ_CLASS_ALLOCATOR(ClonableMutlipleInheritanceOrderingB, AZ::SystemAllocator);
  2725. ClonableMutlipleInheritanceOrderingB() = default;
  2726. ~ClonableMutlipleInheritanceOrderingB() override = default;
  2727. MOCK_METHOD2(OnTick, void (float, AZ::ScriptTimePoint));
  2728. MOCK_METHOD0(SomeVirtualFunction, void ());
  2729. virtual char MyCharSumFunction() { return m_myChar0 + m_myChar1 + m_myChar2; }
  2730. virtual void MyCharResetFunction() { m_myChar0 = m_myChar1 = m_myChar2 = 0; }
  2731. static void Reflect(SerializeContext& serializeContext)
  2732. {
  2733. serializeContext.Class<ClonableMutlipleInheritanceOrderingB, Clonable>()
  2734. ->Field("myChar0", &ClonableMutlipleInheritanceOrderingB::m_myChar0)
  2735. ->Field("myChar1", &ClonableMutlipleInheritanceOrderingB::m_myChar1)
  2736. ->Field("myChar2", &ClonableMutlipleInheritanceOrderingB::m_myChar2)
  2737. ;
  2738. }
  2739. char m_myChar0 = 0;
  2740. char m_myChar1 = 1;
  2741. char m_myChar2 = 2;
  2742. };
  2743. struct ClonableAssociativePointerContainer
  2744. {
  2745. AZ_TYPE_INFO(ClonableAssociativePointerContainer, "{F558DC57-7850-42E1-9D16-5538C0D839E2}");
  2746. AZ_CLASS_ALLOCATOR(ClonableAssociativePointerContainer, AZ::SystemAllocator);
  2747. static void Reflect(SerializeContext& serializeContext)
  2748. {
  2749. serializeContext.Class<ClonableAssociativePointerContainer>()
  2750. ->Field("m_setOfPointers", &ClonableAssociativePointerContainer::m_setOfPointers)
  2751. ->Field("m_mapOfFloatPointers", &ClonableAssociativePointerContainer::m_mapOfFloatPointers)
  2752. ->Field("m_sharedEntityPointer", &ClonableAssociativePointerContainer::m_sharedEntityPointer)
  2753. ;
  2754. }
  2755. AZStd::unordered_set<AZ::Entity*> m_setOfPointers;
  2756. AZStd::unordered_map<int, float*> m_mapOfFloatPointers;
  2757. AZStd::shared_ptr<AZ::Entity> m_sharedEntityPointer;
  2758. };
  2759. }
  2760. TEST_F(Serialization, CloneTest)
  2761. {
  2762. using namespace Clone;
  2763. // We must expose the class for serialization first.
  2764. MyClassBase1::Reflect((*m_serializeContext));
  2765. MyClassBase2::Reflect((*m_serializeContext));
  2766. MyClassBase3::Reflect((*m_serializeContext));
  2767. SerializeTestClasses::MyClassMix::Reflect((*m_serializeContext));
  2768. RefCounted::Reflect((*m_serializeContext));
  2769. Clonable::Reflect((*m_serializeContext));
  2770. Clonable testObj;
  2771. testObj.m_int = 100;
  2772. testObj.m_emptyInitText = ""; // set to empty to make sure we write zero values
  2773. testObj.m_map.insert(AZStd::make_pair(1, 2));
  2774. testObj.m_smartArray[0] = aznew RefCounted(101);
  2775. testObj.m_smartArray[1] = aznew RefCounted(201);
  2776. testObj.m_smartArray[2] = aznew RefCounted(301);
  2777. SerializeTestClasses::MyClassMix val1;
  2778. val1.Set(5); // Initialize with some value
  2779. DynamicSerializableField valField1;
  2780. valField1.m_data = &val1;
  2781. valField1.m_typeId = SerializeTypeInfo<SerializeTestClasses::MyClassMix>::GetUuid();
  2782. testObj.m_fieldValues.push_back(valField1);
  2783. Clonable* cloneObj = m_serializeContext->CloneObject(&testObj);
  2784. EXPECT_TRUE(cloneObj);
  2785. EXPECT_EQ( testObj.m_int, cloneObj->m_int );
  2786. EXPECT_EQ( testObj.m_emptyInitText, cloneObj->m_emptyInitText );
  2787. EXPECT_EQ( testObj.m_map, cloneObj->m_map );
  2788. EXPECT_EQ( testObj.m_fieldValues.size(), cloneObj->m_fieldValues.size() );
  2789. EXPECT_TRUE(cloneObj->m_fieldValues[0].m_data);
  2790. EXPECT_TRUE(cloneObj->m_fieldValues[0].m_data != testObj.m_fieldValues[0].m_data);
  2791. EXPECT_TRUE( *reinterpret_cast<SerializeTestClasses::MyClassMix*>(testObj.m_fieldValues[0].m_data) == *reinterpret_cast<SerializeTestClasses::MyClassMix*>(cloneObj->m_fieldValues[0].m_data) );
  2792. delete reinterpret_cast<SerializeTestClasses::MyClassMix*>(cloneObj->m_fieldValues[0].m_data);
  2793. AZ_TEST_ASSERT(cloneObj->m_smartArray[0] && cloneObj->m_smartArray[0]->m_data == 101);
  2794. AZ_TEST_ASSERT(cloneObj->m_smartArray[1] && cloneObj->m_smartArray[1]->m_data == 201);
  2795. AZ_TEST_ASSERT(cloneObj->m_smartArray[2] && cloneObj->m_smartArray[2]->m_data == 301);
  2796. delete cloneObj;
  2797. delete reinterpret_cast<SerializeTestClasses::MyClassMix*>(testObj.m_fieldValues[0].m_data);
  2798. }
  2799. TEST_F(Serialization, CloneInplaceTest)
  2800. {
  2801. using namespace Clone;
  2802. // We must expose the class for serialization first.
  2803. MyClassBase1::Reflect(*m_serializeContext);
  2804. MyClassBase2::Reflect(*m_serializeContext);
  2805. MyClassBase3::Reflect(*m_serializeContext);
  2806. SerializeTestClasses::MyClassMix::Reflect(*m_serializeContext);
  2807. RefCounted::Reflect(*m_serializeContext);
  2808. Clonable::Reflect(*m_serializeContext);
  2809. Clonable testObj;
  2810. testObj.m_int = 100;
  2811. testObj.m_emptyInitText = ""; // set to empty to make sure we write zero values
  2812. testObj.m_map.insert(AZStd::make_pair(1, 2));
  2813. testObj.m_smartArray[0] = aznew RefCounted(101);
  2814. testObj.m_smartArray[1] = aznew RefCounted(201);
  2815. testObj.m_smartArray[2] = aznew RefCounted(301);
  2816. SerializeTestClasses::MyClassMix val1;
  2817. val1.Set(5); // Initialize with some value
  2818. DynamicSerializableField valField1;
  2819. valField1.m_data = &val1;
  2820. valField1.m_typeId = SerializeTypeInfo<SerializeTestClasses::MyClassMix>::GetUuid();
  2821. testObj.m_fieldValues.push_back(valField1);
  2822. Clonable cloneObj;
  2823. m_serializeContext->CloneObjectInplace(cloneObj, &testObj);
  2824. EXPECT_EQ(testObj.m_int, cloneObj.m_int);
  2825. EXPECT_EQ(testObj.m_emptyInitText, cloneObj.m_emptyInitText);
  2826. EXPECT_EQ(testObj.m_map, cloneObj.m_map);
  2827. EXPECT_EQ(testObj.m_fieldValues.size(), cloneObj.m_fieldValues.size());
  2828. EXPECT_TRUE(cloneObj.m_fieldValues[0].m_data);
  2829. EXPECT_TRUE(cloneObj.m_fieldValues[0].m_data != testObj.m_fieldValues[0].m_data);
  2830. EXPECT_TRUE(*reinterpret_cast<SerializeTestClasses::MyClassMix*>(testObj.m_fieldValues[0].m_data) == *reinterpret_cast<SerializeTestClasses::MyClassMix*>(cloneObj.m_fieldValues[0].m_data));
  2831. delete reinterpret_cast<SerializeTestClasses::MyClassMix*>(cloneObj.m_fieldValues[0].m_data);
  2832. AZ_TEST_ASSERT(cloneObj.m_smartArray[0] && cloneObj.m_smartArray[0]->m_data == 101);
  2833. AZ_TEST_ASSERT(cloneObj.m_smartArray[1] && cloneObj.m_smartArray[1]->m_data == 201);
  2834. AZ_TEST_ASSERT(cloneObj.m_smartArray[2] && cloneObj.m_smartArray[2]->m_data == 301);
  2835. delete reinterpret_cast<SerializeTestClasses::MyClassMix*>(testObj.m_fieldValues[0].m_data);
  2836. }
  2837. TEST_F(Serialization, CloneAssociativeContainerOfPointersTest)
  2838. {
  2839. using namespace Clone;
  2840. // We must expose the class for serialization first.
  2841. AZ::Entity::Reflect(m_serializeContext.get());
  2842. ClonableAssociativePointerContainer::Reflect(*m_serializeContext);
  2843. ClonableAssociativePointerContainer testObj;
  2844. testObj.m_setOfPointers.insert(aznew AZ::Entity("Entity1"));
  2845. testObj.m_setOfPointers.insert(aznew AZ::Entity("Entity2"));
  2846. testObj.m_mapOfFloatPointers.emplace(5, azcreate(float, (3.14f), AZ::SystemAllocator));
  2847. testObj.m_sharedEntityPointer.reset(aznew AZ::Entity("Entity3"));
  2848. ClonableAssociativePointerContainer* cloneObj = m_serializeContext->CloneObject(&testObj);
  2849. EXPECT_EQ(testObj.m_setOfPointers.size(), cloneObj->m_setOfPointers.size());
  2850. auto testObjSetBeginIt = testObj.m_setOfPointers.begin();
  2851. auto cloneObjSetBeginIt = cloneObj->m_setOfPointers.begin();
  2852. for (; testObjSetBeginIt != testObj.m_setOfPointers.end(); ++testObjSetBeginIt, ++cloneObjSetBeginIt)
  2853. {
  2854. EXPECT_EQ((*testObjSetBeginIt)->GetId(), (*cloneObjSetBeginIt)->GetId());
  2855. }
  2856. EXPECT_EQ(testObj.m_mapOfFloatPointers.size(), cloneObj->m_mapOfFloatPointers.size());
  2857. auto testObjMapBeginIt = testObj.m_mapOfFloatPointers.begin();
  2858. auto cloneObjMapBeginIt = cloneObj->m_mapOfFloatPointers.begin();
  2859. for (; testObjMapBeginIt != testObj.m_mapOfFloatPointers.end(); ++testObjMapBeginIt, ++cloneObjMapBeginIt)
  2860. {
  2861. EXPECT_EQ(*(testObjMapBeginIt->second), *(cloneObjMapBeginIt->second));
  2862. }
  2863. EXPECT_NE(nullptr, cloneObj->m_sharedEntityPointer.get());
  2864. EXPECT_EQ(testObj.m_sharedEntityPointer->GetId(), cloneObj->m_sharedEntityPointer->GetId());
  2865. //Free the allocated memory
  2866. for (auto& entitySet : { testObj.m_setOfPointers, cloneObj->m_setOfPointers })
  2867. {
  2868. for (AZ::Entity* entityPtr : entitySet)
  2869. {
  2870. delete entityPtr;
  2871. }
  2872. }
  2873. for (auto& intFloatPtrMap : { testObj.m_mapOfFloatPointers, cloneObj->m_mapOfFloatPointers })
  2874. {
  2875. for (auto& intFloatPtrPair : intFloatPtrMap)
  2876. {
  2877. azdestroy(intFloatPtrPair.second);
  2878. }
  2879. }
  2880. delete cloneObj;
  2881. }
  2882. struct TestCloneAssetData
  2883. : public AZ::Data::AssetData
  2884. {
  2885. AZ_CLASS_ALLOCATOR(TestCloneAssetData, AZ::SystemAllocator);
  2886. AZ_RTTI(TestCloneAssetData, "{0BAECA70-262F-4BDC-9D42-B7F7A10077DA}", AZ::Data::AssetData);
  2887. TestCloneAssetData() = default;
  2888. TestCloneAssetData(const AZ::Data::AssetId& assetId, AZ::Data::AssetData::AssetStatus status, uint32_t valueInt = 0)
  2889. : AZ::Data::AssetData(assetId, status)
  2890. , m_valueInt(valueInt)
  2891. {}
  2892. uint32_t m_valueInt{};
  2893. };
  2894. class TestCloneAssetHandler
  2895. : public AZ::Data::AssetHandler
  2896. , public AZ::Data::AssetCatalog
  2897. {
  2898. public:
  2899. AZ_CLASS_ALLOCATOR(TestCloneAssetHandler, AZ::SystemAllocator);
  2900. //////////////////////////////////////////////////////////////////////////
  2901. // AssetHandler
  2902. AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override
  2903. {
  2904. EXPECT_EQ(AzTypeInfo<TestCloneAssetData>::Uuid(), type);
  2905. return aznew TestCloneAssetData(id, AZ::Data::AssetData::AssetStatus::NotLoaded);
  2906. }
  2907. Data::AssetHandler::LoadResult LoadAssetData(
  2908. const AZ::Data::Asset<AZ::Data::AssetData>& asset,
  2909. AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
  2910. [[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB) override
  2911. {
  2912. EXPECT_EQ(AzTypeInfo<TestCloneAssetData>::Uuid(), asset.GetType());
  2913. const size_t assetDataSize = static_cast<size_t>(stream->GetLength());
  2914. EXPECT_EQ(sizeof(TestCloneAssetData::m_valueInt), assetDataSize);
  2915. TestCloneAssetData* cloneAssetData = asset.GetAs<TestCloneAssetData>();
  2916. stream->Read(assetDataSize, &cloneAssetData->m_valueInt);
  2917. return Data::AssetHandler::LoadResult::LoadComplete;
  2918. }
  2919. bool SaveAssetData(const AZ::Data::Asset<AZ::Data::AssetData>& asset, IO::GenericStream* stream) override
  2920. {
  2921. EXPECT_EQ(AzTypeInfo<TestCloneAssetData>::Uuid(), asset.GetType());
  2922. TestCloneAssetData* cloneAssetData = asset.GetAs<TestCloneAssetData>();
  2923. EXPECT_NE(nullptr, cloneAssetData);
  2924. return Save(*cloneAssetData, stream);
  2925. }
  2926. bool Save(const TestCloneAssetData& testCloneAssetData, IO::GenericStream* stream) const
  2927. {
  2928. stream->Write(sizeof(TestCloneAssetData::m_valueInt), &testCloneAssetData.m_valueInt);
  2929. return true;
  2930. }
  2931. void DestroyAsset(AZ::Data::AssetPtr ptr) override
  2932. {
  2933. EXPECT_EQ(AzTypeInfo<TestCloneAssetData>::Uuid(), ptr->GetType());
  2934. delete ptr;
  2935. }
  2936. void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override
  2937. {
  2938. assetTypes.push_back(AzTypeInfo<TestCloneAssetData>::Uuid());
  2939. }
  2940. //////////////////////////////////////////////////////////////////////////
  2941. // AssetCatalog
  2942. // Redirects stream info request for assets to always return stream info needed to load a TestCloneAssetData
  2943. AZ::Data::AssetStreamInfo GetStreamInfoForLoad(const AZ::Data::AssetId&, const AZ::Data::AssetType& type) override
  2944. {
  2945. EXPECT_EQ(AzTypeInfo<TestCloneAssetData>::Uuid(), type);
  2946. AZ::Data::AssetStreamInfo info;
  2947. info.m_dataOffset = 0;
  2948. info.m_streamFlags = AZ::IO::OpenMode::ModeRead;
  2949. info.m_streamName = GetAssetFilename();
  2950. AZStd::string fullName = AZStd::string::format("%s%s", GetAssetFolderPath(), info.m_streamName.data());
  2951. info.m_dataLen = static_cast<size_t>(IO::SystemFile::Length(fullName.c_str()));
  2952. return info;
  2953. }
  2954. AZ::Data::AssetStreamInfo GetStreamInfoForSave(const AZ::Data::AssetId&, const AZ::Data::AssetType& type) override
  2955. {
  2956. EXPECT_EQ(AzTypeInfo<TestCloneAssetData>::Uuid(), type);
  2957. AZ::Data::AssetStreamInfo info;
  2958. info.m_dataOffset = 0;
  2959. info.m_streamFlags = AZ::IO::OpenMode::ModeWrite;
  2960. info.m_streamName = GetAssetFilename();
  2961. AZStd::string fullName = AZStd::string::format("%s%s", GetAssetFolderPath(), info.m_streamName.data());
  2962. info.m_dataLen = static_cast<size_t>(AZ::IO::SystemFile::Length(fullName.c_str()));
  2963. return info;
  2964. }
  2965. static const char* GetAssetFilename()
  2966. {
  2967. return "TestCloneAsset.bin";
  2968. }
  2969. static const char* GetAssetFolderPath()
  2970. {
  2971. return "";
  2972. }
  2973. };
  2974. struct TestCloneWrapperObject
  2975. {
  2976. AZ_TYPE_INFO(TestCloneWrapperObject, "{4BAE1D45-EFFD-4157-9F80-E20239265304}");
  2977. AZ_CLASS_ALLOCATOR(TestCloneWrapperObject, AZ::SystemAllocator);
  2978. static void Reflect(AZ::ReflectContext* reflectContext)
  2979. {
  2980. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
  2981. {
  2982. serializeContext->Class<TestCloneWrapperObject>()
  2983. ->Field("TestCloneAsset", &TestCloneWrapperObject::m_cloneAsset);
  2984. }
  2985. }
  2986. AZ::Data::Asset<TestCloneAssetData> m_cloneAsset;
  2987. };
  2988. class SerializeAssetFixture
  2989. : public LeakDetectionFixture
  2990. {
  2991. public:
  2992. void SetUp() override
  2993. {
  2994. LeakDetectionFixture::SetUp();
  2995. m_prevFileIO = IO::FileIOBase::GetInstance();
  2996. IO::FileIOBase::SetInstance(&m_fileIO);
  2997. m_streamer = aznew IO::Streamer(AZStd::thread_desc{}, StreamerComponent::CreateStreamerStack());
  2998. Interface<IO::IStreamer>::Register(m_streamer);
  2999. m_serializeContext.reset(aznew AZ::SerializeContext());
  3000. TestCloneWrapperObject::Reflect(m_serializeContext.get());
  3001. // create the database
  3002. AZ::Data::AssetManager::Descriptor desc;
  3003. AZ::Data::AssetManager::Create(desc);
  3004. // create and register an asset handler
  3005. AZ::Data::AssetManager::Instance().RegisterHandler(&m_testAssetHandlerAndCatalog, AzTypeInfo<TestCloneAssetData>::Uuid());
  3006. AZ::Data::AssetManager::Instance().RegisterCatalog(&m_testAssetHandlerAndCatalog, AzTypeInfo<TestCloneAssetData>::Uuid());
  3007. CreateTestCloneAsset();
  3008. }
  3009. void TearDown() override
  3010. {
  3011. m_serializeContext->EnableRemoveReflection();
  3012. TestCloneWrapperObject::Reflect(m_serializeContext.get());
  3013. m_serializeContext->DisableRemoveReflection();
  3014. m_serializeContext.reset();
  3015. // destroy the database
  3016. AZ::Data::AssetManager::Instance().UnregisterHandler(&m_testAssetHandlerAndCatalog);
  3017. AZ::Data::AssetManager::Instance().UnregisterCatalog(&m_testAssetHandlerAndCatalog);
  3018. AZ::Data::AssetManager::Destroy();
  3019. Interface<IO::IStreamer>::Unregister(m_streamer);
  3020. delete m_streamer;
  3021. IO::FileIOBase::SetInstance(m_prevFileIO);
  3022. LeakDetectionFixture::TearDown();
  3023. }
  3024. void CreateTestCloneAsset()
  3025. {
  3026. AZ::IO::Path assetFullPath = m_tempDirectory.GetDirectory();
  3027. assetFullPath /= TestCloneAssetHandler::GetAssetFolderPath();
  3028. assetFullPath /= TestCloneAssetHandler::GetAssetFilename();
  3029. AZ::IO::FileIOStream cloneTestFileStream(assetFullPath.c_str(), AZ::IO::OpenMode::ModeWrite);
  3030. TestCloneAssetData testCloneAssetData;
  3031. testCloneAssetData.m_valueInt = 5;
  3032. m_testAssetHandlerAndCatalog.Save(testCloneAssetData, &cloneTestFileStream);
  3033. }
  3034. protected:
  3035. AZ::Test::ScopedAutoTempDirectory m_tempDirectory;
  3036. AZ::IO::FileIOBase* m_prevFileIO{};
  3037. AZ::IO::Streamer* m_streamer{};
  3038. TestFileIOBase m_fileIO;
  3039. TestCloneAssetHandler m_testAssetHandlerAndCatalog;
  3040. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  3041. };
  3042. TEST_F(SerializeAssetFixture, CloneObjectWithAssetReferenceTest)
  3043. {
  3044. static const AZ::Data::AssetId cloneObjectAssetId(AZ::Uuid("{AF338D46-C607-4F2B-8F0B-8828F88EA5F2}"));
  3045. {
  3046. // Create a TestCloneAssetData asset and keep a reference to in the local testCloneAsset variable so that the AssetManager manages the asset
  3047. AZ::Data::Asset<TestCloneAssetData> testCloneAsset = AZ::Data::AssetManager::Instance().CreateAsset(cloneObjectAssetId, AZ::AzTypeInfo<TestCloneAssetData>::Uuid(), AZ::Data::AssetLoadBehavior::Default);
  3048. testCloneAsset.Get()->m_valueInt = 15;
  3049. /* Create a testCloneWrapper object that has its Asset<T> object set to an AssetId, but not to a loaded asset.
  3050. The PreLoad flag is set on the Asset<T> to validate if the SerializeContext::CloneObject function is attempting to load the asset.
  3051. If the SerializeContext::CloneObject is not attempting to load the asset, then the cloned TestCloneWrapperObject m_cloneAsset member
  3052. should have its asset id set to cloneObjectAssetId without the asset being loaded
  3053. */
  3054. TestCloneWrapperObject testObj;
  3055. testObj.m_cloneAsset = AZ::Data::Asset<TestCloneAssetData>(cloneObjectAssetId, AZ::AzTypeInfo<TestCloneAssetData>::Uuid());
  3056. testObj.m_cloneAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
  3057. // the testCloneAsset should have one reference.
  3058. EXPECT_EQ(1, testCloneAsset.Get()->GetUseCount());
  3059. TestCloneWrapperObject clonedTestObj;
  3060. m_serializeContext->CloneObjectInplace(clonedTestObj, &testObj);
  3061. // the testCloneAsset should still be the only reference after the clone
  3062. EXPECT_EQ(1, testCloneAsset.Get()->GetUseCount());
  3063. // The cloned test object should not have AssetData associated with it,
  3064. // but should have the cloneObjectAssetId asset id set on it
  3065. EXPECT_EQ(cloneObjectAssetId, clonedTestObj.m_cloneAsset.GetId());
  3066. ASSERT_EQ(nullptr, clonedTestObj.m_cloneAsset.Get());
  3067. }
  3068. AZ::Data::AssetManager::Instance().DispatchEvents();
  3069. }
  3070. TEST_F(Serialization, CloneMultipleInheritance_RTTIBaseClassDiffererentOrder_KeepsCorrectOffsets)
  3071. {
  3072. using namespace Clone;
  3073. EXPECT_NE(sizeof(ClonableMutlipleInheritanceOrderingA), sizeof(ClonableMutlipleInheritanceOrderingB));
  3074. Clonable::Reflect(*m_serializeContext.get());
  3075. ClonableMutlipleInheritanceOrderingA::Reflect(*m_serializeContext.get());
  3076. ClonableMutlipleInheritanceOrderingB::Reflect(*m_serializeContext.get());
  3077. AZStd::unique_ptr<Clonable> objA(aznew ClonableMutlipleInheritanceOrderingA);
  3078. AZStd::unique_ptr<Clonable> objB(aznew ClonableMutlipleInheritanceOrderingB);
  3079. // sanity check that the pointer offset for the classes being used is different
  3080. const void* aAsBasePtr = AZ::SerializeTypeInfo<Clonable>::RttiCast(objA.get(), AZ::SerializeTypeInfo<Clonable>::GetRttiTypeId(objA.get()));
  3081. const void* bAsBasePtr = AZ::SerializeTypeInfo<Clonable>::RttiCast(objB.get(), AZ::SerializeTypeInfo<Clonable>::GetRttiTypeId(objB.get()));
  3082. AZStd::ptrdiff_t aOffset = (char*)objA.get() - (char*)aAsBasePtr;
  3083. AZStd::ptrdiff_t bOffset = (char*)objB.get() - (char*)bAsBasePtr;
  3084. EXPECT_NE(aOffset, 0);
  3085. EXPECT_EQ(bOffset, 0);
  3086. // Now clone the original objects, and store in the RTTI base type
  3087. AZStd::unique_ptr<Clonable> cloneObjA(m_serializeContext->CloneObject(objA.get()));
  3088. AZStd::unique_ptr<Clonable> cloneObjB(m_serializeContext->CloneObject(objB.get()));
  3089. // Check our pointer offsets are still different in the cloned objects
  3090. const void* aCloneAsBasePtr = AZ::SerializeTypeInfo<Clonable>::RttiCast(cloneObjA.get(), AZ::SerializeTypeInfo<Clonable>::GetRttiTypeId(cloneObjA.get()));
  3091. const void* bCloneAsBasePtr = AZ::SerializeTypeInfo<Clonable>::RttiCast(cloneObjB.get(), AZ::SerializeTypeInfo<Clonable>::GetRttiTypeId(cloneObjB.get()));
  3092. AZStd::ptrdiff_t aCloneOffset = (char*)cloneObjA.get() - (char*)aCloneAsBasePtr;
  3093. AZStd::ptrdiff_t bCloneOffset = (char*)cloneObjB.get() - (char*)bCloneAsBasePtr;
  3094. EXPECT_NE(aCloneOffset, 0);
  3095. EXPECT_EQ(bCloneOffset, 0);
  3096. // Check that offsets are equivalent between the clones and the original objects
  3097. EXPECT_EQ(aCloneOffset, aOffset);
  3098. EXPECT_EQ(bCloneOffset, bOffset);
  3099. m_serializeContext->EnableRemoveReflection();
  3100. ClonableMutlipleInheritanceOrderingB::Reflect(*m_serializeContext.get());
  3101. ClonableMutlipleInheritanceOrderingA::Reflect(*m_serializeContext.get());
  3102. Clonable::Reflect(*m_serializeContext.get());
  3103. m_serializeContext->DisableRemoveReflection();
  3104. }
  3105. // Prove that if a member of a vector of baseclass pointers is unreadable, the container
  3106. // removes the element instead of leaving a null. This is an arbitrary choice (to remove or leave
  3107. // the null) and this test exists just to prove that the chosen way functions as expected.
  3108. TEST_F(Serialization, Clone_UnreadableVectorElements_LeaveNoGaps_Errors)
  3109. {
  3110. using namespace ContainerElementDeprecationTestData;
  3111. // make sure that when a component is deprecated, it is removed during deserialization
  3112. // and does not leave a hole that is a nullptr.
  3113. ClassWithAVectorOfBaseClasses::Reflect(m_serializeContext.get());
  3114. ClassWithAVectorOfBaseClasses vectorContainer;
  3115. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  3116. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  3117. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  3118. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  3119. // (remove it, but without deprecating)
  3120. m_serializeContext->EnableRemoveReflection();
  3121. DerivedClass2::Reflect(m_serializeContext.get());
  3122. m_serializeContext->DisableRemoveReflection();
  3123. // clone it, we expect errors:
  3124. AZ_TEST_START_TRACE_SUPPRESSION;
  3125. ClassWithAVectorOfBaseClasses loadedContainer;
  3126. m_serializeContext->CloneObjectInplace(loadedContainer, &vectorContainer);
  3127. AZ_TEST_STOP_TRACE_SUPPRESSION(2); // 2 classes should have failed and generated warnings/errors
  3128. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses.size(), 2); // we still preserve the ones we CAN read.
  3129. for (auto baseclass : loadedContainer.m_vectorOfBaseClasses)
  3130. {
  3131. // we should only have baseclass1's in there.
  3132. EXPECT_EQ(baseclass->RTTI_GetType(), azrtti_typeid<DerivedClass1>());
  3133. }
  3134. }
  3135. // Prove that if you properly deprecate a member of a vector of baseclass pointers, the container
  3136. // removes the element instead of leaving a null and does not emit an error
  3137. TEST_F(Serialization, Clone_DeprecatedVectorElements_LeaveNoGaps_DoesNotError)
  3138. {
  3139. using namespace ContainerElementDeprecationTestData;
  3140. // make sure that when a component is deprecated, it is removed during deserialization
  3141. // and does not leave a hole that is a nullptr.
  3142. ClassWithAVectorOfBaseClasses::Reflect(m_serializeContext.get());
  3143. ClassWithAVectorOfBaseClasses vectorContainer;
  3144. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  3145. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  3146. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  3147. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  3148. // remove it and properly deprecate it
  3149. m_serializeContext->EnableRemoveReflection();
  3150. DerivedClass2::Reflect(m_serializeContext.get());
  3151. m_serializeContext->DisableRemoveReflection();
  3152. m_serializeContext->ClassDeprecate("Dummy UUID", azrtti_typeid<DerivedClass2>());
  3153. // clone it, we expect no errors:
  3154. ClassWithAVectorOfBaseClasses loadedContainer;
  3155. m_serializeContext->CloneObjectInplace(loadedContainer, &vectorContainer);
  3156. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses.size(), 2); // we still preserve the ones we CAN read.
  3157. for (auto baseclass : loadedContainer.m_vectorOfBaseClasses)
  3158. {
  3159. // we should only have baseclass1's in there.
  3160. EXPECT_EQ(baseclass->RTTI_GetType(), azrtti_typeid<DerivedClass1>());
  3161. }
  3162. }
  3163. // Prove that if you deprecate but upgrade a member of a vector of baseclass pointers, the container
  3164. // Clone actually errors. This behavior differs from serialize and datapatch because you're not
  3165. // expected to even have a deprecated class being cloned in the first place (it should have
  3166. // converted on deserialize or datapatch!)
  3167. TEST_F(Serialization, Clone_DeprecatedVectorElements_ConvertedClass_LeavesGaps_Errors)
  3168. {
  3169. using namespace ContainerElementDeprecationTestData;
  3170. // make sure that when a component is deprecated, it is removed during deserialization
  3171. // and does not leave a hole that is a nullptr.
  3172. ClassWithAVectorOfBaseClasses::Reflect(m_serializeContext.get());
  3173. ClassWithAVectorOfBaseClasses vectorContainer;
  3174. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  3175. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  3176. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  3177. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  3178. // remove it and properly deprecate it with a converter that will upgrade it.
  3179. m_serializeContext->EnableRemoveReflection();
  3180. DerivedClass2::Reflect(m_serializeContext.get());
  3181. m_serializeContext->DisableRemoveReflection();
  3182. m_serializeContext->ClassDeprecate("Dummy UUID", azrtti_typeid<DerivedClass2>(), ConvertDerivedClass2ToDerivedClass3);
  3183. // clone it, we expect no errors:
  3184. ClassWithAVectorOfBaseClasses loadedContainer;
  3185. AZ_TEST_START_TRACE_SUPPRESSION;
  3186. m_serializeContext->CloneObjectInplace(loadedContainer, &vectorContainer);
  3187. AZ_TEST_STOP_TRACE_SUPPRESSION(2); // one for each converter
  3188. ASSERT_EQ(loadedContainer.m_vectorOfBaseClasses.size(), 2); // we still preserve the ones we CAN read.
  3189. // this also proves it does not shuffle elements around.
  3190. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses[0]->RTTI_GetType(), azrtti_typeid<DerivedClass1>());
  3191. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses[1]->RTTI_GetType(), azrtti_typeid<DerivedClass1>());
  3192. }
  3193. struct TestContainerType
  3194. {
  3195. AZ_TYPE_INFO(TestContainerType, "{81F20E9F-3F35-4063-BE29-A22EAF10AF59}");
  3196. int32_t m_value{};
  3197. };
  3198. struct ContainerWrapper
  3199. {
  3200. AZ_TYPE_INFO(ContainerWrapper, "{F4EE9211-CABE-4D28-8356-2C2ADE6E5315}");
  3201. TestContainerType m_testContainer;
  3202. };
  3203. TEST_F(Serialization, Clone_Container_WhereReserveElement_ReturnsNullptr_DoesNotCrash)
  3204. {
  3205. struct EmptyDataContainer
  3206. : AZ::SerializeContext::IDataContainer
  3207. {
  3208. EmptyDataContainer()
  3209. {
  3210. // Create SerializeContext ClassElement for a int32_t type that is not a pointer
  3211. m_classElement.m_name = "Test";
  3212. m_classElement.m_nameCrc = AZ_CRC_CE("Test");
  3213. m_classElement.m_typeId = azrtti_typeid<int32_t>();
  3214. m_classElement.m_dataSize = sizeof(int32_t);
  3215. m_classElement.m_offset = 0;
  3216. m_classElement.m_azRtti = {};
  3217. m_classElement.m_editData = {};
  3218. m_classElement.m_flags = 0;
  3219. }
  3220. const AZ::SerializeContext::ClassElement* GetElement(uint32_t) const override
  3221. {
  3222. return {};
  3223. }
  3224. bool GetElement(AZ::SerializeContext::ClassElement&, const AZ::SerializeContext::DataElement&) const override
  3225. {
  3226. return {};
  3227. }
  3228. void EnumElements(void* instance, const ElementCB& cb) override
  3229. {
  3230. auto dataContainer = reinterpret_cast<TestContainerType*>(instance);
  3231. cb(&dataContainer->m_value, m_classElement.m_typeId, m_classElement.m_genericClassInfo ? m_classElement.m_genericClassInfo->GetClassData() : nullptr, &m_classElement);
  3232. }
  3233. void EnumTypes(const ElementTypeCB& cb) override
  3234. {
  3235. cb(m_classElement.m_typeId, &m_classElement);
  3236. }
  3237. size_t Size(void*) const override
  3238. {
  3239. return {};
  3240. }
  3241. size_t Capacity(void*) const override
  3242. {
  3243. return {};
  3244. }
  3245. bool IsStableElements() const override
  3246. {
  3247. return {};
  3248. }
  3249. bool IsFixedSize() const override
  3250. {
  3251. return {};
  3252. }
  3253. bool IsFixedCapacity() const override
  3254. {
  3255. return {};
  3256. }
  3257. bool IsSmartPointer() const override
  3258. {
  3259. return {};
  3260. }
  3261. bool CanAccessElementsByIndex() const override
  3262. {
  3263. return {};
  3264. }
  3265. void* ReserveElement(void*, const AZ::SerializeContext::ClassElement*) override
  3266. {
  3267. return {};
  3268. }
  3269. void* GetElementByIndex(void*, const AZ::SerializeContext::ClassElement*, size_t) override
  3270. {
  3271. return {};
  3272. }
  3273. void StoreElement([[maybe_unused]] void* instance, [[maybe_unused]] void* element) override
  3274. {}
  3275. bool RemoveElement(void*, const void*, [[maybe_unused]] AZ::SerializeContext* serializeContext) override
  3276. {
  3277. return {};
  3278. }
  3279. size_t RemoveElements(void*, const void**, size_t, [[maybe_unused]] AZ::SerializeContext* serializeContext) override
  3280. {
  3281. return {};
  3282. }
  3283. void ClearElements(void*, AZ::SerializeContext*) override
  3284. {}
  3285. AZ::SerializeContext::ClassElement m_classElement;
  3286. };
  3287. m_serializeContext->Class<TestContainerType>()
  3288. ->DataContainer<EmptyDataContainer>();
  3289. m_serializeContext->Class<ContainerWrapper>()
  3290. ->Field("m_testContainer", &ContainerWrapper::m_testContainer);
  3291. ContainerWrapper expectObject{ {42} };
  3292. ContainerWrapper resultObject;
  3293. AZ_TEST_START_TRACE_SUPPRESSION;
  3294. m_serializeContext->CloneObjectInplace(resultObject, &expectObject);
  3295. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3296. EXPECT_EQ(0, resultObject.m_testContainer.m_value);
  3297. m_serializeContext->EnableRemoveReflection();
  3298. m_serializeContext->Class<TestContainerType>();
  3299. m_serializeContext->Class<ContainerWrapper>();
  3300. m_serializeContext->DisableRemoveReflection();
  3301. }
  3302. /*
  3303. * Error Testing
  3304. */
  3305. namespace Error
  3306. {
  3307. struct UnregisteredClass
  3308. {
  3309. AZ_TYPE_INFO(UnregisteredClass, "{6558CEBC-D764-4E50-BAA0-025BF55FAD15}")
  3310. };
  3311. struct UnregisteredRttiClass
  3312. {
  3313. AZ_RTTI(UnregisteredRttiClass, "{F948E16B-975D-4F23-911E-2AA5758D8B21}");
  3314. virtual ~UnregisteredRttiClass() {}
  3315. };
  3316. struct ChildOfUnregisteredClass
  3317. : public UnregisteredClass
  3318. {
  3319. AZ_TYPE_INFO(ChildOfUnregisteredClass, "{C72CB2C9-7E9A-41EB-8219-5D13B6445AFC}")
  3320. ChildOfUnregisteredClass() {}
  3321. ChildOfUnregisteredClass(SerializeContext& sc)
  3322. {
  3323. sc.Class<ChildOfUnregisteredClass, UnregisteredClass>();
  3324. }
  3325. };
  3326. struct ChildOfUnregisteredRttiClass
  3327. : public UnregisteredRttiClass
  3328. {
  3329. AZ_RTTI(ChildOfUnregisteredRttiClass, "{E58F6984-4C0A-4D1B-B034-FDEF711AB711}", UnregisteredRttiClass);
  3330. ChildOfUnregisteredRttiClass() {}
  3331. ChildOfUnregisteredRttiClass(SerializeContext& sc)
  3332. {
  3333. sc.Class<ChildOfUnregisteredRttiClass, UnregisteredRttiClass>();
  3334. }
  3335. };
  3336. struct UnserializableMembers
  3337. {
  3338. AZ_TYPE_INFO(UnserializableMembers, "{36F0C52A-5CAC-4060-982C-FC9A86D1393A}");
  3339. UnserializableMembers() {}
  3340. UnserializableMembers(SerializeContext& sc)
  3341. : m_childOfUnregisteredRttiBase(sc)
  3342. , m_childOfUnregisteredBase(&m_childOfUnregisteredRttiBase)
  3343. , m_basePtrToGenericChild(&m_unserializableGeneric)
  3344. {
  3345. m_vectorUnregisteredClass.emplace_back();
  3346. m_vectorUnregisteredRttiClass.emplace_back();
  3347. m_vectorUnregisteredRttiBase.push_back(&m_unregisteredRttiMember);
  3348. m_vectorGenericChildPtr.push_back(&m_unserializableGeneric);
  3349. sc.Class<UnserializableMembers>()->
  3350. Field("unregisteredMember", &UnserializableMembers::m_unregisteredMember)->
  3351. Field("unregisteredRttiMember", &UnserializableMembers::m_unregisteredRttiMember)->
  3352. Field("childOfUnregisteredBase", &UnserializableMembers::m_childOfUnregisteredBase)->
  3353. Field("basePtrToGenericChild", &UnserializableMembers::m_basePtrToGenericChild)->
  3354. Field("vectorUnregisteredClass", &UnserializableMembers::m_vectorUnregisteredClass)->
  3355. Field("vectorUnregisteredRttiClass", &UnserializableMembers::m_vectorUnregisteredRttiClass)->
  3356. Field("vectorUnregisteredRttiBase", &UnserializableMembers::m_vectorUnregisteredRttiBase)->
  3357. Field("vectorGenericChildPtr", &UnserializableMembers::m_vectorGenericChildPtr);
  3358. }
  3359. ChildOfUnregisteredRttiClass m_childOfUnregisteredRttiBase;
  3360. GenericChild m_unserializableGeneric;
  3361. UnregisteredClass m_unregisteredMember;
  3362. UnregisteredRttiClass m_unregisteredRttiMember;
  3363. UnregisteredRttiClass* m_childOfUnregisteredBase;
  3364. GenericClass* m_basePtrToGenericChild;
  3365. AZStd::vector<UnregisteredClass> m_vectorUnregisteredClass;
  3366. AZStd::vector<UnregisteredRttiClass> m_vectorUnregisteredRttiClass;
  3367. AZStd::vector<UnregisteredRttiClass*> m_vectorUnregisteredRttiBase;
  3368. AZStd::vector<GenericClass*> m_vectorGenericChildPtr;
  3369. };
  3370. }
  3371. // Tests that reflection of classes with no base types and those with base types will reflect and unreflect
  3372. // as expected using the templated function, Class()
  3373. TEST_F(Serialization, ClassReflectAndUnreflect)
  3374. {
  3375. using namespace SerializeTestClasses;
  3376. m_serializeContext->Class<SerializeTestClasses::MyClassMix>();
  3377. m_serializeContext->Class<BaseRtti>();
  3378. {
  3379. AZStd::vector<AZ::Uuid> foundUuids = m_serializeContext->FindClassId(AZ::Crc32(AzTypeInfo<BaseRtti>::Name()));
  3380. ASSERT_FALSE(foundUuids.empty());
  3381. EXPECT_EQ(foundUuids.size(), 1);
  3382. EXPECT_EQ(foundUuids[0], AZ::Uuid::CreateString("{2581047D-26EC-4969-8354-BA0A4510C51A}"));
  3383. EXPECT_NE(m_serializeContext->FindClassData(azrtti_typeid<BaseRtti>()), nullptr);
  3384. AZStd::any testAnyCreate = m_serializeContext->CreateAny(azrtti_typeid<BaseRtti>());
  3385. EXPECT_FALSE(testAnyCreate.empty());
  3386. EXPECT_TRUE(testAnyCreate.is<BaseRtti>());
  3387. }
  3388. {
  3389. AZStd::vector<AZ::Uuid> foundUuids = m_serializeContext->FindClassId(AZ::Crc32(AzTypeInfo<SerializeTestClasses::MyClassMix>::Name()));
  3390. ASSERT_FALSE(foundUuids.empty());
  3391. EXPECT_EQ(foundUuids.size(), 1);
  3392. EXPECT_EQ(foundUuids[0], AZ::Uuid::CreateString("{A15003C6-797A-41BB-9D21-716DF0678D02}"));
  3393. EXPECT_NE(m_serializeContext->FindClassData(azrtti_typeid<SerializeTestClasses::MyClassMix>()), nullptr);
  3394. AZStd::any testAnyCreate = m_serializeContext->CreateAny(azrtti_typeid<SerializeTestClasses::MyClassMix>());
  3395. EXPECT_FALSE(testAnyCreate.empty());
  3396. EXPECT_TRUE(testAnyCreate.is<SerializeTestClasses::MyClassMix>());
  3397. }
  3398. m_serializeContext->EnableRemoveReflection();
  3399. m_serializeContext->Class<SerializeTestClasses::MyClassMix>();
  3400. m_serializeContext->Class<BaseRtti>();
  3401. m_serializeContext->DisableRemoveReflection();
  3402. {
  3403. AZStd::vector<AZ::Uuid> foundUuids = m_serializeContext->FindClassId(AZ::Crc32(AzTypeInfo<BaseRtti>::Name()));
  3404. EXPECT_TRUE(foundUuids.empty());
  3405. EXPECT_EQ(m_serializeContext->FindClassData(azrtti_typeid<BaseRtti>()), nullptr);
  3406. AZStd::any testAnyCreate = m_serializeContext->CreateAny(azrtti_typeid<BaseRtti>());
  3407. EXPECT_TRUE(testAnyCreate.empty());
  3408. EXPECT_FALSE(testAnyCreate.is<BaseRtti>());
  3409. }
  3410. {
  3411. AZStd::vector<AZ::Uuid> foundUuids = m_serializeContext->FindClassId(AZ::Crc32(AzTypeInfo<SerializeTestClasses::MyClassMix>::Name()));
  3412. EXPECT_TRUE(foundUuids.empty());
  3413. EXPECT_EQ(m_serializeContext->FindClassData(azrtti_typeid<SerializeTestClasses::MyClassMix>()), nullptr);
  3414. AZStd::any testAnyCreate = m_serializeContext->CreateAny(azrtti_typeid<SerializeTestClasses::MyClassMix>());
  3415. EXPECT_TRUE(testAnyCreate.empty());
  3416. EXPECT_FALSE(testAnyCreate.is<SerializeTestClasses::MyClassMix>());
  3417. }
  3418. }
  3419. TEST_F(Serialization, ErrorTest)
  3420. {
  3421. using namespace Error;
  3422. class ErrorTest
  3423. {
  3424. public:
  3425. void SaveObjects(ObjectStream* writer, SerializeContext* sc)
  3426. {
  3427. static int i = 0;
  3428. bool success;
  3429. // test saving root unregistered class
  3430. if (i == 0)
  3431. {
  3432. UnregisteredClass unregisteredClass;
  3433. AZ_TEST_START_TRACE_SUPPRESSION;
  3434. success = writer->WriteClass(&unregisteredClass);
  3435. EXPECT_TRUE(!success);
  3436. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3437. }
  3438. // test saving root unregistered Rtti class
  3439. else if (i == 1)
  3440. {
  3441. UnregisteredRttiClass unregisteredRttiClass;
  3442. AZ_TEST_START_TRACE_SUPPRESSION;
  3443. success = writer->WriteClass(&unregisteredRttiClass);
  3444. EXPECT_TRUE(!success);
  3445. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3446. }
  3447. // test saving root generic class
  3448. else if (i == 2)
  3449. {
  3450. GenericClass genericClass;
  3451. AZ_TEST_START_TRACE_SUPPRESSION;
  3452. success = writer->WriteClass(&genericClass);
  3453. EXPECT_TRUE(!success);
  3454. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3455. }
  3456. // test saving as pointer to unregistered base class with no rtti
  3457. else if (i == 3)
  3458. {
  3459. ChildOfUnregisteredClass childOfUnregisteredClass(*sc);
  3460. AZ_TEST_START_TRACE_SUPPRESSION;
  3461. success = writer->WriteClass(static_cast<UnregisteredClass*>(&childOfUnregisteredClass));
  3462. EXPECT_TRUE(!success);
  3463. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3464. }
  3465. // test saving unserializable members
  3466. else if (i == 4)
  3467. {
  3468. UnserializableMembers badMembers(*sc);
  3469. AZ_TEST_START_TRACE_SUPPRESSION;
  3470. success = writer->WriteClass(&badMembers);
  3471. EXPECT_TRUE(!success);
  3472. AZ_TEST_STOP_TRACE_SUPPRESSION(8); // 1 failure for each member
  3473. }
  3474. i++;
  3475. }
  3476. void run()
  3477. {
  3478. AZStd::vector<char> buffer;
  3479. IO::ByteContainerStream<AZStd::vector<char> > stream(&buffer);
  3480. // test saving root unregistered class
  3481. {
  3482. SerializeContext sc;
  3483. ObjectStream* objStream = ObjectStream::Create(&stream, sc, ObjectStream::ST_XML);
  3484. SaveObjects(objStream, &sc);
  3485. objStream->Finalize();
  3486. }
  3487. // test saving root unregistered Rtti class
  3488. {
  3489. SerializeContext sc;
  3490. ObjectStream* objStream = ObjectStream::Create(&stream, sc, ObjectStream::ST_XML);
  3491. SaveObjects(objStream, &sc);
  3492. objStream->Finalize();
  3493. }
  3494. // test saving root generic class
  3495. {
  3496. SerializeContext sc;
  3497. ObjectStream* objStream = ObjectStream::Create(&stream, sc, ObjectStream::ST_XML);
  3498. SaveObjects(objStream, &sc);
  3499. objStream->Finalize();
  3500. }
  3501. // test saving as pointer to unregistered base class with no rtti
  3502. {
  3503. SerializeContext sc;
  3504. ObjectStream* objStream = ObjectStream::Create(&stream, sc, ObjectStream::ST_XML);
  3505. SaveObjects(objStream, &sc);
  3506. objStream->Finalize();
  3507. }
  3508. // test saving unserializable members
  3509. // errors covered:
  3510. // - unregistered type with no rtti
  3511. // - unregistered type with rtti
  3512. // - pointer to unregistered base with rtti
  3513. // - base pointer pointing to a generic child
  3514. // - vector of unregistered types
  3515. // - vector of unregistered types with rtti
  3516. // - vector of pointers to unregistered base with rtti
  3517. // - vector of base pointers pointing to generic child
  3518. {
  3519. SerializeContext sc;
  3520. ObjectStream* objStream = ObjectStream::Create(&stream, sc, ObjectStream::ST_XML);
  3521. SaveObjects(objStream, &sc);
  3522. objStream->Finalize();
  3523. }
  3524. }
  3525. };
  3526. ErrorTest test;
  3527. test.run();
  3528. }
  3529. namespace EditTest
  3530. {
  3531. struct MyEditStruct
  3532. {
  3533. AZ_TYPE_INFO(MyEditStruct, "{89CCD760-A556-4EDE-98C0-33FD9DD556B9}")
  3534. MyEditStruct()
  3535. : m_data(11)
  3536. , m_specialData(3) {}
  3537. int Foo(int m) { return 5 * m; }
  3538. bool IsShowSpecialData() const { return true; }
  3539. int GetDataOption(int option) { return option * 2; }
  3540. int m_data;
  3541. int m_specialData;
  3542. };
  3543. int MyEditGlobalFunc(int m)
  3544. {
  3545. return 4 * m;
  3546. }
  3547. class MyEditStruct2
  3548. {
  3549. public:
  3550. AZ_TYPE_INFO(MyEditStruct2, "{FFD27958-9856-4CE2-AE13-18878DE5ECE0}");
  3551. MyEditStruct m_myEditStruct;
  3552. };
  3553. class MyEditStruct3
  3554. {
  3555. public:
  3556. enum EditEnum
  3557. {
  3558. ENUM_Test1 = 1,
  3559. ENUM_Test2 = 2,
  3560. ENUM_Test3 = -1,
  3561. ENUM_Test4 = INT_MAX,
  3562. };
  3563. enum class EditEnumClass : AZ::u8
  3564. {
  3565. EEC_1,
  3566. EEC_2,
  3567. EEC_255 = 255,
  3568. };
  3569. public:
  3570. AZ_TYPE_INFO(MyEditStruct3, "{11F859C7-7A15-49C8-8A38-783A1EFC0E06}");
  3571. EditEnum m_enum;
  3572. EditEnum m_enum2;
  3573. EditEnumClass m_enumClass;
  3574. };
  3575. }
  3576. } // namespace UnitTest
  3577. namespace AZ
  3578. {
  3579. AZ_TYPE_INFO_SPECIALIZE(UnitTest::EditTest::MyEditStruct3::EditEnum, "{4AF433C2-055E-4E34-921A-A7D16AB548CA}");
  3580. AZ_TYPE_INFO_SPECIALIZE(UnitTest::EditTest::MyEditStruct3::EditEnumClass, "{4FEC2F0B-A599-4FCD-836B-89E066791793}");
  3581. }
  3582. namespace UnitTest
  3583. {
  3584. TEST_F(Serialization, EditContextTest)
  3585. {
  3586. using namespace EditTest;
  3587. class EditContextTest
  3588. {
  3589. public:
  3590. bool BeginSerializationElement(SerializeContext* sc, void* instance, const SerializeContext::ClassData* classData, const SerializeContext::ClassElement* classElement)
  3591. {
  3592. (void)instance;
  3593. (void)classData;
  3594. (void)classElement;
  3595. if (classElement)
  3596. {
  3597. // if we are a pointer, then we may be pointing to a derived type.
  3598. if (classElement->m_flags & SerializeContext::ClassElement::FLG_POINTER)
  3599. {
  3600. // if dataAddress is a pointer in this case, cast it's value to a void* (or const void*) and dereference to get to the actual class.
  3601. instance = *(void**)(instance);
  3602. if (instance && classElement->m_azRtti)
  3603. {
  3604. AZ::Uuid actualClassId = classElement->m_azRtti->GetActualUuid(instance);
  3605. if (actualClassId != classElement->m_typeId)
  3606. {
  3607. // we are pointing to derived type, adjust class data, uuid and pointer.
  3608. classData = sc->FindClassData(actualClassId);
  3609. if (classData)
  3610. {
  3611. instance = classElement->m_azRtti->Cast(instance, classData->m_azRtti->GetTypeId());
  3612. }
  3613. }
  3614. }
  3615. }
  3616. }
  3617. if (strcmp(classData->m_name, "MyEditStruct") == 0)
  3618. {
  3619. EXPECT_TRUE(classData->m_editData != nullptr);
  3620. EXPECT_EQ( 0, strcmp(classData->m_editData->m_name, "MyEditStruct") );
  3621. EXPECT_EQ( 0, strcmp(classData->m_editData->m_description, "My edit struct class used for ...") );
  3622. EXPECT_EQ( 2, classData->m_editData->m_elements.size() );
  3623. EXPECT_EQ( 0, strcmp(classData->m_editData->m_elements.front().m_description, "Special data group") );
  3624. EXPECT_EQ( 1, classData->m_editData->m_elements.front().m_attributes.size() );
  3625. EXPECT_TRUE(classData->m_editData->m_elements.front().m_attributes[0].first == AZ_CRC_CE("Callback") );
  3626. }
  3627. else if (classElement && classElement->m_editData && strcmp(classElement->m_editData->m_description, "Type") == 0)
  3628. {
  3629. EXPECT_EQ( 2, classElement->m_editData->m_attributes.size() );
  3630. // Number of options attribute
  3631. EXPECT_EQ(classElement->m_editData->m_attributes[0].first, AZ_CRC_CE("NumOptions"));
  3632. Edit::AttributeData<int>* intData = azrtti_cast<Edit::AttributeData<int>*>(classElement->m_editData->m_attributes[0].second);
  3633. EXPECT_TRUE(intData != nullptr);
  3634. EXPECT_EQ( 3, intData->Get(instance) );
  3635. // Get options attribute
  3636. EXPECT_EQ( classElement->m_editData->m_attributes[1].first, AZ_CRC_CE("Options"));
  3637. Edit::AttributeFunction<int(int)>* funcData = azrtti_cast<Edit::AttributeFunction<int(int)>*>(classElement->m_editData->m_attributes[1].second);
  3638. EXPECT_TRUE(funcData != nullptr);
  3639. EXPECT_EQ( 20, funcData->Invoke(instance, 10) );
  3640. }
  3641. return true;
  3642. }
  3643. bool EndSerializationElement()
  3644. {
  3645. return true;
  3646. }
  3647. void run()
  3648. {
  3649. SerializeContext serializeContext;
  3650. // We must expose the class for serialization first.
  3651. serializeContext.Class<MyEditStruct>()->
  3652. Field("data", &MyEditStruct::m_data);
  3653. serializeContext.Class<MyEditStruct2>()->
  3654. Field("m_myEditStruct", &MyEditStruct2::m_myEditStruct);
  3655. serializeContext.Class<MyEditStruct3>()->
  3656. Field("m_enum", &MyEditStruct3::m_enum)->
  3657. Field("m_enum2", &MyEditStruct3::m_enum2)->
  3658. Field("m_enumClass", &MyEditStruct3::m_enumClass);
  3659. // create edit context
  3660. serializeContext.CreateEditContext();
  3661. EditContext* editContext = serializeContext.GetEditContext();
  3662. // reflect the class for editing
  3663. editContext->Class<MyEditStruct>("MyEditStruct", "My edit struct class used for ...")->
  3664. ClassElement(AZ::Edit::ClassElements::Group, "Special data group")->
  3665. Attribute("Callback", &MyEditStruct::IsShowSpecialData)->
  3666. DataElement("ComboSelector", &MyEditStruct::m_data, "Name", "Type")->
  3667. Attribute("NumOptions", 3)->
  3668. Attribute("Options", &MyEditStruct::GetDataOption);
  3669. // reflect class by using the element edit reflection as name/descriptor
  3670. editContext->Class<MyEditStruct2>("MyEditStruct2", "My edit struct class 2 with redirected data element...")->
  3671. DataElement("ComboSelector", &MyEditStruct2::m_myEditStruct)->
  3672. Attribute("NumOptions", 3);
  3673. // enumerate elements and verify the class reflection..
  3674. MyEditStruct myObj;
  3675. serializeContext.EnumerateObject(&myObj,
  3676. AZStd::bind(&EditContextTest::BeginSerializationElement, this, &serializeContext, AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::placeholders::_3),
  3677. AZStd::bind(&EditContextTest::EndSerializationElement, this),
  3678. SerializeContext::ENUM_ACCESS_FOR_READ);
  3679. editContext->Enum<MyEditStruct3::EditEnum>("EditEnum", "The enum for testing the Enum<>() call")->
  3680. Value("Test1", MyEditStruct3::EditEnum::ENUM_Test1)->
  3681. Value("Test2", MyEditStruct3::EditEnum::ENUM_Test2)->
  3682. Value("Test3", MyEditStruct3::EditEnum::ENUM_Test3)->
  3683. Value("Test4", MyEditStruct3::EditEnum::ENUM_Test4);
  3684. editContext->Enum<MyEditStruct3::EditEnumClass>("EditEnumClass", "The enum class for testing the Enum<>() call")->
  3685. Value("One", MyEditStruct3::EditEnumClass::EEC_1)->
  3686. Value("Two", MyEditStruct3::EditEnumClass::EEC_2)->
  3687. Value("TwoFiftyFive", MyEditStruct3::EditEnumClass::EEC_255);
  3688. AZ_TEST_START_TRACE_SUPPRESSION;
  3689. editContext->Class<MyEditStruct3>("MyEditStruct3", "Used to test enum global reflection")->
  3690. DataElement("Enum", &MyEditStruct3::m_enum)-> // safe
  3691. DataElement("Enum2", &MyEditStruct3::m_enum2)-> // safe
  3692. EnumAttribute(MyEditStruct3::EditEnum::ENUM_Test1, "THIS SHOULD CAUSE AN ERROR")->
  3693. Attribute(AZ::Edit::Attributes::EnumValues, AZStd::vector<AZ::Edit::EnumConstant<MyEditStruct3::EditEnum>> {
  3694. AZ::Edit::EnumConstant<MyEditStruct3::EditEnum>(MyEditStruct3::EditEnum::ENUM_Test1, "EnumTest1 - ERROR"),
  3695. AZ::Edit::EnumConstant<MyEditStruct3::EditEnum>(MyEditStruct3::EditEnum::ENUM_Test2, "EnumTest2 - ERROR"),
  3696. AZ::Edit::EnumConstant<MyEditStruct3::EditEnum>(MyEditStruct3::EditEnum::ENUM_Test3, "EnumTest3 - ERROR"),
  3697. AZ::Edit::EnumConstant<MyEditStruct3::EditEnum>(MyEditStruct3::EditEnum::ENUM_Test4, "EnumTest4 - ERROR"),
  3698. })->
  3699. ElementAttribute(AZ::Edit::InternalAttributes::EnumValue, AZStd::make_pair(MyEditStruct3::EditEnum::ENUM_Test1, "THIS SHOULD ALSO CAUSE AN ERROR"));
  3700. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  3701. }
  3702. };
  3703. EditContextTest test;
  3704. test.run();
  3705. }
  3706. /**
  3707. * Test cases when (usually with DLLs) we have to unload parts of the reflected context
  3708. */
  3709. TEST_F(Serialization, UnregisterTest)
  3710. {
  3711. using namespace EditTest;
  3712. auto reflectClasses = [](SerializeContext* context)
  3713. {
  3714. context->Class<MyEditStruct>()->
  3715. Field("data", &MyEditStruct::m_data);
  3716. };
  3717. SerializeContext serializeContext;
  3718. // Register class
  3719. reflectClasses(&serializeContext);
  3720. // enumerate elements and verify the class reflection..
  3721. MyEditStruct myObj;
  3722. EXPECT_TRUE(serializeContext.FindClassData(AzTypeInfo<MyEditStruct>::Uuid()) != nullptr);
  3723. EXPECT_EQ( 0, strcmp(serializeContext.FindClassData(AzTypeInfo<MyEditStruct>::Uuid())->m_name, "MyEditStruct") );
  3724. // remove the class from the context
  3725. serializeContext.EnableRemoveReflection();
  3726. reflectClasses(&serializeContext);
  3727. serializeContext.DisableRemoveReflection();
  3728. EXPECT_EQ( nullptr, serializeContext.FindClassData(AzTypeInfo<MyEditStruct>::Uuid()) );
  3729. // Register class again
  3730. reflectClasses(&serializeContext);
  3731. EXPECT_EQ( nullptr, serializeContext.FindClassData(AzTypeInfo<MyEditStruct>::Uuid())->m_editData ); // no edit data yet
  3732. // create edit context
  3733. serializeContext.CreateEditContext();
  3734. EditContext* editContext = serializeContext.GetEditContext();
  3735. // reflect the class for editing
  3736. editContext->Class<MyEditStruct>("MyEditStruct", "My edit struct class used for ...")->
  3737. ClassElement(AZ::Edit::ClassElements::Group, "Special data group")->
  3738. Attribute("Callback", &MyEditStruct::IsShowSpecialData)->
  3739. DataElement("ComboSelector", &MyEditStruct::m_data, "Name", "Type")->
  3740. Attribute("NumOptions", 3)->
  3741. Attribute("Options", &MyEditStruct::GetDataOption);
  3742. editContext->Enum<MyEditStruct3::EditEnumClass>("Load Type", "Automatic or Manual loading and unloading")
  3743. ->Value("EEC_1", MyEditStruct3::EditEnumClass::EEC_1)
  3744. ->Value("EEC_2", MyEditStruct3::EditEnumClass::EEC_2)
  3745. ->Value("EEC_255", MyEditStruct3::EditEnumClass::EEC_255);
  3746. EXPECT_TRUE(serializeContext.FindClassData(AzTypeInfo<MyEditStruct>::Uuid())->m_editData != nullptr);
  3747. EXPECT_EQ( 0, strcmp(serializeContext.FindClassData(AzTypeInfo<MyEditStruct>::Uuid())->m_editData->m_name, "MyEditStruct") );
  3748. // remove the class from the context
  3749. serializeContext.EnableRemoveReflection();
  3750. reflectClasses(&serializeContext);
  3751. serializeContext.DisableRemoveReflection();
  3752. EXPECT_EQ( nullptr, serializeContext.FindClassData(AzTypeInfo<MyEditStruct>::Uuid()) );
  3753. }
  3754. namespace LargeData
  3755. {
  3756. class InnerPayload
  3757. {
  3758. public:
  3759. AZ_CLASS_ALLOCATOR(InnerPayload, AZ::SystemAllocator);
  3760. AZ_RTTI(InnerPayload, "{3423157C-C6C5-4914-BB5C-B656439B8D3D}");
  3761. AZStd::string m_textData;
  3762. InnerPayload()
  3763. {
  3764. m_textData = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sed pellentesque nibh. Mauris ac ipsum ante. Mauris dignissim vehicula dui, et mollis mauris tincidunt non. Aliquam sodales diam ante, in vestibulum nibh ultricies et. Pellentesque accumsan porta vulputate. Donec vel fringilla sem. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam eu erat eu est mollis condimentum ut eget metus."
  3765. "Sed nec felis enim.Ut auctor arcu nec tristique volutpat.Nulla viverra vulputate nibh et fringilla.Curabitur sagittis eu libero ullamcorper porta.Ut ac nisi vitae massa luctus tristique.Donec scelerisque, odio at pharetra consectetur, nunc urna porta ligula, tincidunt auctor orci purus non nisi.Nulla at risus at lacus vestibulum varius vitae ac tellus.Etiam ut sem commodo justo tempor congue vel id odio.Duis erat sem, condimentum a neque id, bibendum consectetur ligula.In eget massa lectus.Interdum et malesuada fames ac ante ipsum primis in faucibus.Ut ornare lectus at sem condimentum gravida vel ut est."
  3766. "Curabitur nisl metus, euismod in enim eu, pulvinar ullamcorper lorem.Morbi et adipiscing nisi.Aliquam id dapibus sapien.Aliquam facilisis, lacus porta interdum mattis, erat metus tempus ligula, nec cursus augue tellus ut urna.Sed sagittis arcu vel magna consequat, eget eleifend quam tincidunt.Maecenas non ornare nisi, placerat ornare orci.Proin auctor in nunc eu ultrices.Vivamus interdum imperdiet sapien nec cursus."
  3767. "Etiam et iaculis tortor.Nam lacus risus, rutrum a mollis quis, accumsan quis risus.Mauris ac fringilla lectus.Cras posuere massa ultricies libero fermentum, in convallis metus porttitor.Duis hendrerit gravida neque at ultricies.Vestibulum semper congue gravida.Etiam vel mi quis risus ornare convallis nec et elit.Praesent a mollis erat, in eleifend libero.Fusce porttitor malesuada velit, nec pharetra justo rutrum sit amet.Ut vel egestas lacus, sit amet posuere nunc."
  3768. "Maecenas in eleifend risus.Integer volutpat sodales massa vitae consequat.Cras urna turpis, laoreet sed ante sit amet, dictum commodo sem.Vivamus porta, neque vel blandit dictum, enim metus molestie nisl, a consectetur libero odio eu magna.Maecenas nisi nibh, dignissim et nisi eget, adipiscing auctor ligula.Sed in nisl libero.Maecenas aliquam urna orci, ac ultrices massa sollicitudin vitae.Donec ullamcorper suscipit viverra.Praesent dolor ipsum, tincidunt eu quam sit amet, aliquam cursus orci.Praesent elementum est sit amet lectus imperdiet interdum.Pellentesque et sem et nulla tempus cursus.Sed enim dolor, viverra eu mauris id, ornare congue urna."
  3769. "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sed pellentesque nibh. Mauris ac ipsum ante. Mauris dignissim vehicula dui, et mollis mauris tincidunt non. Aliquam sodales diam ante, in vestibulum nibh ultricies et. Pellentesque accumsan porta vulputate. Donec vel fringilla sem. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam eu erat eu est mollis condimentum ut eget metus."
  3770. "Sed nec felis enim.Ut auctor arcu nec tristique volutpat.Nulla viverra vulputate nibh et fringilla.Curabitur sagittis eu libero ullamcorper porta.Ut ac nisi vitae massa luctus tristique.Donec scelerisque, odio at pharetra consectetur, nunc urna porta ligula, tincidunt auctor orci purus non nisi.Nulla at risus at lacus vestibulum varius vitae ac tellus.Etiam ut sem commodo justo tempor congue vel id odio.Duis erat sem, condimentum a neque id, bibendum consectetur ligula.In eget massa lectus.Interdum et malesuada fames ac ante ipsum primis in faucibus.Ut ornare lectus at sem condimentum gravida vel ut est."
  3771. "Curabitur nisl metus, euismod in enim eu, pulvinar ullamcorper lorem.Morbi et adipiscing nisi.Aliquam id dapibus sapien.Aliquam facilisis, lacus porta interdum mattis, erat metus tempus ligula, nec cursus augue tellus ut urna.Sed sagittis arcu vel magna consequat, eget eleifend quam tincidunt.Maecenas non ornare nisi, placerat ornare orci.Proin auctor in nunc eu ultrices.Vivamus interdum imperdiet sapien nec cursus."
  3772. "Etiam et iaculis tortor.Nam lacus risus, rutrum a mollis quis, accumsan quis risus.Mauris ac fringilla lectus.Cras posuere massa ultricies libero fermentum, in convallis metus porttitor.Duis hendrerit gravida neque at ultricies.Vestibulum semper congue gravida.Etiam vel mi quis risus ornare convallis nec et elit.Praesent a mollis erat, in eleifend libero.Fusce porttitor malesuada velit, nec pharetra justo rutrum sit amet.Ut vel egestas lacus, sit amet posuere nunc."
  3773. "Maecenas in eleifend risus.Integer volutpat sodales massa vitae consequat.Cras urna turpis, laoreet sed ante sit amet, dictum commodo sem.Vivamus porta, neque vel blandit dictum, enim metus molestie nisl, a consectetur libero odio eu magna.Maecenas nisi nibh, dignissim et nisi eget, adipiscing auctor ligula.Sed in nisl libero.Maecenas aliquam urna orci, ac ultrices massa sollicitudin vitae.Donec ullamcorper suscipit viverra.Praesent dolor ipsum, tincidunt eu quam sit amet, aliquam cursus orci.Praesent elementum est sit amet lectus imperdiet interdum.Pellentesque et sem et nulla tempus cursus.Sed enim dolor, viverra eu mauris id, ornare congue urna."
  3774. ;
  3775. }
  3776. virtual ~InnerPayload()
  3777. {}
  3778. static void Reflect(AZ::SerializeContext& sc)
  3779. {
  3780. sc.Class<InnerPayload>()->
  3781. Version(5, &InnerPayload::ConvertOldVersions)->
  3782. Field("m_textData", &InnerPayload::m_textData)
  3783. ;
  3784. }
  3785. static bool ConvertOldVersions(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  3786. {
  3787. (void)context;
  3788. (void)classElement;
  3789. return false;
  3790. }
  3791. };
  3792. class Payload
  3793. {
  3794. public:
  3795. AZ_CLASS_ALLOCATOR(Payload, AZ::SystemAllocator);
  3796. AZ_RTTI(Payload, "{7A14FC65-44FB-4956-B5BC-4CFCBF36E1AE}");
  3797. AZStd::string m_textData;
  3798. AZStd::string m_newTextData;
  3799. InnerPayload m_payload;
  3800. SerializeContext m_context;
  3801. Payload()
  3802. {
  3803. m_textData = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sed pellentesque nibh. Mauris ac ipsum ante. Mauris dignissim vehicula dui, et mollis mauris tincidunt non. Aliquam sodales diam ante, in vestibulum nibh ultricies et. Pellentesque accumsan porta vulputate. Donec vel fringilla sem. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam eu erat eu est mollis condimentum ut eget metus."
  3804. "Sed nec felis enim.Ut auctor arcu nec tristique volutpat.Nulla viverra vulputate nibh et fringilla.Curabitur sagittis eu libero ullamcorper porta.Ut ac nisi vitae massa luctus tristique.Donec scelerisque, odio at pharetra consectetur, nunc urna porta ligula, tincidunt auctor orci purus non nisi.Nulla at risus at lacus vestibulum varius vitae ac tellus.Etiam ut sem commodo justo tempor congue vel id odio.Duis erat sem, condimentum a neque id, bibendum consectetur ligula.In eget massa lectus.Interdum et malesuada fames ac ante ipsum primis in faucibus.Ut ornare lectus at sem condimentum gravida vel ut est."
  3805. "Curabitur nisl metus, euismod in enim eu, pulvinar ullamcorper lorem.Morbi et adipiscing nisi.Aliquam id dapibus sapien.Aliquam facilisis, lacus porta interdum mattis, erat metus tempus ligula, nec cursus augue tellus ut urna.Sed sagittis arcu vel magna consequat, eget eleifend quam tincidunt.Maecenas non ornare nisi, placerat ornare orci.Proin auctor in nunc eu ultrices.Vivamus interdum imperdiet sapien nec cursus."
  3806. "Etiam et iaculis tortor.Nam lacus risus, rutrum a mollis quis, accumsan quis risus.Mauris ac fringilla lectus.Cras posuere massa ultricies libero fermentum, in convallis metus porttitor.Duis hendrerit gravida neque at ultricies.Vestibulum semper congue gravida.Etiam vel mi quis risus ornare convallis nec et elit.Praesent a mollis erat, in eleifend libero.Fusce porttitor malesuada velit, nec pharetra justo rutrum sit amet.Ut vel egestas lacus, sit amet posuere nunc."
  3807. "Maecenas in eleifend risus.Integer volutpat sodales massa vitae consequat.Cras urna turpis, laoreet sed ante sit amet, dictum commodo sem.Vivamus porta, neque vel blandit dictum, enim metus molestie nisl, a consectetur libero odio eu magna.Maecenas nisi nibh, dignissim et nisi eget, adipiscing auctor ligula.Sed in nisl libero.Maecenas aliquam urna orci, ac ultrices massa sollicitudin vitae.Donec ullamcorper suscipit viverra.Praesent dolor ipsum, tincidunt eu quam sit amet, aliquam cursus orci.Praesent elementum est sit amet lectus imperdiet interdum.Pellentesque et sem et nulla tempus cursus.Sed enim dolor, viverra eu mauris id, ornare congue urna."
  3808. "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sed pellentesque nibh. Mauris ac ipsum ante. Mauris dignissim vehicula dui, et mollis mauris tincidunt non. Aliquam sodales diam ante, in vestibulum nibh ultricies et. Pellentesque accumsan porta vulputate. Donec vel fringilla sem. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam eu erat eu est mollis condimentum ut eget metus."
  3809. "Sed nec felis enim.Ut auctor arcu nec tristique volutpat.Nulla viverra vulputate nibh et fringilla.Curabitur sagittis eu libero ullamcorper porta.Ut ac nisi vitae massa luctus tristique.Donec scelerisque, odio at pharetra consectetur, nunc urna porta ligula, tincidunt auctor orci purus non nisi.Nulla at risus at lacus vestibulum varius vitae ac tellus.Etiam ut sem commodo justo tempor congue vel id odio.Duis erat sem, condimentum a neque id, bibendum consectetur ligula.In eget massa lectus.Interdum et malesuada fames ac ante ipsum primis in faucibus.Ut ornare lectus at sem condimentum gravida vel ut est."
  3810. "Curabitur nisl metus, euismod in enim eu, pulvinar ullamcorper lorem.Morbi et adipiscing nisi.Aliquam id dapibus sapien.Aliquam facilisis, lacus porta interdum mattis, erat metus tempus ligula, nec cursus augue tellus ut urna.Sed sagittis arcu vel magna consequat, eget eleifend quam tincidunt.Maecenas non ornare nisi, placerat ornare orci.Proin auctor in nunc eu ultrices.Vivamus interdum imperdiet sapien nec cursus."
  3811. "Etiam et iaculis tortor.Nam lacus risus, rutrum a mollis quis, accumsan quis risus.Mauris ac fringilla lectus.Cras posuere massa ultricies libero fermentum, in convallis metus porttitor.Duis hendrerit gravida neque at ultricies.Vestibulum semper congue gravida.Etiam vel mi quis risus ornare convallis nec et elit.Praesent a mollis erat, in eleifend libero.Fusce porttitor malesuada velit, nec pharetra justo rutrum sit amet.Ut vel egestas lacus, sit amet posuere nunc."
  3812. "Maecenas in eleifend risus.Integer volutpat sodales massa vitae consequat.Cras urna turpis, laoreet sed ante sit amet, dictum commodo sem.Vivamus porta, neque vel blandit dictum, enim metus molestie nisl, a consectetur libero odio eu magna.Maecenas nisi nibh, dignissim et nisi eget, adipiscing auctor ligula.Sed in nisl libero.Maecenas aliquam urna orci, ac ultrices massa sollicitudin vitae.Donec ullamcorper suscipit viverra.Praesent dolor ipsum, tincidunt eu quam sit amet, aliquam cursus orci.Praesent elementum est sit amet lectus imperdiet interdum.Pellentesque et sem et nulla tempus cursus.Sed enim dolor, viverra eu mauris id, ornare congue urna."
  3813. ;
  3814. }
  3815. virtual ~Payload() {}
  3816. static bool ConvertOldVersions(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  3817. {
  3818. (void)classElement;
  3819. (void)context;
  3820. if (classElement.GetVersion() == 4)
  3821. {
  3822. // convert from version 0
  3823. AZStd::string newData;
  3824. for (int i = 0; i < classElement.GetNumSubElements(); ++i)
  3825. {
  3826. AZ::SerializeContext::DataElementNode& elementNode = classElement.GetSubElement(i);
  3827. if (elementNode.GetName() == AZ_CRC_CE("m_textData"))
  3828. {
  3829. bool result = elementNode.GetData(newData);
  3830. EXPECT_TRUE(result);
  3831. classElement.RemoveElement(i);
  3832. break;
  3833. }
  3834. }
  3835. for (int i = 0; i < classElement.GetNumSubElements(); ++i)
  3836. {
  3837. AZ::SerializeContext::DataElementNode& elementNode = classElement.GetSubElement(i);
  3838. if (elementNode.GetName() == AZ_CRC_CE("m_newTextData"))
  3839. {
  3840. elementNode.SetData(context, newData);
  3841. break;
  3842. }
  3843. }
  3844. return true;
  3845. }
  3846. return false; // just discard unknown versions
  3847. }
  3848. static void Reflect(AZ::SerializeContext& sc)
  3849. {
  3850. sc.Class<Payload>()->
  3851. Version(5, &Payload::ConvertOldVersions)->
  3852. Field("m_textData", &Payload::m_textData)->
  3853. Field("m_newTextData", &Payload::m_newTextData)->
  3854. Field("m_payload", &Payload::m_payload)
  3855. ;
  3856. }
  3857. void SaveObjects(ObjectStream* writer)
  3858. {
  3859. bool success = true;
  3860. success = writer->WriteClass(this);
  3861. EXPECT_TRUE(success);
  3862. }
  3863. void TestSave(IO::GenericStream* stream, ObjectStream::StreamType format)
  3864. {
  3865. ObjectStream* objStream = ObjectStream::Create(stream, m_context, format);
  3866. SaveObjects(objStream);
  3867. bool done = objStream->Finalize();
  3868. EXPECT_TRUE(done);
  3869. }
  3870. };
  3871. }
  3872. /*
  3873. * Test serialization using FileUtil.
  3874. * FileUtil interacts with the serialization context through the ComponentApplicationBus.
  3875. */
  3876. class SerializationFileUtil
  3877. : public Serialization
  3878. {
  3879. public:
  3880. void SetUp() override
  3881. {
  3882. Serialization::SetUp();
  3883. m_prevFileIO = AZ::IO::FileIOBase::GetInstance();
  3884. AZ::IO::FileIOBase::SetInstance(&m_fileIO);
  3885. BaseRtti::Reflect(*m_serializeContext);
  3886. }
  3887. void TearDown() override
  3888. {
  3889. AZ::IO::FileIOBase::SetInstance(m_prevFileIO);
  3890. Serialization::TearDown();
  3891. }
  3892. void TestFileUtilsStream(AZ::DataStream::StreamType streamType)
  3893. {
  3894. BaseRtti toSerialize;
  3895. toSerialize.m_data = false;
  3896. // Test Stream Write
  3897. AZStd::vector<char> charBuffer;
  3898. IO::ByteContainerStream<AZStd::vector<char> > charStream(&charBuffer);
  3899. bool success = AZ::Utils::SaveObjectToStream(charStream, streamType, &toSerialize);
  3900. EXPECT_TRUE(success);
  3901. // Test Stream Read
  3902. // Set the stream to the beginning so what was written can be read.
  3903. charStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  3904. BaseRtti* deserialized = AZ::Utils::LoadObjectFromStream<BaseRtti>(charStream);
  3905. EXPECT_TRUE(deserialized);
  3906. EXPECT_EQ( toSerialize.m_data, deserialized->m_data );
  3907. delete deserialized;
  3908. deserialized = nullptr;
  3909. // Test LoadObjectFromBuffer
  3910. // First, save the object to a u8 buffer.
  3911. AZStd::vector<u8> u8Buffer;
  3912. IO::ByteContainerStream<AZStd::vector<u8> > u8Stream(&u8Buffer);
  3913. success = AZ::Utils::SaveObjectToStream(u8Stream, streamType, &toSerialize);
  3914. EXPECT_TRUE(success);
  3915. u8Stream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  3916. deserialized = AZ::Utils::LoadObjectFromBuffer<BaseRtti>(&u8Buffer[0], u8Buffer.size());
  3917. EXPECT_TRUE(deserialized);
  3918. EXPECT_EQ( toSerialize.m_data, deserialized->m_data );
  3919. delete deserialized;
  3920. deserialized = nullptr;
  3921. // Write to stream twice, read once.
  3922. // Note that subsequent calls to write to stream will be ignored.
  3923. // Note that many asserts here are commented out because the stream functionality was giving
  3924. // unexpected results. There are rally stories on the backlog backlog (I e-mailed someone to put them on the backlog)
  3925. // related to this.
  3926. AZStd::vector<char> charBufferWriteTwice;
  3927. IO::ByteContainerStream<AZStd::vector<char> > charStreamWriteTwice(&charBufferWriteTwice);
  3928. success = AZ::Utils::SaveObjectToStream(charStreamWriteTwice, streamType, &toSerialize);
  3929. EXPECT_TRUE(success);
  3930. BaseRtti secondSerializedObject;
  3931. secondSerializedObject.m_data = true;
  3932. success = AZ::Utils::SaveObjectToStream(charStreamWriteTwice, streamType, &secondSerializedObject);
  3933. // SaveObjectToStream currently returns success after attempting to save a second object.
  3934. // This does not match up with the later behavior of loading from this stream.
  3935. // Currently, saving twice returns a success on each save, and loading once returns the first object.
  3936. // What should happen, is either the attempt to save onto the stream again should return false,
  3937. // or the read should return the second object first.
  3938. //EXPECT_TRUE(success);
  3939. charStreamWriteTwice.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  3940. deserialized = AZ::Utils::LoadObjectFromStream<BaseRtti>(charStreamWriteTwice);
  3941. EXPECT_TRUE(deserialized);
  3942. // Read the above text. This is here for whoever addresses these backlog items.
  3943. //EXPECT_EQ( toSerialize.m_data, deserialized->m_data );
  3944. //EXPECT_EQ( secondSerializedObject.m_data, deserialized->m_data );
  3945. delete deserialized;
  3946. deserialized = nullptr;
  3947. }
  3948. void TestFileUtilsFile(AZ::DataStream::StreamType streamType)
  3949. {
  3950. BaseRtti toSerialize;
  3951. toSerialize.m_data = false;
  3952. // Test save once, read once.
  3953. AZ::IO::Path filePath = GetTestFolderPath() / "FileUtilsTest";
  3954. bool success = AZ::Utils::SaveObjectToFile(filePath.Native(), streamType, &toSerialize);
  3955. EXPECT_TRUE(success);
  3956. BaseRtti* deserialized = AZ::Utils::LoadObjectFromFile<BaseRtti>(filePath.Native());
  3957. EXPECT_TRUE(deserialized);
  3958. EXPECT_EQ( toSerialize.m_data, deserialized->m_data );
  3959. delete deserialized;
  3960. deserialized = nullptr;
  3961. // Test save twice, read once.
  3962. // This is valid with files because saving a file again will overwrite it. Note that streams function differently.
  3963. success = AZ::Utils::SaveObjectToFile(filePath.Native(), streamType, &toSerialize);
  3964. EXPECT_TRUE(success);
  3965. success = AZ::Utils::SaveObjectToFile(filePath.Native(), streamType, &toSerialize);
  3966. EXPECT_TRUE(success);
  3967. deserialized = AZ::Utils::LoadObjectFromFile<BaseRtti>(filePath.Native());
  3968. EXPECT_TRUE(deserialized);
  3969. EXPECT_EQ( toSerialize.m_data, deserialized->m_data );
  3970. delete deserialized;
  3971. deserialized = nullptr;
  3972. // Test reading from an invalid file. The system should return 'nullptr' when given a bad file path.
  3973. AZ::IO::SystemFile::Delete(filePath.c_str());
  3974. deserialized = AZ::Utils::LoadObjectFromFile<BaseRtti>(filePath.Native());
  3975. EXPECT_EQ(nullptr, deserialized);
  3976. }
  3977. TestFileIOBase m_fileIO;
  3978. AZ::IO::FileIOBase* m_prevFileIO;
  3979. };
  3980. TEST_F(SerializationFileUtil, TestFileUtilsStream_XML)
  3981. {
  3982. TestFileUtilsStream(ObjectStream::ST_XML);
  3983. }
  3984. TEST_F(SerializationFileUtil, TestFileUtilsStream_Binary)
  3985. {
  3986. TestFileUtilsStream(ObjectStream::ST_BINARY);
  3987. }
  3988. TEST_F(SerializationFileUtil, DISABLED_TestFileUtilsFile_XML)
  3989. {
  3990. TestFileUtilsFile(ObjectStream::ST_XML);
  3991. }
  3992. TEST_F(SerializationFileUtil, DISABLED_TestFileUtilsFile_Binary)
  3993. {
  3994. TestFileUtilsFile(ObjectStream::ST_BINARY);
  3995. }
  3996. /*
  3997. *
  3998. */
  3999. class SerializeDescendentDataElementTest
  4000. : public LeakDetectionFixture
  4001. {
  4002. public:
  4003. struct DataElementTestClass
  4004. {
  4005. AZ_CLASS_ALLOCATOR(DataElementTestClass, AZ::SystemAllocator);
  4006. AZ_TYPE_INFO(DataElementTestClass, "{F515B922-BBB9-4216-A2C9-FD665AA30046}");
  4007. DataElementTestClass() {}
  4008. AZStd::unique_ptr<AZ::Entity> m_data;
  4009. AZStd::vector<AZ::Vector2> m_positions;
  4010. private:
  4011. DataElementTestClass(const DataElementTestClass&) = delete;
  4012. };
  4013. void SetUp() override
  4014. {
  4015. LeakDetectionFixture::SetUp();
  4016. m_dataElementClass = AZStd::make_unique<DataElementTestClass>();
  4017. }
  4018. void TearDown() override
  4019. {
  4020. m_dataElementClass.reset(); // reset it before the allocators are destroyed
  4021. LeakDetectionFixture::TearDown();
  4022. }
  4023. static bool VersionConverter(AZ::SerializeContext& sc, AZ::SerializeContext::DataElementNode& classElement)
  4024. {
  4025. if (classElement.GetVersion() == 0)
  4026. {
  4027. auto entityIdElements = AZ::Utils::FindDescendantElements(sc, classElement, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("m_data"), AZ_CRC_CE("element"), AZ_CRC_CE("Id"), AZ_CRC_CE("id") }));
  4028. EXPECT_EQ(1, entityIdElements.size());
  4029. AZ::u64 id1;
  4030. EXPECT_TRUE(entityIdElements.front()->GetData(id1));
  4031. EXPECT_EQ(47, id1);
  4032. auto vector2Elements = AZ::Utils::FindDescendantElements(sc, classElement, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("m_positions"), AZ_CRC_CE("element") }));
  4033. EXPECT_EQ(2, vector2Elements.size());
  4034. AZ::Vector2 position;
  4035. EXPECT_TRUE(vector2Elements[0]->GetData(position));
  4036. EXPECT_FLOAT_EQ(1.0f, position.GetX());
  4037. EXPECT_FLOAT_EQ(2.0f, position.GetY());
  4038. EXPECT_TRUE(vector2Elements[1]->GetData(position));
  4039. EXPECT_FLOAT_EQ(2.0f, position.GetX());
  4040. EXPECT_FLOAT_EQ(4.0f, position.GetY());
  4041. }
  4042. return true;
  4043. }
  4044. AZStd::unique_ptr<DataElementTestClass> m_dataElementClass;
  4045. void run()
  4046. {
  4047. m_dataElementClass->m_data = AZStd::make_unique<AZ::Entity>("DataElement");
  4048. m_dataElementClass->m_data->SetId(AZ::EntityId(47));
  4049. m_dataElementClass->m_positions.emplace_back(1.0f, 2.0f);
  4050. m_dataElementClass->m_positions.emplace_back(2.0f, 4.0f);
  4051. // Write original data
  4052. AZStd::vector<AZ::u8> binaryBuffer;
  4053. {
  4054. AZ::SerializeContext sc;
  4055. AZ::Entity::Reflect(&sc);
  4056. sc.Class<DataElementTestClass>()
  4057. ->Version(0)
  4058. ->Field("m_data", &DataElementTestClass::m_data)
  4059. ->Field("m_positions", &DataElementTestClass::m_positions);
  4060. // Binary
  4061. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > binaryStream(&binaryBuffer);
  4062. AZ::ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  4063. binaryObjStream->WriteClass(m_dataElementClass.get());
  4064. EXPECT_TRUE(binaryObjStream->Finalize());
  4065. }
  4066. // Test find descendant version converter
  4067. {
  4068. AZ::SerializeContext sc;
  4069. AZ::Entity::Reflect(&sc);
  4070. sc.Class<DataElementTestClass>()
  4071. ->Version(1, &VersionConverter)
  4072. ->Field("m_data", &DataElementTestClass::m_data)
  4073. ->Field("m_positions", &DataElementTestClass::m_positions);
  4074. // Binary
  4075. IO::ByteContainerStream<const AZStd::vector<AZ::u8> > binaryStream(&binaryBuffer);
  4076. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  4077. AZ::ObjectStream::ClassReadyCB readyCB([&](void* classPtr, const AZ::Uuid& classId, AZ::SerializeContext* sc)
  4078. {
  4079. AZ_UNUSED(classId);
  4080. AZ_UNUSED(sc);
  4081. delete reinterpret_cast<DataElementTestClass*>(classPtr);
  4082. });
  4083. ObjectStream::LoadBlocking(&binaryStream, sc, readyCB);
  4084. }
  4085. }
  4086. };
  4087. TEST_F(SerializeDescendentDataElementTest, FindTest)
  4088. {
  4089. run();
  4090. }
  4091. class SerializeDataElementNodeTreeTest
  4092. : public LeakDetectionFixture
  4093. {
  4094. public:
  4095. struct EntityWrapperTest
  4096. {
  4097. AZ_CLASS_ALLOCATOR(EntityWrapperTest, AZ::SystemAllocator);
  4098. AZ_TYPE_INFO(EntityWrapperTest, "{BCBC25C3-3D6F-4FC4-B73D-51E6FBD38730}");
  4099. AZ::Entity* m_entity = nullptr;
  4100. };
  4101. struct ContainerTest
  4102. {
  4103. AZ_CLASS_ALLOCATOR(ContainerTest, AZ::SystemAllocator);
  4104. AZ_TYPE_INFO(ContainerTest, "{88FD1BBA-EE9C-4165-8C66-B8B5F28B9205}");
  4105. AZStd::vector<int> m_addedVector;
  4106. AZStd::unordered_set<int> m_removedSet;
  4107. AZStd::vector<int> m_changedVector;
  4108. AZStd::string m_addedString;
  4109. };
  4110. struct EntityContainerTest
  4111. {
  4112. AZ_CLASS_ALLOCATOR(EntityContainerTest, AZ::SystemAllocator);
  4113. AZ_TYPE_INFO(EntityContainerTest, "{A1145D9A-402F-4A40-9B59-52DEAE1070DA}");
  4114. AZStd::unordered_set<AZ::Entity*> m_entitySet;
  4115. };
  4116. struct UnorderedMapContainerTest
  4117. {
  4118. AZ_CLASS_ALLOCATOR(UnorderedMapContainerTest, AZ::SystemAllocator);
  4119. AZ_TYPE_INFO(UnorderedMapContainerTest, "{744ADFE1-4BFF-4F3F-8ED0-EA1BDC4A0D2F}");
  4120. AZStd::unordered_map<AZStd::string, int> m_stringIntMap;
  4121. };
  4122. void SetUp() override
  4123. {
  4124. LeakDetectionFixture::SetUp();
  4125. SerializeDataElementNodeTreeTest::m_wrappedBuffer = AZStd::make_unique<AZStd::vector<AZ::u8>>();
  4126. }
  4127. void TearDown() override
  4128. {
  4129. SerializeDataElementNodeTreeTest::m_wrappedBuffer.reset();
  4130. LeakDetectionFixture::TearDown();
  4131. }
  4132. static bool GetDataHierachyVersionConverter(AZ::SerializeContext& sc, AZ::SerializeContext::DataElementNode& rootElement)
  4133. {
  4134. if (rootElement.GetVersion() == 0)
  4135. {
  4136. int entityIndex = rootElement.FindElement(AZ_CRC_CE("m_entity"));
  4137. EXPECT_NE(-1, entityIndex);
  4138. AZ::SerializeContext::DataElementNode& entityElement = rootElement.GetSubElement(entityIndex);
  4139. AZ::Entity newEntity;
  4140. EXPECT_TRUE(entityElement.GetData(newEntity));
  4141. EXPECT_EQ(AZ::EntityId(21434), newEntity.GetId());
  4142. AZStd::vector<AZ::u8> newEntityBuffer;
  4143. {
  4144. // Binary
  4145. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > binaryStream(&newEntityBuffer);
  4146. AZ::ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  4147. binaryObjStream->WriteClass(&newEntity);
  4148. EXPECT_TRUE(binaryObjStream->Finalize());
  4149. }
  4150. // Validate the newEntityBuffer against the wrapped entity.
  4151. EXPECT_EQ(*SerializeDataElementNodeTreeTest::m_wrappedBuffer, newEntityBuffer);
  4152. }
  4153. return true;
  4154. }
  4155. static bool ContainerTestVersionConverter(AZ::SerializeContext& sc, AZ::SerializeContext::DataElementNode& rootElement)
  4156. {
  4157. if (rootElement.GetVersion() == 0)
  4158. {
  4159. int removedSetIndex = rootElement.FindElement(AZ_CRC_CE("m_removedSet"));
  4160. EXPECT_NE(-1, removedSetIndex);
  4161. int changedVectorIndex = rootElement.FindElement(AZ_CRC_CE("m_changedVector"));
  4162. EXPECT_NE(-1, changedVectorIndex);
  4163. auto changedVectorInts = AZ::Utils::FindDescendantElements(sc, rootElement.GetSubElement(changedVectorIndex), { AZ_CRC_CE("element") });
  4164. EXPECT_EQ(2, changedVectorInts.size());
  4165. EXPECT_TRUE(changedVectorInts[0]->SetData(sc, 75));
  4166. EXPECT_TRUE(changedVectorInts[1]->SetData(sc, 50));
  4167. int addedVectorIndex = rootElement.FindElement(AZ_CRC_CE("m_addedVector"));
  4168. EXPECT_EQ(-1, addedVectorIndex);
  4169. ContainerTest containerTest;
  4170. EXPECT_TRUE(rootElement.GetData(containerTest));
  4171. EXPECT_TRUE(containerTest.m_removedSet.empty());
  4172. EXPECT_TRUE(containerTest.m_addedVector.empty());
  4173. EXPECT_EQ(2, containerTest.m_changedVector.size());
  4174. EXPECT_EQ(75, containerTest.m_changedVector[0]);
  4175. EXPECT_EQ(50, containerTest.m_changedVector[1]);
  4176. rootElement.RemoveElement(removedSetIndex);
  4177. // Add an m_addedVector array and remove the zeroth element from the m_changedVector array
  4178. AZStd::vector<int> newInts;
  4179. newInts.push_back(200);
  4180. newInts.push_back(-265);
  4181. newInts.push_back(9451);
  4182. AZStd::string newString("Test");
  4183. AZ::GenericClassInfo* containerGenericInfo = sc.FindGenericClassInfo(azrtti_typeid<AZStd::string>());
  4184. EXPECT_NE(nullptr, containerGenericInfo);
  4185. int addedStringIndex = rootElement.AddElement(sc, "m_addedString", containerGenericInfo); // Add String Element
  4186. EXPECT_NE(-1, addedStringIndex);
  4187. rootElement.GetSubElement(addedStringIndex).SetData(sc, newString); // Set string element data
  4188. rootElement.AddElementWithData(sc, "m_addedVector", newInts); // Add the addedVector vector<int> with initialized data
  4189. AZ::SerializeContext::DataElementNode* changedVectorElementNode = rootElement.FindSubElement(AZ_CRC_CE("m_changedVector"));
  4190. EXPECT_NE(nullptr, changedVectorElementNode);
  4191. changedVectorElementNode->RemoveElement(0);
  4192. ContainerTest containerTest2;
  4193. EXPECT_TRUE(rootElement.GetData(containerTest2));
  4194. EXPECT_TRUE(containerTest2.m_removedSet.empty());
  4195. EXPECT_EQ(3, containerTest2.m_addedVector.size());
  4196. EXPECT_EQ(1, containerTest2.m_changedVector.size());
  4197. EXPECT_EQ(200, containerTest2.m_addedVector[0]);
  4198. EXPECT_EQ(-265, containerTest2.m_addedVector[1]);
  4199. EXPECT_EQ(9451, containerTest2.m_addedVector[2]);
  4200. EXPECT_EQ(50, containerTest2.m_changedVector[0]);
  4201. EXPECT_EQ("Test", containerTest2.m_addedString);
  4202. }
  4203. return true;
  4204. }
  4205. static bool ContainerOfEntitiesVersionConverter(AZ::SerializeContext&, AZ::SerializeContext::DataElementNode& rootElement)
  4206. {
  4207. if (rootElement.GetVersion() == 0)
  4208. {
  4209. int entityContainerIndex = rootElement.FindElement(AZ_CRC_CE("m_entitySet"));
  4210. EXPECT_NE(-1, entityContainerIndex);
  4211. AZ::SerializeContext::DataElementNode& entityContainerElement = rootElement.GetSubElement(entityContainerIndex);
  4212. AZStd::unordered_set<AZ::Entity*> newContainerEntities;
  4213. EXPECT_TRUE(entityContainerElement.GetData(newContainerEntities));
  4214. for (AZ::Entity* entity : newContainerEntities)
  4215. {
  4216. delete entity;
  4217. }
  4218. }
  4219. return true;
  4220. }
  4221. static bool StringIntMapVersionConverter(AZ::SerializeContext& sc, AZ::SerializeContext::DataElementNode& rootElement)
  4222. {
  4223. if (rootElement.GetVersion() == 0)
  4224. {
  4225. int stringIntMapIndex = rootElement.FindElement(AZ_CRC_CE("m_stringIntMap"));
  4226. EXPECT_NE(-1, stringIntMapIndex);
  4227. UnorderedMapContainerTest containerTest;
  4228. EXPECT_TRUE(rootElement.GetDataHierarchy(sc, containerTest));
  4229. EXPECT_EQ(4, containerTest.m_stringIntMap.size());
  4230. auto foundIt = containerTest.m_stringIntMap.find("Source");
  4231. EXPECT_NE(foundIt, containerTest.m_stringIntMap.end());
  4232. EXPECT_EQ(0, foundIt->second);
  4233. foundIt = containerTest.m_stringIntMap.find("Target");
  4234. EXPECT_NE(containerTest.m_stringIntMap.end(), foundIt);
  4235. EXPECT_EQ(2, foundIt->second);
  4236. foundIt = containerTest.m_stringIntMap.find("In");
  4237. EXPECT_NE(containerTest.m_stringIntMap.end(), foundIt);
  4238. EXPECT_EQ(1, foundIt->second);
  4239. foundIt = containerTest.m_stringIntMap.find("Out");
  4240. EXPECT_NE(containerTest.m_stringIntMap.end(), foundIt);
  4241. EXPECT_EQ(4, foundIt->second);
  4242. }
  4243. return true;
  4244. }
  4245. protected:
  4246. static AZStd::unique_ptr<AZStd::vector<AZ::u8>> m_wrappedBuffer;
  4247. };
  4248. AZStd::unique_ptr<AZStd::vector<AZ::u8>> SerializeDataElementNodeTreeTest::m_wrappedBuffer;
  4249. TEST_F(SerializeDataElementNodeTreeTest, GetDataHierarchyTest)
  4250. {
  4251. EntityWrapperTest entityWrapperTest;
  4252. entityWrapperTest.m_entity = aznew Entity("DataElement");
  4253. entityWrapperTest.m_entity->SetId(AZ::EntityId(21434));
  4254. // Write original data
  4255. AZStd::vector<AZ::u8> binaryBuffer;
  4256. {
  4257. AZ::SerializeContext sc;
  4258. AZ::Entity::Reflect(&sc);
  4259. sc.Class<EntityWrapperTest>()
  4260. ->Version(0)
  4261. ->Field("m_entity", &EntityWrapperTest::m_entity);
  4262. // Binary
  4263. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> binaryStream(&binaryBuffer);
  4264. AZ::ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  4265. binaryObjStream->WriteClass(&entityWrapperTest);
  4266. EXPECT_TRUE(binaryObjStream->Finalize());
  4267. // Write static buffer for wrapped entity data
  4268. binaryStream = AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>>(SerializeDataElementNodeTreeTest::m_wrappedBuffer.get());
  4269. binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  4270. binaryObjStream->WriteClass(entityWrapperTest.m_entity); // Serialize out the wrapped entity.
  4271. EXPECT_TRUE(binaryObjStream->Finalize());
  4272. }
  4273. // GetDataHierarhyVersionConverter version converter
  4274. {
  4275. AZ::SerializeContext sc;
  4276. AZ::Entity::Reflect(&sc);
  4277. sc.Class<EntityWrapperTest>()
  4278. ->Version(1, &GetDataHierachyVersionConverter)
  4279. ->Field("m_entity", &EntityWrapperTest::m_entity);
  4280. // Binary
  4281. IO::ByteContainerStream<const AZStd::vector<AZ::u8> > binaryStream(&binaryBuffer);
  4282. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  4283. AZ::ObjectStream::ClassReadyCB readyCB([&](void* classPtr, const AZ::Uuid& classId, AZ::SerializeContext* sc)
  4284. {
  4285. AZ_UNUSED(classId);
  4286. AZ_UNUSED(sc);
  4287. EntityWrapperTest* entityWrapper = reinterpret_cast<EntityWrapperTest*>(classPtr);
  4288. delete entityWrapper->m_entity;
  4289. delete entityWrapper;
  4290. });
  4291. ObjectStream::LoadBlocking(&binaryStream, sc, readyCB);
  4292. }
  4293. delete entityWrapperTest.m_entity;
  4294. }
  4295. TEST_F(SerializeDataElementNodeTreeTest, ContainerElementTest)
  4296. {
  4297. ContainerTest containerTest;
  4298. containerTest.m_addedVector.push_back(10);
  4299. containerTest.m_addedVector.push_back(15);
  4300. containerTest.m_removedSet.emplace(25);
  4301. containerTest.m_removedSet.emplace(30);
  4302. containerTest.m_changedVector.push_back(40);
  4303. containerTest.m_changedVector.push_back(45);
  4304. // Write original data
  4305. AZStd::vector<AZ::u8> binaryBuffer;
  4306. {
  4307. AZ::SerializeContext sc;
  4308. sc.Class<ContainerTest>()
  4309. ->Version(0)
  4310. ->Field("m_removedSet", &ContainerTest::m_removedSet)
  4311. ->Field("m_changedVector", &ContainerTest::m_changedVector);
  4312. // Binary
  4313. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> binaryStream(&binaryBuffer);
  4314. AZ::ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  4315. binaryObjStream->WriteClass(&containerTest);
  4316. EXPECT_TRUE(binaryObjStream->Finalize());
  4317. }
  4318. // Test container version converter
  4319. {
  4320. ContainerTest loadedContainer;
  4321. AZ::SerializeContext sc;
  4322. AZ::GenericClassInfo* genericClassInfo = AZ::SerializeGenericTypeInfo<AZStd::unordered_set<int>>::GetGenericInfo();
  4323. genericClassInfo->Reflect(&sc);
  4324. sc.Class<ContainerTest>()
  4325. ->Version(1, &ContainerTestVersionConverter)
  4326. ->Field("m_addedVector", &ContainerTest::m_addedVector)
  4327. ->Field("m_changedVector", &ContainerTest::m_changedVector)
  4328. ->Field("m_addedString", &ContainerTest::m_addedString);
  4329. // Binary
  4330. IO::ByteContainerStream<const AZStd::vector<AZ::u8> > binaryStream(&binaryBuffer);
  4331. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  4332. ObjectStream::LoadBlocking(&binaryStream, sc, [&loadedContainer](void* objectPtr, const AZ::Uuid typeId, AZ::SerializeContext* serializeContext)
  4333. {
  4334. auto containerTestPtr = static_cast<ContainerTest*>(serializeContext->DownCast(objectPtr, typeId, azrtti_typeid<ContainerTest>()));
  4335. if (containerTestPtr)
  4336. {
  4337. loadedContainer = *containerTestPtr;
  4338. }
  4339. auto classData = serializeContext->FindClassData(typeId);
  4340. if (classData && classData->m_factory)
  4341. {
  4342. classData->m_factory->Destroy(objectPtr);
  4343. }
  4344. });
  4345. EXPECT_TRUE(loadedContainer.m_removedSet.empty());
  4346. EXPECT_EQ(1, loadedContainer.m_changedVector.size());
  4347. EXPECT_EQ(3, loadedContainer.m_addedVector.size());
  4348. EXPECT_EQ(50, loadedContainer.m_changedVector[0]);
  4349. EXPECT_EQ(200, loadedContainer.m_addedVector[0]);
  4350. EXPECT_EQ(-265, loadedContainer.m_addedVector[1]);
  4351. EXPECT_EQ(9451, loadedContainer.m_addedVector[2]);
  4352. EXPECT_EQ("Test", loadedContainer.m_addedString);
  4353. }
  4354. }
  4355. TEST_F(SerializeDataElementNodeTreeTest, EntityContainerElementTest)
  4356. {
  4357. EntityContainerTest containerTest;
  4358. containerTest.m_entitySet.insert(aznew AZ::Entity("Test"));
  4359. // Write original data
  4360. AZStd::vector<AZ::u8> binaryBuffer;
  4361. {
  4362. AZ::SerializeContext sc;
  4363. AZ::Entity::Reflect(&sc);
  4364. sc.Class<EntityContainerTest>()
  4365. ->Version(0)
  4366. ->Field("m_entitySet", &EntityContainerTest::m_entitySet);
  4367. // Binary
  4368. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> binaryStream(&binaryBuffer);
  4369. AZ::ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  4370. binaryObjStream->WriteClass(&containerTest);
  4371. EXPECT_TRUE(binaryObjStream->Finalize());
  4372. }
  4373. // Test container version converter
  4374. {
  4375. EntityContainerTest loadedContainer;
  4376. AZ::SerializeContext sc;
  4377. AZ::Entity::Reflect(&sc);
  4378. sc.Class<EntityContainerTest>()
  4379. ->Version(1, &ContainerOfEntitiesVersionConverter)
  4380. ->Field("m_entitySet", &EntityContainerTest::m_entitySet);
  4381. // Binary
  4382. IO::ByteContainerStream<const AZStd::vector<AZ::u8> > binaryStream(&binaryBuffer);
  4383. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  4384. ObjectStream::LoadBlocking(&binaryStream, sc, [&loadedContainer](void* objectPtr, const AZ::Uuid typeId, AZ::SerializeContext* serializeContext)
  4385. {
  4386. auto containerTestPtr = static_cast<EntityContainerTest*>(serializeContext->DownCast(objectPtr, typeId, azrtti_typeid<EntityContainerTest>()));
  4387. if (containerTestPtr)
  4388. {
  4389. loadedContainer = *containerTestPtr;
  4390. }
  4391. auto classData = serializeContext->FindClassData(typeId);
  4392. if (classData && classData->m_factory)
  4393. {
  4394. classData->m_factory->Destroy(objectPtr);
  4395. }
  4396. });
  4397. for (auto&& entityContainer : { containerTest.m_entitySet, loadedContainer.m_entitySet })
  4398. {
  4399. for (AZ::Entity* entity : entityContainer)
  4400. {
  4401. delete entity;
  4402. }
  4403. }
  4404. }
  4405. }
  4406. TEST_F(SerializeDataElementNodeTreeTest, UnorderedMapContainerElementTest)
  4407. {
  4408. UnorderedMapContainerTest containerTest;
  4409. containerTest.m_stringIntMap.emplace("Source", 0);
  4410. containerTest.m_stringIntMap.emplace("Target", 2);
  4411. containerTest.m_stringIntMap.emplace("In", 1);
  4412. containerTest.m_stringIntMap.emplace("Out", 4);
  4413. // Write original data
  4414. AZStd::vector<AZ::u8> binaryBuffer;
  4415. {
  4416. AZ::SerializeContext sc;
  4417. sc.Class<UnorderedMapContainerTest>()
  4418. ->Version(0)
  4419. ->Field("m_stringIntMap", &UnorderedMapContainerTest::m_stringIntMap);
  4420. // Binary
  4421. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> binaryStream(&binaryBuffer);
  4422. AZ::ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  4423. binaryObjStream->WriteClass(&containerTest);
  4424. EXPECT_TRUE(binaryObjStream->Finalize());
  4425. }
  4426. // Test container version converter
  4427. {
  4428. UnorderedMapContainerTest loadedContainer;
  4429. AZ::SerializeContext sc;
  4430. sc.Class<UnorderedMapContainerTest>()
  4431. ->Version(1, &StringIntMapVersionConverter)
  4432. ->Field("m_stringIntMap", &UnorderedMapContainerTest::m_stringIntMap);
  4433. // Binary
  4434. IO::ByteContainerStream<const AZStd::vector<AZ::u8> > binaryStream(&binaryBuffer);
  4435. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  4436. EXPECT_TRUE(Utils::LoadObjectFromStreamInPlace(binaryStream, loadedContainer, &sc));
  4437. }
  4438. }
  4439. class SerializeDataElementNodeGetDataTest
  4440. : public LeakDetectionFixture
  4441. {
  4442. public:
  4443. struct TemporarilyReflected
  4444. {
  4445. AZ_CLASS_ALLOCATOR(TemporarilyReflected, AZ::SystemAllocator);
  4446. AZ_TYPE_INFO(TemporarilyReflected, "{F0909A1D-09BF-44D5-A1D8-E27C8E45579D}");
  4447. AZ::u64 m_num{};
  4448. };
  4449. struct ReflectionWrapper
  4450. {
  4451. AZ_CLASS_ALLOCATOR(ReflectionWrapper, AZ::SystemAllocator);
  4452. AZ_TYPE_INFO(ReflectionWrapper, "{EACE8B18-CC31-4E7F-A34C-2A6AA8EB998D}");
  4453. TemporarilyReflected m_tempReflected;
  4454. };
  4455. static bool GetDataOnNonReflectedClassVersionConverter(AZ::SerializeContext& sc, AZ::SerializeContext::DataElementNode& rootElement)
  4456. {
  4457. (void)sc;
  4458. if (rootElement.GetVersion() == 0)
  4459. {
  4460. // The GetData should not crash
  4461. ReflectionWrapper reflectionWrapper;
  4462. EXPECT_FALSE(rootElement.GetData(reflectionWrapper));
  4463. // Drop the m_tempReflectedElement from the ReflectionWrapper
  4464. EXPECT_TRUE(rootElement.RemoveElementByName(AZ_CRC_CE("m_tempReflected")));
  4465. EXPECT_TRUE(rootElement.GetData(reflectionWrapper));
  4466. }
  4467. return true;
  4468. }
  4469. };
  4470. TEST_F(SerializeDataElementNodeGetDataTest, GetDataOnNonReflectedClassTest)
  4471. {
  4472. ReflectionWrapper testReflectionWrapper;
  4473. AZ::SerializeContext sc;
  4474. sc.Class<TemporarilyReflected>()
  4475. ->Version(0)
  4476. ->Field("m_num", &TemporarilyReflected::m_num)
  4477. ;
  4478. sc.Class<ReflectionWrapper>()
  4479. ->Version(0)
  4480. ->Field("m_tempReflected", &ReflectionWrapper::m_tempReflected)
  4481. ;
  4482. AZStd::vector<AZ::u8> binaryBuffer;
  4483. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> binaryStream(&binaryBuffer);
  4484. AZ::ObjectStream* binaryObjStream = ObjectStream::Create(&binaryStream, sc, ObjectStream::ST_BINARY);
  4485. binaryObjStream->WriteClass(&testReflectionWrapper);
  4486. EXPECT_TRUE(binaryObjStream->Finalize());
  4487. sc.EnableRemoveReflection();
  4488. // Remove the TemporarilyReflected struct so that it is not found when loading
  4489. sc.Class<TemporarilyReflected>()
  4490. ->Version(0)
  4491. ->Field("m_num", &TemporarilyReflected::m_num)
  4492. ;
  4493. // Unreflect ReflectionWrapper version 0 and Reflect it again as version 1
  4494. sc.Class<ReflectionWrapper>()
  4495. ->Version(0)
  4496. ->Field("m_tempReflected", &ReflectionWrapper::m_tempReflected)
  4497. ;
  4498. sc.DisableRemoveReflection();
  4499. sc.Class<ReflectionWrapper>()
  4500. ->Version(1, &GetDataOnNonReflectedClassVersionConverter)
  4501. ->Field("m_tempReflected", &ReflectionWrapper::m_tempReflected)
  4502. ;
  4503. ReflectionWrapper loadReflectionWrapper;
  4504. binaryStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  4505. AZ_TEST_START_TRACE_SUPPRESSION;
  4506. EXPECT_TRUE(Utils::LoadObjectFromStreamInPlace(binaryStream, loadReflectionWrapper, &sc));
  4507. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  4508. }
  4509. class SerializableAnyFieldTest
  4510. : public LeakDetectionFixture
  4511. {
  4512. public:
  4513. struct AnyMemberClass
  4514. {
  4515. AZ_TYPE_INFO(AnyMemberClass, "{67F73D37-5F9E-42FE-AFC9-9867924D87DD}");
  4516. AZ_CLASS_ALLOCATOR(AnyMemberClass, AZ::SystemAllocator);
  4517. static void Reflect(ReflectContext* context)
  4518. {
  4519. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  4520. {
  4521. serializeContext->Class<AnyMemberClass>()
  4522. ->Field("Any", &AnyMemberClass::m_any)
  4523. ;
  4524. }
  4525. }
  4526. AZStd::any m_any;
  4527. };
  4528. // We must expose the class for serialization first.
  4529. void SetUp() override
  4530. {
  4531. LeakDetectionFixture::SetUp();
  4532. m_serializeContext = AZStd::make_unique<SerializeContext>();
  4533. AnyMemberClass::Reflect(m_serializeContext.get());
  4534. MyClassBase1::Reflect(*m_serializeContext);
  4535. MyClassBase2::Reflect(*m_serializeContext);
  4536. MyClassBase3::Reflect(*m_serializeContext);
  4537. SerializeTestClasses::MyClassMix::Reflect(*m_serializeContext);
  4538. ReflectedString::Reflect(m_serializeContext.get());
  4539. ReflectedSmartPtr::Reflect(m_serializeContext.get());
  4540. NonCopyableClass::Reflect(m_serializeContext.get());
  4541. m_serializeContext->RegisterGenericType<AZStd::shared_ptr<NonCopyableClass>>();
  4542. }
  4543. void TearDown() override
  4544. {
  4545. m_serializeContext->EnableRemoveReflection();
  4546. AnyMemberClass::Reflect(m_serializeContext.get());
  4547. MyClassBase1::Reflect(*m_serializeContext);
  4548. MyClassBase2::Reflect(*m_serializeContext);
  4549. MyClassBase3::Reflect(*m_serializeContext);
  4550. SerializeTestClasses::MyClassMix::Reflect(*m_serializeContext);
  4551. ReflectedString::Reflect(m_serializeContext.get());
  4552. ReflectedSmartPtr::Reflect(m_serializeContext.get());
  4553. NonCopyableClass::Reflect(m_serializeContext.get());
  4554. m_serializeContext->RegisterGenericType<AZStd::shared_ptr<NonCopyableClass>>();
  4555. m_serializeContext->DisableRemoveReflection();
  4556. m_serializeContext.reset();
  4557. LeakDetectionFixture::TearDown();
  4558. }
  4559. struct ReflectedString
  4560. {
  4561. AZ_TYPE_INFO(ReflectedString, "{5DE01DEA-119F-43E9-B87C-BF980EBAD896}");
  4562. AZ_CLASS_ALLOCATOR(ReflectedString, AZ::SystemAllocator);
  4563. static void Reflect(ReflectContext* context)
  4564. {
  4565. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  4566. {
  4567. //String class must reflected in at least one field
  4568. serializeContext->Class<ReflectedString>()
  4569. ->Field("String", &ReflectedString::m_name)
  4570. ;
  4571. }
  4572. }
  4573. AZStd::string m_name;
  4574. };
  4575. struct ReflectedSmartPtr
  4576. {
  4577. AZ_TYPE_INFO(ReflectedSmartPtr, "{3EAA2B56-A6A8-46E0-9869-DA4A15AE6704}");
  4578. AZ_CLASS_ALLOCATOR(ReflectedSmartPtr, AZ::SystemAllocator);
  4579. ReflectedSmartPtr() = default;
  4580. static void Reflect(ReflectContext* context)
  4581. {
  4582. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  4583. {
  4584. //String class must reflected in at least one field
  4585. serializeContext->Class<ReflectedSmartPtr>()
  4586. ->Field("Field1", &ReflectedSmartPtr::m_uniqueString)
  4587. ->Field("Field2", &ReflectedSmartPtr::m_sharedString)
  4588. ;
  4589. }
  4590. }
  4591. AZStd::unique_ptr<ReflectedString> m_uniqueString;
  4592. AZStd::shared_ptr<ReflectedString> m_sharedString;
  4593. private:
  4594. ReflectedSmartPtr(const ReflectedSmartPtr&) = delete;
  4595. };
  4596. struct NonCopyableClass
  4597. {
  4598. AZ_TYPE_INFO(NonCopyableClass, "{5DE8EA5C-9F4A-43F6-9B8B-10EF06319972}");
  4599. AZ_CLASS_ALLOCATOR(NonCopyableClass, AZ::SystemAllocator);
  4600. NonCopyableClass() = default;
  4601. NonCopyableClass(const NonCopyableClass&) = delete;
  4602. NonCopyableClass& operator=(const NonCopyableClass&) = delete;
  4603. static void Reflect(ReflectContext* context)
  4604. {
  4605. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  4606. {
  4607. serializeContext->Class<NonCopyableClass>();
  4608. }
  4609. }
  4610. };
  4611. protected:
  4612. struct NonReflectedClass
  4613. {
  4614. AZ_TYPE_INFO(NonReflectedClass, "{13B8CFB0-601A-4C03-BC19-4EDC71156254}");
  4615. AZ_CLASS_ALLOCATOR(NonReflectedClass, AZ::SystemAllocator);
  4616. AZ::u64 m_num;
  4617. AZStd::string m_name;
  4618. };
  4619. AZStd::unique_ptr<SerializeContext> m_serializeContext;
  4620. };
  4621. TEST_F(SerializableAnyFieldTest, EmptyAnyTest)
  4622. {
  4623. AZStd::any emptyAny;
  4624. // BINARY
  4625. AZStd::vector<char> byteBuffer;
  4626. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4627. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  4628. byteObjStream->WriteClass(&emptyAny);
  4629. byteObjStream->Finalize();
  4630. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4631. AZStd::any readAnyData;
  4632. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, readAnyData, m_serializeContext.get());
  4633. EXPECT_TRUE(readAnyData.empty());
  4634. // JSON
  4635. byteBuffer.clear();
  4636. IO::ByteContainerStream<AZStd::vector<char> > jsonStream(&byteBuffer);
  4637. ObjectStream* jsonObjStream = ObjectStream::Create(&jsonStream, *m_serializeContext, ObjectStream::ST_JSON);
  4638. jsonObjStream->WriteClass(&emptyAny);
  4639. jsonObjStream->Finalize();
  4640. jsonStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4641. AZStd::any readAnyDataJson;
  4642. AZ::Utils::LoadObjectFromStreamInPlace(jsonStream, readAnyDataJson, m_serializeContext.get());
  4643. EXPECT_TRUE(readAnyDataJson.empty());
  4644. // JSON
  4645. byteBuffer.clear();
  4646. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&byteBuffer);
  4647. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, *m_serializeContext, ObjectStream::ST_XML);
  4648. xmlObjStream->WriteClass(&emptyAny);
  4649. xmlObjStream->Finalize();
  4650. xmlStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4651. AZStd::any readAnyDataXml;
  4652. AZ::Utils::LoadObjectFromStreamInPlace(xmlStream, readAnyDataXml, m_serializeContext.get());
  4653. EXPECT_TRUE(readAnyDataXml.empty());
  4654. }
  4655. TEST_F(SerializableAnyFieldTest, MultipleContextsAnyTest)
  4656. {
  4657. SerializeTestClasses::MyClassMix obj;
  4658. obj.Set(5); // Initialize with some value
  4659. AZStd::any testData(obj);
  4660. AZStd::vector<char> byteBuffer;
  4661. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4662. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_XML);
  4663. byteObjStream->WriteClass(&testData);
  4664. byteObjStream->Finalize();
  4665. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4666. // create and destroy temporary context to test static context members
  4667. SerializeContext* tmpContext = aznew SerializeContext();
  4668. delete tmpContext;
  4669. AZStd::any readAnyData;
  4670. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, readAnyData, m_serializeContext.get());
  4671. EXPECT_EQ(SerializeTypeInfo<SerializeTestClasses::MyClassMix>::GetUuid(), readAnyData.type());
  4672. EXPECT_NE(nullptr, AZStd::any_cast<void>(&readAnyData));
  4673. const SerializeTestClasses::MyClassMix& anyMixRef = *AZStd::any_cast<SerializeTestClasses::MyClassMix>(&testData);
  4674. const SerializeTestClasses::MyClassMix& readAnyMixRef = *AZStd::any_cast<SerializeTestClasses::MyClassMix>(&readAnyData);
  4675. EXPECT_EQ(anyMixRef.m_dataMix, readAnyMixRef.m_dataMix);
  4676. }
  4677. TEST_F(SerializableAnyFieldTest, ReflectedFieldTest)
  4678. {
  4679. SerializeTestClasses::MyClassMix obj;
  4680. obj.Set(5); // Initialize with some value
  4681. AZStd::any testData(obj);
  4682. // BINARY
  4683. AZStd::vector<char> byteBuffer;
  4684. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4685. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_XML);
  4686. byteObjStream->WriteClass(&testData);
  4687. byteObjStream->Finalize();
  4688. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4689. AZStd::any readAnyData;
  4690. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, readAnyData, m_serializeContext.get());
  4691. EXPECT_EQ(SerializeTypeInfo<SerializeTestClasses::MyClassMix>::GetUuid(), readAnyData.type());
  4692. EXPECT_NE(nullptr, AZStd::any_cast<void>(&readAnyData));
  4693. const SerializeTestClasses::MyClassMix& anyMixRef = *AZStd::any_cast<SerializeTestClasses::MyClassMix>(&testData);
  4694. const SerializeTestClasses::MyClassMix& readAnyMixRef = *AZStd::any_cast<SerializeTestClasses::MyClassMix>(&readAnyData);
  4695. EXPECT_EQ(anyMixRef.m_dataMix, readAnyMixRef.m_dataMix);
  4696. }
  4697. TEST_F(SerializableAnyFieldTest, NonReflectedFieldTest)
  4698. {
  4699. NonReflectedClass notReflected;
  4700. notReflected.m_num = 17;
  4701. notReflected.m_name = "Test";
  4702. AZStd::any testData(notReflected);
  4703. // BINARY
  4704. AZStd::vector<char> byteBuffer;
  4705. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4706. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  4707. AZ_TEST_START_TRACE_SUPPRESSION;
  4708. byteObjStream->WriteClass(&testData);
  4709. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  4710. byteObjStream->Finalize();
  4711. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4712. AZStd::any readAnyData;
  4713. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, readAnyData, m_serializeContext.get());
  4714. EXPECT_EQ(AZ::Uuid::CreateNull(), readAnyData.type());
  4715. EXPECT_TRUE(readAnyData.empty());
  4716. }
  4717. TEST_F(SerializableAnyFieldTest, EnumerateFieldTest)
  4718. {
  4719. SerializeTestClasses::MyClassMix obj;
  4720. obj.m_dataMix = 5.;
  4721. m_serializeContext->EnumerateObject(&obj,
  4722. [](void* classPtr, const SerializeContext::ClassData* classData, const SerializeContext::ClassElement*)
  4723. {
  4724. if (classData->m_typeId == azrtti_typeid<SerializeTestClasses::MyClassMix>())
  4725. {
  4726. auto mixinClassPtr = reinterpret_cast<SerializeTestClasses::MyClassMix*>(classPtr);
  4727. EXPECT_NE(nullptr, mixinClassPtr);
  4728. EXPECT_DOUBLE_EQ(5.0, mixinClassPtr->m_dataMix);
  4729. }
  4730. return true;
  4731. },
  4732. []() -> bool
  4733. {
  4734. return true;
  4735. },
  4736. SerializeContext::ENUM_ACCESS_FOR_READ);
  4737. }
  4738. TEST_F(SerializableAnyFieldTest, MemberFieldTest)
  4739. {
  4740. SerializeTestClasses::MyClassMix mixedClass;
  4741. mixedClass.m_enum = MyClassBase3::Option3;
  4742. AnyMemberClass anyWrapper;
  4743. anyWrapper.m_any = AZStd::any(mixedClass);
  4744. // BINARY
  4745. AZStd::vector<char> byteBuffer;
  4746. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4747. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  4748. byteObjStream->WriteClass(&anyWrapper);
  4749. byteObjStream->Finalize();
  4750. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4751. AnyMemberClass readAnyWrapper;
  4752. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, readAnyWrapper, m_serializeContext.get());
  4753. EXPECT_EQ(SerializeTypeInfo<SerializeTestClasses::MyClassMix>::GetUuid(), readAnyWrapper.m_any.type());
  4754. EXPECT_NE(nullptr, AZStd::any_cast<void>(&readAnyWrapper.m_any));
  4755. auto* readMixedClass = AZStd::any_cast<SerializeTestClasses::MyClassMix>(&readAnyWrapper.m_any);
  4756. EXPECT_NE(nullptr, readMixedClass);
  4757. EXPECT_EQ(MyClassBase3::Option3, readMixedClass->m_enum);
  4758. SerializeTestClasses::MyClassMix& anyMixRef = *AZStd::any_cast<SerializeTestClasses::MyClassMix>(&anyWrapper.m_any);
  4759. EXPECT_EQ(anyMixRef, *readMixedClass);
  4760. }
  4761. TEST_F(SerializableAnyFieldTest, AZStdStringFieldTest)
  4762. {
  4763. AZStd::string test("Canvas");
  4764. AZStd::any anyString(test);
  4765. // BINARY
  4766. AZStd::vector<char> byteBuffer;
  4767. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4768. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  4769. byteObjStream->WriteClass(&anyString);
  4770. byteObjStream->Finalize();
  4771. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4772. AZStd::any readAnyString;
  4773. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, readAnyString, m_serializeContext.get());
  4774. EXPECT_EQ(azrtti_typeid<AZStd::string>(), readAnyString.type());
  4775. auto* serializedString = AZStd::any_cast<AZStd::string>(&readAnyString);
  4776. EXPECT_NE(nullptr, serializedString);
  4777. EXPECT_EQ(test, *serializedString);
  4778. }
  4779. TEST_F(SerializableAnyFieldTest, AZStdSmartPtrFieldTest)
  4780. {
  4781. /*
  4782. //For some reason that the static_assert inside of AZStd::any about only being able to be constructed with a copyable type
  4783. //or move only type is firing when attempting to move a unique_ptr into it.
  4784. {
  4785. auto testUniquePtr = AZStd::make_unique<ReflectedString>();
  4786. testUniquePtr->m_name = "Script";
  4787. AZStd::any anySmartPtr(AZStd::make_unique<ReflectedString>());
  4788. // BINARY
  4789. AZStd::vector<char> byteBuffer;
  4790. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4791. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  4792. byteObjStream->WriteClass(&anySmartPtr);
  4793. byteObjStream->Finalize();
  4794. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4795. AZStd::any readAnySmartPtr;
  4796. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, readAnySmartPtr, m_serializeContext.get());
  4797. EXPECT_EQ(azrtti_typeid<AZStd::unique_ptr<ReflectedString>>(), readAnySmartPtr.type());
  4798. auto uniquePtrAny = AZStd::any_cast<AZStd::unique_ptr<ReflectedString>>(&readAnySmartPtr);
  4799. EXPECT_NE(nullptr, *uniquePtrAny);
  4800. auto testUniquePtrAny = AZStd::any_cast<AZStd::unique_ptr<ReflectedString>>(&anySmartPtr);
  4801. EXPECT_EQ((*testUniquePtrAny)->m_name, (*uniquePtrAny)->m_name);
  4802. }
  4803. */
  4804. {
  4805. auto testSharedPtr = AZStd::make_shared<ReflectedString>();
  4806. testSharedPtr->m_name = "Canvas";
  4807. AZStd::any anySmartPtr(testSharedPtr);
  4808. // BINARY
  4809. AZStd::vector<char> byteBuffer;
  4810. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4811. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  4812. byteObjStream->WriteClass(&anySmartPtr);
  4813. byteObjStream->Finalize();
  4814. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4815. AZStd::any readAnySmartPtr;
  4816. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, readAnySmartPtr, m_serializeContext.get());
  4817. EXPECT_EQ(azrtti_typeid<AZStd::shared_ptr<ReflectedString>>(), readAnySmartPtr.type());
  4818. auto sharedPtrAny = AZStd::any_cast<AZStd::shared_ptr<ReflectedString>>(&readAnySmartPtr);
  4819. EXPECT_NE(nullptr, *sharedPtrAny);
  4820. EXPECT_EQ(testSharedPtr->m_name, (*sharedPtrAny)->m_name);
  4821. }
  4822. }
  4823. TEST_F(SerializableAnyFieldTest, ReflectedPointerFieldTest)
  4824. {
  4825. SerializeTestClasses::MyClassMix obj;
  4826. obj.Set(26); // Initialize with some value
  4827. AZStd::any testData(&obj);
  4828. // BINARY
  4829. AZStd::vector<char> byteBuffer;
  4830. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4831. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  4832. byteObjStream->WriteClass(&testData);
  4833. byteObjStream->Finalize();
  4834. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4835. AZStd::any readAnyData;
  4836. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, readAnyData, m_serializeContext.get());
  4837. EXPECT_EQ(SerializeTypeInfo<SerializeTestClasses::MyClassMix>::GetUuid(), readAnyData.type());
  4838. EXPECT_NE(nullptr, AZStd::any_cast<void>(&readAnyData));
  4839. const SerializeTestClasses::MyClassMix* anyMixRef = AZStd::any_cast<SerializeTestClasses::MyClassMix*>(testData);
  4840. const SerializeTestClasses::MyClassMix& readAnyMixRef = *AZStd::any_cast<SerializeTestClasses::MyClassMix>(&readAnyData);
  4841. EXPECT_EQ(anyMixRef->m_dataMix, readAnyMixRef.m_dataMix);
  4842. }
  4843. TEST_F(SerializableAnyFieldTest, CreateAnyForSmartPtrWithNonCopyableSmartPtrDoesNotCrash)
  4844. {
  4845. AZStd::any nonCopyableSharedPtr = m_serializeContext->CreateAny(azrtti_typeid<AZStd::shared_ptr<NonCopyableClass>>());
  4846. EXPECT_FALSE(nonCopyableSharedPtr.empty());
  4847. }
  4848. class SerializableOptionalFixture
  4849. : public LeakDetectionFixture
  4850. {
  4851. public:
  4852. struct OptionalMemberClass
  4853. {
  4854. AZ_TYPE_INFO(OptionalMemberClass, "{6BC95A2D-FE6B-4FD8-9586-771F47C44C0B}");
  4855. AZ_CLASS_ALLOCATOR(OptionalMemberClass, AZ::SystemAllocator);
  4856. static void Reflect(ReflectContext* context)
  4857. {
  4858. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  4859. {
  4860. serializeContext->Class<OptionalMemberClass>()
  4861. ->Field("Optional", &OptionalMemberClass::m_optional)
  4862. ;
  4863. }
  4864. }
  4865. AZStd::optional<int> m_optional;
  4866. };
  4867. // We must expose the class for serialization first.
  4868. void SetUp() override
  4869. {
  4870. LeakDetectionFixture::SetUp();
  4871. m_serializeContext = AZStd::make_unique<SerializeContext>();
  4872. OptionalMemberClass::Reflect(m_serializeContext.get());
  4873. }
  4874. void TearDown() override
  4875. {
  4876. m_serializeContext->EnableRemoveReflection();
  4877. OptionalMemberClass::Reflect(m_serializeContext.get());
  4878. m_serializeContext.reset();
  4879. LeakDetectionFixture::TearDown();
  4880. }
  4881. protected:
  4882. AZStd::unique_ptr<SerializeContext> m_serializeContext;
  4883. };
  4884. TEST_F(SerializableOptionalFixture, TestHasValueOptionalSerialization)
  4885. {
  4886. AZStd::optional<int> theOpt {42};
  4887. AZStd::vector<char> byteBuffer;
  4888. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4889. AZ::Utils::SaveObjectToStream(byteStream, ObjectStream::ST_XML, &theOpt, m_serializeContext.get());
  4890. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4891. AZStd::optional<int> deserializedOptional;
  4892. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, deserializedOptional, m_serializeContext.get());
  4893. EXPECT_TRUE(deserializedOptional.has_value());
  4894. EXPECT_EQ(deserializedOptional.value(), 42);
  4895. }
  4896. TEST_F(SerializableOptionalFixture, TestNulloptOptionalSerialization)
  4897. {
  4898. AZStd::optional<int> theOpt;
  4899. AZStd::vector<char> byteBuffer;
  4900. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  4901. AZ::Utils::SaveObjectToStream(byteStream, ObjectStream::ST_XML, &theOpt, m_serializeContext.get());
  4902. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  4903. AZStd::optional<int> deserializedOptional;
  4904. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, deserializedOptional, m_serializeContext.get());
  4905. EXPECT_FALSE(deserializedOptional.has_value());
  4906. }
  4907. TEST_F(Serialization, AttributeTest)
  4908. {
  4909. const AZ::Crc32 attributeCrc = AZ_CRC_CE("TestAttribute");
  4910. const int attributeValue = 5;
  4911. m_serializeContext->Class<SerializeTestClasses::BaseNoRtti>()
  4912. ->Attribute(attributeCrc, attributeValue)
  4913. ;
  4914. auto classData = m_serializeContext->FindClassData(azrtti_typeid<SerializeTestClasses::BaseNoRtti>());
  4915. ASSERT_NE(nullptr, classData);
  4916. auto attribute = AZ::FindAttribute(attributeCrc, classData->m_attributes);
  4917. ASSERT_NE(nullptr, attribute);
  4918. AZ::AttributeReader reader(nullptr, attribute);
  4919. int value = 0;
  4920. EXPECT_TRUE(reader.Read<int>(value));
  4921. EXPECT_EQ(attributeValue, value);
  4922. }
  4923. TEST_F(Serialization, AttributeData_WithCallableType_Succeeds)
  4924. {
  4925. static constexpr AZ::Crc32 invokableCrc = AZ_CRC_CE("Invokable");
  4926. static constexpr AZ::Crc32 nonInvokableCrc = AZ_CRC_CE("NonInvokable");
  4927. auto ReadFloat = [](SerializeTestClasses::BaseNoRtti* instance) -> float
  4928. {
  4929. auto noRttiInstance = instance;
  4930. if (!noRttiInstance)
  4931. {
  4932. ADD_FAILURE() << "BaseNoRtti instance object should not be nullptr";
  4933. return 0.0f;
  4934. }
  4935. EXPECT_FALSE(noRttiInstance->m_data);
  4936. return 2.0f;
  4937. };
  4938. m_serializeContext->Class<SerializeTestClasses::BaseNoRtti>()
  4939. ->Attribute(invokableCrc, ReadFloat)
  4940. ->Attribute(nonInvokableCrc, 4.0f)
  4941. ;
  4942. SerializeTestClasses::BaseNoRtti baseNoRttiInstance;
  4943. baseNoRttiInstance.Set();
  4944. auto classData = m_serializeContext->FindClassData(azrtti_typeid<SerializeTestClasses::BaseNoRtti>());
  4945. ASSERT_NE(nullptr, classData);
  4946. AZ::Attribute* attribute = AZ::FindAttribute(invokableCrc, classData->m_attributes);
  4947. ASSERT_NE(nullptr, attribute);
  4948. AZ::AttributeInvoker invoker(&baseNoRttiInstance, attribute);
  4949. float value = 0;
  4950. EXPECT_TRUE(invoker.Read<float>(value));
  4951. EXPECT_FLOAT_EQ(2.0f, value);
  4952. AZ::Attribute* nonInvokeAttribute = AZ::FindAttribute(nonInvokableCrc, classData->m_attributes);
  4953. ASSERT_NE(nullptr, nonInvokeAttribute);
  4954. invoker = { &baseNoRttiInstance, nonInvokeAttribute };
  4955. value = {};
  4956. EXPECT_TRUE(invoker.Read<float>(value));
  4957. EXPECT_FLOAT_EQ(4.0f, value);
  4958. }
  4959. TEST_F(Serialization, AttributeInvocable_UsingVoidPointerInstance_Succeeds)
  4960. {
  4961. static constexpr AZ::Crc32 invokableCrc = AZ_CRC_CE("Invokable");
  4962. auto ReadFloat = [](SerializeTestClasses::BaseNoRtti* instance) -> float
  4963. {
  4964. auto noRttiInstance = instance;
  4965. if (!noRttiInstance)
  4966. {
  4967. ADD_FAILURE() << "BaseNoRtti instance object should not be nullptr";
  4968. return 0.0f;
  4969. }
  4970. EXPECT_FALSE(noRttiInstance->m_data);
  4971. return 2.0f;
  4972. };
  4973. m_serializeContext->Class<SerializeTestClasses::BaseNoRtti>()
  4974. ->Attribute(invokableCrc, ReadFloat)
  4975. ;
  4976. SerializeTestClasses::BaseNoRtti baseNoRttiInstance;
  4977. baseNoRttiInstance.Set();
  4978. auto classData = m_serializeContext->FindClassData(azrtti_typeid<SerializeTestClasses::BaseNoRtti>());
  4979. ASSERT_NE(nullptr, classData);
  4980. AZ::Attribute* attribute = AZ::FindAttribute(invokableCrc, classData->m_attributes);
  4981. ASSERT_NE(nullptr, attribute);
  4982. void* instance = &baseNoRttiInstance;
  4983. auto voidAttributeInvocable = attribute->GetVoidInstanceAttributeInvocable();
  4984. AZ::AttributeReader reader(instance, voidAttributeInvocable.get());
  4985. float value = 0;
  4986. EXPECT_TRUE(reader.Read<float>(value));
  4987. EXPECT_FLOAT_EQ(2.0f, value);
  4988. }
  4989. class ObjectStreamSerialization
  4990. : public LeakDetectionFixture
  4991. {
  4992. public:
  4993. void SetUp() override
  4994. {
  4995. LeakDetectionFixture::SetUp();
  4996. m_serializeContext = AZStd::make_unique<SerializeContext>();
  4997. TemplateInstantiationReflectedWrapper::Reflect(m_serializeContext.get());
  4998. }
  4999. void TearDown() override
  5000. {
  5001. m_serializeContext->EnableRemoveReflection();
  5002. TemplateInstantiationReflectedWrapper::Reflect(m_serializeContext.get());
  5003. m_serializeContext->DisableRemoveReflection();
  5004. m_serializeContext.reset();
  5005. LeakDetectionFixture::TearDown();
  5006. }
  5007. struct TemplateInstantiationReflectedWrapper
  5008. {
  5009. AZ_TYPE_INFO(TemplateInstantiationReflectedWrapper, "{5A2F60AA-F63E-4106-BD5E-0F77E01DDBAC}");
  5010. AZ_CLASS_ALLOCATOR(TemplateInstantiationReflectedWrapper, AZ::SystemAllocator);
  5011. static void Reflect(ReflectContext* context)
  5012. {
  5013. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  5014. {
  5015. //Reflected Template classes must be reflected in one field
  5016. serializeContext->Class<TemplateInstantiationReflectedWrapper>()
  5017. ->Field("m_name", &TemplateInstantiationReflectedWrapper::m_name)
  5018. ;
  5019. }
  5020. }
  5021. AZStd::string m_name;
  5022. };
  5023. struct DeprecatedClass
  5024. {
  5025. AZ_TYPE_INFO(DeprecatedClass, "{5AB3F3C9-21D9-4AA8-84B2-9ACCC81C77B6}");
  5026. static void Reflect(ReflectContext* context)
  5027. {
  5028. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  5029. {
  5030. //Reflected Template classes must be reflected in one field
  5031. serializeContext->Class<DeprecatedClass>()
  5032. ->Field("m_value", &DeprecatedClass::m_value)
  5033. ->Field("m_testFlag", &DeprecatedClass::m_testFlag)
  5034. ;
  5035. }
  5036. }
  5037. int64_t m_value;
  5038. bool m_testFlag;
  5039. };
  5040. struct ConvertedClass
  5041. {
  5042. AZ_TYPE_INFO(ConvertedClass, "{97733A6F-98B5-4EB7-B782-9F8F69FBD581}");
  5043. static void Reflect(ReflectContext* context)
  5044. {
  5045. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  5046. {
  5047. //Reflected Template classes must be reflected in one field
  5048. serializeContext->Class<ConvertedClass>()
  5049. ->Field("m_value", &ConvertedClass::m_value)
  5050. ->Field("m_testString", &ConvertedClass::m_testString)
  5051. ;
  5052. }
  5053. }
  5054. int64_t m_value;
  5055. AZStd::string m_testString;
  5056. };
  5057. static bool DeprecatedClassConverter(SerializeContext& serializeContext, SerializeContext::DataElementNode& deprecatedNode)
  5058. {
  5059. return deprecatedNode.Convert<ConvertedClass>(serializeContext) && deprecatedNode.SetData(serializeContext, ConvertedClass{});
  5060. }
  5061. static constexpr const char* c_reflectedFieldNameTypeId{ "{78469836-4D08-42CE-AC22-B2056442D5AF}" };
  5062. static constexpr const char* c_rootReflectedClassTypeId{ "{DED0BFF5-84A8-47E5-8AFB-73B6BED56F0C}" };
  5063. static constexpr unsigned int c_reflectedFieldNameVersion{ 0 };
  5064. // Wraps a DeprecatedClass element that gets written to an ObjectStream
  5065. // and but loaded with a version change using the same typeid into a structure
  5066. // that no longer contains the deprecated class field
  5067. struct ReflectedFieldNameOldVersion1
  5068. {
  5069. AZ_TYPE_INFO(ReflectedFieldNameOldVersion1, c_reflectedFieldNameTypeId);
  5070. static void Reflect(ReflectContext* context)
  5071. {
  5072. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  5073. {
  5074. //Reflected Template classes must be reflected in one field
  5075. serializeContext->Class<ReflectedFieldNameOldVersion1>()
  5076. ->Version(c_reflectedFieldNameVersion)
  5077. ->Field("m_deprecatedElement", &ReflectedFieldNameOldVersion1::m_deprecatedElement)
  5078. ;
  5079. }
  5080. }
  5081. DeprecatedClass m_deprecatedElement;
  5082. };
  5083. struct ReflectedFieldNameNewVersion1
  5084. {
  5085. AZ_TYPE_INFO(ReflectedFieldNameNewVersion1, c_reflectedFieldNameTypeId);
  5086. static void Reflect(ReflectContext* context)
  5087. {
  5088. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  5089. {
  5090. //Reflected Template classes must be reflected in one field
  5091. serializeContext->Class<ReflectedFieldNameNewVersion1>()
  5092. ->Version(c_reflectedFieldNameVersion)
  5093. ->Field("newElement", &ReflectedFieldNameNewVersion1::m_newElement)
  5094. ;
  5095. }
  5096. }
  5097. int m_newElement{};
  5098. };
  5099. struct RootFieldNameV1
  5100. {
  5101. AZ_TYPE_INFO(RootFieldNameV1, c_rootReflectedClassTypeId);
  5102. static void Reflect(ReflectContext* context)
  5103. {
  5104. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  5105. {
  5106. //Reflected Template classes must be reflected in one field
  5107. serializeContext->Class<RootFieldNameV1>()
  5108. ->Version(c_reflectedFieldNameVersion)
  5109. ->Field("m_reflectedField", &RootFieldNameV1::m_reflectedField)
  5110. ->Field("m_rootName", &RootFieldNameV1::m_rootName)
  5111. ;
  5112. }
  5113. }
  5114. ReflectedFieldNameOldVersion1 m_reflectedField;
  5115. AZStd::string m_rootName;
  5116. };
  5117. struct RootFieldNameV2
  5118. {
  5119. AZ_TYPE_INFO(RootFieldNameV2, c_rootReflectedClassTypeId);
  5120. static void Reflect(ReflectContext* context)
  5121. {
  5122. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  5123. {
  5124. //Reflected Template classes must be reflected in one field
  5125. serializeContext->Class<RootFieldNameV2>()
  5126. ->Version(c_reflectedFieldNameVersion)
  5127. ->Field("m_reflectedField", &RootFieldNameV2::m_reflectedField)
  5128. ->Field("m_rootName", &RootFieldNameV2::m_rootName)
  5129. ;
  5130. }
  5131. }
  5132. ReflectedFieldNameNewVersion1 m_reflectedField;
  5133. AZStd::string m_rootName;
  5134. };
  5135. struct RootElementMemoryTracker
  5136. {
  5137. AZ_TYPE_INFO(RootElementMemoryTracker, "{772D354F-F6EB-467F-8FA7-9086DDD58324}");
  5138. AZ_CLASS_ALLOCATOR(RootElementMemoryTracker, AZ::SystemAllocator);
  5139. RootElementMemoryTracker()
  5140. {
  5141. ++s_allocatedInstance;
  5142. }
  5143. ~RootElementMemoryTracker()
  5144. {
  5145. --s_allocatedInstance;
  5146. }
  5147. static void Reflect(ReflectContext* context)
  5148. {
  5149. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  5150. {
  5151. //Reflected Template classes must be reflected in one field
  5152. serializeContext->Class<RootElementMemoryTracker>();
  5153. }
  5154. }
  5155. static int32_t s_allocatedInstance;
  5156. };
  5157. protected:
  5158. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  5159. };
  5160. int32_t ObjectStreamSerialization::RootElementMemoryTracker::s_allocatedInstance;
  5161. TEST_F(ObjectStreamSerialization, NewerVersionThanSupportedTest)
  5162. {
  5163. AZStd::string loadString;
  5164. // Set the object stream version to numeric_limits<AZ::u32>::max() "4294967295"
  5165. {
  5166. AZStd::string_view versionMaxStringXml = R"(<ObjectStream version="4294967295">
  5167. <Class name="AZStd::string" field="Name" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}" value="Test" specializationTypeId="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
  5168. </ObjectStream>
  5169. )";
  5170. AZ::IO::MemoryStream versionMaxStream(versionMaxStringXml.data(), versionMaxStringXml.size());
  5171. AZ_TEST_START_TRACE_SUPPRESSION;
  5172. bool result = AZ::Utils::LoadObjectFromStreamInPlace(versionMaxStream, loadString, m_serializeContext.get());
  5173. EXPECT_FALSE(result);
  5174. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  5175. EXPECT_EQ("", loadString);
  5176. }
  5177. {
  5178. AZStd::string_view versionMaxStringJson = R"({
  5179. "name": "ObjectStream",
  5180. "version": 4294967295,
  5181. "Objects": [
  5182. {
  5183. "field": "m_textData",
  5184. "typeName": "AZStd::string",
  5185. "typeId": "{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}",
  5186. "specializationTypeId": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}",
  5187. "value": "Test"
  5188. }
  5189. ]
  5190. })";
  5191. AZ::IO::MemoryStream versionMaxStream(versionMaxStringJson.data(), versionMaxStringJson.size());
  5192. AZ_TEST_START_TRACE_SUPPRESSION;
  5193. bool result = AZ::Utils::LoadObjectFromStreamInPlace(versionMaxStream, loadString, m_serializeContext.get());
  5194. EXPECT_FALSE(result);
  5195. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  5196. EXPECT_EQ("", loadString);
  5197. }
  5198. {
  5199. AZStd::string_view versionMaxStringBinary = "00FFFFFFFF18EF8FF807DDEE4EB0B6784CA3A2C490A40000";
  5200. AZStd::vector<AZ::u8> byteArray;
  5201. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> binaryStream(&byteArray);
  5202. AZStd::unique_ptr<AZ::SerializeContext::IDataSerializer> binarySerializer = AZStd::make_unique<AZ::Internal::AZByteStream<AZStd::allocator>>();
  5203. binarySerializer->TextToData(versionMaxStringBinary.data(), 0, binaryStream);
  5204. binarySerializer.reset();
  5205. binaryStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5206. AZ_TEST_START_TRACE_SUPPRESSION;
  5207. bool result = AZ::Utils::LoadObjectFromStreamInPlace(binaryStream, loadString, m_serializeContext.get());
  5208. EXPECT_FALSE(result);
  5209. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  5210. EXPECT_EQ("", loadString);
  5211. }
  5212. }
  5213. TEST_F(ObjectStreamSerialization, V1ToCurrentVersionTest)
  5214. {
  5215. // Set the object stream version to "1"
  5216. {
  5217. TemplateInstantiationReflectedWrapper loadXmlWrapper;
  5218. AZStd::string_view versionStringXml = R"(<ObjectStream version="1">
  5219. <Class name="TemplateInstantiationReflectedWrapper" type="{5A2F60AA-F63E-4106-BD5E-0F77E01DDBAC}">
  5220. <Class name="AZStd::string" field="m_name" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}" value="Test"/>
  5221. </Class>
  5222. </ObjectStream>
  5223. )";
  5224. AZ::IO::MemoryStream versionStream(versionStringXml.data(), versionStringXml.size());
  5225. AZ::Utils::LoadObjectFromStreamInPlace(versionStream, loadXmlWrapper, m_serializeContext.get());
  5226. EXPECT_EQ("Test", loadXmlWrapper.m_name);
  5227. }
  5228. {
  5229. TemplateInstantiationReflectedWrapper loadJsonWrapper;
  5230. AZStd::string_view versionStringJson = R"({
  5231. "name": "ObjectStream",
  5232. "version": 1,
  5233. "Objects": [
  5234. {
  5235. "typeName": "TemplateInstantiationReflectedWrapper",
  5236. "typeId": "{5A2F60AA-F63E-4106-BD5E-0F77E01DDBAC}",
  5237. "Objects": [
  5238. {
  5239. "field": "m_name",
  5240. "typeName": "AZStd::string",
  5241. "typeId": "{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}",
  5242. "value": "Test"
  5243. }
  5244. ]
  5245. }
  5246. ]
  5247. })";
  5248. AZ::IO::MemoryStream versionStream(versionStringJson.data(), versionStringJson.size());
  5249. AZ::Utils::LoadObjectFromStreamInPlace(versionStream, loadJsonWrapper, m_serializeContext.get());
  5250. EXPECT_EQ("Test", loadJsonWrapper.m_name);
  5251. }
  5252. {
  5253. TemplateInstantiationReflectedWrapper loadBinaryWrapper;
  5254. AZStd::string_view version1StringBinary = "0000000001085A2F60AAF63E4106BD5E0F77E01DDBAC5CC08C4427EF8FF807DDEE4EB0B6784CA3A2C490A454657374000000";
  5255. AZStd::vector<AZ::u8> byteArray;
  5256. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> binaryStream(&byteArray);
  5257. AZStd::unique_ptr<AZ::SerializeContext::IDataSerializer> binarySerializer = AZStd::make_unique<AZ::Internal::AZByteStream<AZStd::allocator>>();
  5258. binarySerializer->TextToData(version1StringBinary.data(), 0, binaryStream);
  5259. binarySerializer.reset();
  5260. binaryStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5261. AZ::Utils::LoadObjectFromStreamInPlace(binaryStream, loadBinaryWrapper, m_serializeContext.get());
  5262. EXPECT_EQ("Test", loadBinaryWrapper.m_name);
  5263. }
  5264. }
  5265. TEST_F(ObjectStreamSerialization, V2ToCurrentVersionTest)
  5266. {
  5267. AZStd::string loadJsonString;
  5268. // Set the object stream version to "2"
  5269. {
  5270. AZStd::string_view version2StringXml = R"(<ObjectStream version="2">
  5271. <Class name="AZStd::string" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}" value="Test" specializationTypeId="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
  5272. </ObjectStream>
  5273. )";
  5274. AZ::IO::MemoryStream version2Stream(version2StringXml.data(), version2StringXml.size());
  5275. AZ::Utils::LoadObjectFromStreamInPlace(version2Stream, loadJsonString, m_serializeContext.get());
  5276. }
  5277. EXPECT_EQ("Test", loadJsonString);
  5278. AZStd::string loadXmlString;
  5279. {
  5280. AZStd::string_view version2StringJson = R"({
  5281. "name": "ObjectStream",
  5282. "version": 2,
  5283. "Objects": [
  5284. {
  5285. "typeName": "AZStd::string",
  5286. "typeId": "{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}",
  5287. "specializationTypeId": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}",
  5288. "value": "Test"
  5289. }
  5290. ]
  5291. })";
  5292. AZ::IO::MemoryStream version2Stream(version2StringJson.data(), version2StringJson.size());
  5293. AZ::Utils::LoadObjectFromStreamInPlace(version2Stream, loadXmlString, m_serializeContext.get());
  5294. }
  5295. EXPECT_EQ("Test", loadXmlString);
  5296. AZStd::string testString = "Test";
  5297. AZStd::vector<AZ::u8> stringArray;
  5298. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> byteStream(&stringArray);
  5299. AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, &testString, m_serializeContext.get());
  5300. AZStd::string loadBinaryString;
  5301. {
  5302. AZStd::string_view version2StringBinary = "00000000021CEF8FF807DDEE4EB0B6784CA3A2C490A403AAAB3F5C475A669EBCD5FA4DB353C9546573740000";
  5303. AZStd::vector<AZ::u8> byteArray;
  5304. AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8>> binaryStream(&byteArray);
  5305. AZStd::unique_ptr<AZ::SerializeContext::IDataSerializer> binarySerializer = AZStd::make_unique<AZ::Internal::AZByteStream<AZStd::allocator>>();
  5306. binarySerializer->TextToData(version2StringBinary.data(), 0, binaryStream);
  5307. binarySerializer.reset();
  5308. binaryStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5309. AZ::Utils::LoadObjectFromStreamInPlace(binaryStream, loadBinaryString, m_serializeContext.get());
  5310. }
  5311. EXPECT_EQ("Test", loadBinaryString);
  5312. }
  5313. TEST_F(ObjectStreamSerialization, UnreflectedChildElementAndDeprecatedClass_XmlTest)
  5314. {
  5315. // Reflect the Deprecated class and the wrapper class
  5316. // with the deprecated class as a field
  5317. DeprecatedClass::Reflect(m_serializeContext.get());
  5318. ReflectedFieldNameOldVersion1::Reflect(m_serializeContext.get());
  5319. RootFieldNameV1::Reflect(m_serializeContext.get());
  5320. ConvertedClass::Reflect(m_serializeContext.get());
  5321. RootFieldNameV1 oldDeprecatedElement;
  5322. // Test Saving and Loading XML
  5323. AZStd::vector<AZ::u8> byteBuffer;
  5324. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5325. EXPECT_TRUE(AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_XML, &oldDeprecatedElement, m_serializeContext.get()));
  5326. // Un-reflect both the deprecated class and the wrapper class with the deprecated field
  5327. {
  5328. m_serializeContext->EnableRemoveReflection();
  5329. DeprecatedClass::Reflect(m_serializeContext.get());
  5330. ReflectedFieldNameOldVersion1::Reflect(m_serializeContext.get());
  5331. RootFieldNameV1::Reflect(m_serializeContext.get());
  5332. m_serializeContext->DisableRemoveReflection();
  5333. }
  5334. // Reflect the Deprecation Converter for the DeprecatedClass and the wrapper class
  5335. // with the converter class as a field
  5336. m_serializeContext->ClassDeprecate("DeprecatedClass", AzTypeInfo<DeprecatedClass>::Uuid(), &ObjectStreamSerialization::DeprecatedClassConverter);
  5337. ReflectedFieldNameNewVersion1::Reflect(m_serializeContext.get());
  5338. RootFieldNameV2::Reflect(m_serializeContext.get());
  5339. byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5340. RootFieldNameV2 newConvertedElement;
  5341. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, newConvertedElement, m_serializeContext.get());
  5342. // Un-reflect remaining classes
  5343. {
  5344. m_serializeContext->EnableRemoveReflection();
  5345. ConvertedClass::Reflect(m_serializeContext.get());
  5346. m_serializeContext->ClassDeprecate("DeprecatedClass", AzTypeInfo<DeprecatedClass>::Uuid(), &ObjectStreamSerialization::DeprecatedClassConverter);
  5347. ReflectedFieldNameNewVersion1::Reflect(m_serializeContext.get());
  5348. RootFieldNameV2::Reflect(m_serializeContext.get());
  5349. m_serializeContext->DisableRemoveReflection();
  5350. }
  5351. }
  5352. TEST_F(ObjectStreamSerialization, UnreflectedChildElementAndDeprecatedClass_BinaryTest)
  5353. {
  5354. // Reflect the Deprecated class and the wrapper class
  5355. // with the deprecated class as a field
  5356. DeprecatedClass::Reflect(m_serializeContext.get());
  5357. ReflectedFieldNameOldVersion1::Reflect(m_serializeContext.get());
  5358. RootFieldNameV1::Reflect(m_serializeContext.get());
  5359. ConvertedClass::Reflect(m_serializeContext.get());
  5360. RootFieldNameV1 oldDeprecatedElement;
  5361. // Test Saving and Loading XML
  5362. AZStd::vector<AZ::u8> byteBuffer;
  5363. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5364. EXPECT_TRUE(AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, &oldDeprecatedElement, m_serializeContext.get()));
  5365. // Un-reflect both the deprecated class and the wrapper class with the deprecated field
  5366. {
  5367. m_serializeContext->EnableRemoveReflection();
  5368. DeprecatedClass::Reflect(m_serializeContext.get());
  5369. ReflectedFieldNameOldVersion1::Reflect(m_serializeContext.get());
  5370. RootFieldNameV1::Reflect(m_serializeContext.get());
  5371. m_serializeContext->DisableRemoveReflection();
  5372. }
  5373. // Reflect the Deprecation Converter for the DeprecatedClass and the wrapper class
  5374. // with the converter class as a field
  5375. m_serializeContext->ClassDeprecate("DeprecatedClass", AzTypeInfo<DeprecatedClass>::Uuid(), &ObjectStreamSerialization::DeprecatedClassConverter);
  5376. ReflectedFieldNameNewVersion1::Reflect(m_serializeContext.get());
  5377. RootFieldNameV2::Reflect(m_serializeContext.get());
  5378. byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5379. RootFieldNameV2 newConvertedElement;
  5380. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, newConvertedElement, m_serializeContext.get());
  5381. // Un-reflect remaining classes
  5382. {
  5383. m_serializeContext->EnableRemoveReflection();
  5384. ConvertedClass::Reflect(m_serializeContext.get());
  5385. m_serializeContext->ClassDeprecate("DeprecatedClass", AzTypeInfo<DeprecatedClass>::Uuid(), &ObjectStreamSerialization::DeprecatedClassConverter);
  5386. ReflectedFieldNameNewVersion1::Reflect(m_serializeContext.get());
  5387. RootFieldNameV2::Reflect(m_serializeContext.get());
  5388. m_serializeContext->DisableRemoveReflection();
  5389. }
  5390. }
  5391. TEST_F(ObjectStreamSerialization, UnreflectedChildElementAndDeprecatedClass_JSONTest)
  5392. {
  5393. // Reflect the Deprecated class and the wrapper class
  5394. // with the deprecated class as a field
  5395. DeprecatedClass::Reflect(m_serializeContext.get());
  5396. ReflectedFieldNameOldVersion1::Reflect(m_serializeContext.get());
  5397. RootFieldNameV1::Reflect(m_serializeContext.get());
  5398. ConvertedClass::Reflect(m_serializeContext.get());
  5399. RootFieldNameV1 oldDeprecatedElement;
  5400. // Test Saving and Loading XML
  5401. AZStd::vector<AZ::u8> byteBuffer;
  5402. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5403. EXPECT_TRUE(AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_JSON, &oldDeprecatedElement, m_serializeContext.get()));
  5404. // Un-reflect both the deprecated class and the wrapper class with the deprecated field
  5405. {
  5406. m_serializeContext->EnableRemoveReflection();
  5407. DeprecatedClass::Reflect(m_serializeContext.get());
  5408. ReflectedFieldNameOldVersion1::Reflect(m_serializeContext.get());
  5409. RootFieldNameV1::Reflect(m_serializeContext.get());
  5410. m_serializeContext->DisableRemoveReflection();
  5411. }
  5412. // Reflect the Deprecation Converter for the DeprecatedClass and the wrapper class
  5413. // with the converter class as a field
  5414. m_serializeContext->ClassDeprecate("DeprecatedClass", AzTypeInfo<DeprecatedClass>::Uuid(), &ObjectStreamSerialization::DeprecatedClassConverter);
  5415. ReflectedFieldNameNewVersion1::Reflect(m_serializeContext.get());
  5416. RootFieldNameV2::Reflect(m_serializeContext.get());
  5417. byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5418. RootFieldNameV2 newConvertedElement;
  5419. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, newConvertedElement, m_serializeContext.get());
  5420. // Un-reflect remaining classes
  5421. {
  5422. m_serializeContext->EnableRemoveReflection();
  5423. ConvertedClass::Reflect(m_serializeContext.get());
  5424. m_serializeContext->ClassDeprecate("DeprecatedClass", AzTypeInfo<DeprecatedClass>::Uuid(), &ObjectStreamSerialization::DeprecatedClassConverter);
  5425. ReflectedFieldNameNewVersion1::Reflect(m_serializeContext.get());
  5426. RootFieldNameV1::Reflect(m_serializeContext.get());
  5427. m_serializeContext->DisableRemoveReflection();
  5428. }
  5429. }
  5430. // Prove that if a member of a vector of baseclass pointers is unreadable, the container
  5431. // removes the element instead of leaving a null. This is an arbitrary choice (to remove or leave
  5432. // the null) and this test exists just to prove that the chosen way functions as expected.
  5433. TEST_F(ObjectStreamSerialization, UnreadableVectorElements_LeaveNoGaps_Errors)
  5434. {
  5435. using namespace ContainerElementDeprecationTestData;
  5436. // make sure that when a component is deprecated, it is removed during deserialization
  5437. // and does not leave a hole that is a nullptr.
  5438. ClassWithAVectorOfBaseClasses::Reflect(m_serializeContext.get());
  5439. ClassWithAVectorOfBaseClasses vectorContainer;
  5440. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  5441. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  5442. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  5443. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  5444. AZStd::vector<char> charBuffer;
  5445. AZ::IO::ByteContainerStream<AZStd::vector<char> > containerStream(&charBuffer);
  5446. bool success = AZ::Utils::SaveObjectToStream(containerStream, AZ::ObjectStream::ST_XML, &vectorContainer, m_serializeContext.get());
  5447. EXPECT_TRUE(success);
  5448. // (remove it, but without deprecating)
  5449. m_serializeContext->EnableRemoveReflection();
  5450. DerivedClass2::Reflect(m_serializeContext.get());
  5451. m_serializeContext->DisableRemoveReflection();
  5452. // load it, we expect errors:
  5453. ClassWithAVectorOfBaseClasses loadedContainer;
  5454. AZ_TEST_START_TRACE_SUPPRESSION;
  5455. success = AZ::Utils::LoadObjectFromBufferInPlace(charBuffer.data(), charBuffer.size(), loadedContainer, m_serializeContext.get());
  5456. AZ_TEST_STOP_TRACE_SUPPRESSION(2); // 2 classes should have failed and generated warnings/errors
  5457. EXPECT_TRUE(success);
  5458. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses.size(), 2); // we still preserve the ones we CAN read.
  5459. for (auto baseclass : loadedContainer.m_vectorOfBaseClasses)
  5460. {
  5461. // we should only have baseclass1's in there.
  5462. EXPECT_EQ(baseclass->RTTI_GetType(), azrtti_typeid<DerivedClass1>());
  5463. }
  5464. }
  5465. // Prove that if you properly deprecate a member of a vector of baseclass pointers, the container
  5466. // removes the element instead of leaving a null and does not emit an error
  5467. TEST_F(ObjectStreamSerialization, DeprecatedVectorElements_LeaveNoGaps_DoesNotError)
  5468. {
  5469. using namespace ContainerElementDeprecationTestData;
  5470. // make sure that when a component is deprecated, it is removed during deserialization,
  5471. // and does not leave a hole that is a nullptr.
  5472. ClassWithAVectorOfBaseClasses::Reflect(m_serializeContext.get());
  5473. ClassWithAVectorOfBaseClasses vectorContainer;
  5474. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  5475. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  5476. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  5477. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  5478. AZStd::vector<char> charBuffer;
  5479. AZ::IO::ByteContainerStream<AZStd::vector<char> > containerStream(&charBuffer);
  5480. bool success = AZ::Utils::SaveObjectToStream(containerStream, AZ::ObjectStream::ST_XML, &vectorContainer, m_serializeContext.get());
  5481. EXPECT_TRUE(success);
  5482. // remove it and properly deprecate it
  5483. m_serializeContext->EnableRemoveReflection();
  5484. DerivedClass2::Reflect(m_serializeContext.get());
  5485. m_serializeContext->DisableRemoveReflection();
  5486. m_serializeContext->ClassDeprecate("Dummy UUID", azrtti_typeid<DerivedClass2>());
  5487. ClassWithAVectorOfBaseClasses loadedContainer;
  5488. // it should generate no warnings but the deprecated ones should not be there.
  5489. success = AZ::Utils::LoadObjectFromBufferInPlace(charBuffer.data(), charBuffer.size(), loadedContainer, m_serializeContext.get());
  5490. EXPECT_TRUE(success);
  5491. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses.size(), 2); // we still preserve the ones we CAN read.
  5492. for (auto baseclass : loadedContainer.m_vectorOfBaseClasses)
  5493. {
  5494. // we should only have baseclass1's in there.
  5495. EXPECT_EQ(baseclass->RTTI_GetType(), azrtti_typeid<DerivedClass1>());
  5496. }
  5497. }
  5498. // Prove that if you deprecate but upgrade a member of a vector of baseclass pointers, the container
  5499. // contains the freshly upgraded element instead of leaving a null and does not emit an error
  5500. TEST_F(ObjectStreamSerialization, DeprecatedVectorElements_ConvertedClass_DoesNotError_DoesNotDiscardData)
  5501. {
  5502. using namespace ContainerElementDeprecationTestData;
  5503. // make sure that when a component is deprecated, it is removed during deserialization
  5504. // and does not leave a hole that is a nullptr.
  5505. ClassWithAVectorOfBaseClasses::Reflect(m_serializeContext.get());
  5506. ClassWithAVectorOfBaseClasses vectorContainer;
  5507. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  5508. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  5509. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass1());
  5510. vectorContainer.m_vectorOfBaseClasses.push_back(new DerivedClass2());
  5511. AZStd::vector<char> charBuffer;
  5512. AZ::IO::ByteContainerStream<AZStd::vector<char> > containerStream(&charBuffer);
  5513. bool success = AZ::Utils::SaveObjectToStream(containerStream, AZ::ObjectStream::ST_XML, &vectorContainer, m_serializeContext.get());
  5514. EXPECT_TRUE(success);
  5515. // remove it and properly deprecate it with a converter that will upgrade it.
  5516. m_serializeContext->EnableRemoveReflection();
  5517. DerivedClass2::Reflect(m_serializeContext.get());
  5518. m_serializeContext->DisableRemoveReflection();
  5519. m_serializeContext->ClassDeprecate("Dummy UUID", azrtti_typeid<DerivedClass2>(), ConvertDerivedClass2ToDerivedClass3);
  5520. ClassWithAVectorOfBaseClasses loadedContainer;
  5521. // it should generate no warnings but the deprecated ones should not be there.
  5522. success = AZ::Utils::LoadObjectFromBufferInPlace(charBuffer.data(), charBuffer.size(), loadedContainer, m_serializeContext.get());
  5523. EXPECT_TRUE(success);
  5524. ASSERT_EQ(loadedContainer.m_vectorOfBaseClasses.size(), 4); // we still preserve the ones we CAN read.
  5525. // this also proves it does not shuffle elements around.
  5526. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses[0]->RTTI_GetType(), azrtti_typeid<DerivedClass1>());
  5527. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses[1]->RTTI_GetType(), azrtti_typeid<DerivedClass3>());
  5528. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses[2]->RTTI_GetType(), azrtti_typeid<DerivedClass1>());
  5529. EXPECT_EQ(loadedContainer.m_vectorOfBaseClasses[3]->RTTI_GetType(), azrtti_typeid<DerivedClass3>());
  5530. }
  5531. TEST_F(ObjectStreamSerialization, LoadObjectFromStreamInPlaceFailureDoesNotLeak)
  5532. {
  5533. RootElementMemoryTracker::Reflect(m_serializeContext.get());
  5534. AZStd::vector<AZ::u8> byteBuffer;
  5535. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5536. {
  5537. RootElementMemoryTracker saveTracker;
  5538. EXPECT_TRUE(AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, &saveTracker, m_serializeContext.get()));
  5539. byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5540. }
  5541. // Attempt to load a RootElementMemoryTracker into an int64_t
  5542. int64_t loadTracker;
  5543. AZ_TEST_START_TRACE_SUPPRESSION;
  5544. EXPECT_FALSE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadTracker, m_serializeContext.get()));
  5545. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  5546. EXPECT_EQ(0U, RootElementMemoryTracker::s_allocatedInstance);
  5547. }
  5548. struct EmptyDeprecatedClass
  5549. {
  5550. AZ_TYPE_INFO(EmptyDeprecatedClass, "{73890A64-9ADB-4639-B0E0-93294CE81B19}");
  5551. };
  5552. struct ConvertedNewClass
  5553. {
  5554. AZ_TYPE_INFO(ConvertedNewClass, "{BE892776-3830-43E5-873C-38A1CA6EF4BB}");
  5555. int32_t m_value{ 5 };
  5556. };
  5557. struct AggregateTestClassV1
  5558. {
  5559. AZ_TYPE_INFO(AggregateTestClassV1, "{088E3B16-4D93-4116-A747-706BE132AF5F}");
  5560. EmptyDeprecatedClass m_testField;
  5561. AZ::Vector3 m_position = AZ::Vector3::CreateZero();
  5562. EmptyDeprecatedClass m_value;
  5563. };
  5564. struct AggregateTestClassV2
  5565. {
  5566. // AggregateTestClassV2 Uuid should match version 1, It isn't the class that
  5567. // is being converted, but it's m_value that is.
  5568. AZ_TYPE_INFO(AggregateTestClassV2, "{088E3B16-4D93-4116-A747-706BE132AF5F}");
  5569. ConvertedNewClass m_testField;
  5570. AZ::Vector3 m_position = AZ::Vector3::CreateZero();
  5571. ConvertedNewClass m_value;
  5572. };
  5573. TEST_F(ObjectStreamSerialization, LoadNonDeprecatedElement_FollowedByZeroSizeDeprecatedElement_DoesNotAssert)
  5574. {
  5575. m_serializeContext->Class<EmptyDeprecatedClass>();
  5576. m_serializeContext->Class<AggregateTestClassV1>()
  5577. ->Field("m_testField", &AggregateTestClassV1::m_testField)
  5578. ->Field("m_position", &AggregateTestClassV1::m_position)
  5579. ->Field("m_value", &AggregateTestClassV1::m_value)
  5580. ;
  5581. // Write out AggrgateTestClassV1 instance
  5582. AggregateTestClassV1 testData;
  5583. testData.m_position = AZ::Vector3(1.0f, 2.0f, 3.0f);
  5584. AZStd::vector<AZ::u8> byteBuffer;
  5585. AZ::IO::ByteContainerStream<decltype(byteBuffer)> saveStream(&byteBuffer);
  5586. {
  5587. EXPECT_TRUE(AZ::Utils::SaveObjectToStream(saveStream, AZ::DataStream::ST_XML, &testData, m_serializeContext.get()));
  5588. saveStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5589. }
  5590. // Unreflect AggregateTestClassV1
  5591. m_serializeContext->EnableRemoveReflection();
  5592. m_serializeContext->Class<EmptyDeprecatedClass>();
  5593. m_serializeContext->Class<AggregateTestClassV1>();
  5594. m_serializeContext->DisableRemoveReflection();
  5595. // Reflect AggregateTestClassV2 and load the AggregateTestClassV1 data into memory
  5596. m_serializeContext->Class<ConvertedNewClass>()
  5597. ->Field("m_value", &ConvertedNewClass::m_value)
  5598. ;
  5599. m_serializeContext->Class<AggregateTestClassV2>()
  5600. ->Field("m_testField", &AggregateTestClassV2::m_testField)
  5601. ->Field("m_position", &AggregateTestClassV2::m_position)
  5602. ->Field("m_value", &AggregateTestClassV2::m_value)
  5603. ;
  5604. m_serializeContext->ClassDeprecate("EmptyDeprecatedClass", AZ::Uuid("{73890A64-9ADB-4639-B0E0-93294CE81B19}"),
  5605. [](AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& rootElementNode) -> bool
  5606. {
  5607. rootElementNode.Convert<ConvertedNewClass>(context);
  5608. return true;
  5609. });
  5610. AggregateTestClassV2 resultData;
  5611. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(saveStream, resultData, m_serializeContext.get()));
  5612. EXPECT_TRUE(testData.m_position.IsClose(resultData.m_position));
  5613. EXPECT_EQ(5, resultData.m_value.m_value);
  5614. // Cleanup - Unreflect the AggregateTestClassV2, ConvertedNewClass and the EmptyDeprecatedClass
  5615. m_serializeContext->EnableRemoveReflection();
  5616. m_serializeContext->Class<ConvertedNewClass>();
  5617. m_serializeContext->Class<AggregateTestClassV2>();
  5618. m_serializeContext->ClassDeprecate("EmptyDeprecatedClass", AZ::Uuid("{73890A64-9ADB-4639-B0E0-93294CE81B19}"),
  5619. [](AZ::SerializeContext&, AZ::SerializeContext::DataElementNode&) -> bool
  5620. {
  5621. return true;
  5622. });
  5623. m_serializeContext->DisableRemoveReflection();
  5624. }
  5625. struct ClassWithObjectStreamCallback
  5626. {
  5627. AZ_TYPE_INFO(ClassWithObjectStreamCallback, "{780F96D2-9907-439D-94B2-60B915BC12F6}");
  5628. AZ_CLASS_ALLOCATOR(ClassWithObjectStreamCallback, AZ::SystemAllocator);
  5629. ClassWithObjectStreamCallback() = default;
  5630. ClassWithObjectStreamCallback(int32_t value)
  5631. : m_value{ value }
  5632. {}
  5633. static void ReflectWithEventHandler(ReflectContext* context, SerializeContext::IEventHandler* eventHandler)
  5634. {
  5635. if (auto serializeContext = azrtti_cast<SerializeContext*>(context))
  5636. {
  5637. //Reflected Template classes must be reflected in one field
  5638. serializeContext->Class<ClassWithObjectStreamCallback>()
  5639. ->EventHandler(eventHandler)
  5640. ->Field("m_value", &ClassWithObjectStreamCallback::m_value)
  5641. ;
  5642. }
  5643. }
  5644. class ObjectStreamEventHandler
  5645. : public SerializeContext::IEventHandler
  5646. {
  5647. public:
  5648. MOCK_METHOD1(OnLoadedFromObjectStream, void(void*));
  5649. MOCK_METHOD1(OnObjectCloned, void(void*));
  5650. };
  5651. int32_t m_value{};
  5652. };
  5653. TEST_F(ObjectStreamSerialization, OnLoadedFromObjectStreamIsInvokedForObjectStreamLoading)
  5654. {
  5655. ClassWithObjectStreamCallback::ObjectStreamEventHandler mockEventHandler;
  5656. EXPECT_CALL(mockEventHandler, OnLoadedFromObjectStream(testing::_)).Times(1);
  5657. ClassWithObjectStreamCallback::ReflectWithEventHandler(m_serializeContext.get(), &mockEventHandler);
  5658. AZStd::vector<AZ::u8> byteBuffer;
  5659. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5660. {
  5661. ClassWithObjectStreamCallback saveObject{ 1234349 };
  5662. AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, &saveObject, m_serializeContext.get());
  5663. byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5664. }
  5665. ClassWithObjectStreamCallback loadObject;
  5666. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadObject, m_serializeContext.get());
  5667. }
  5668. TEST_F(ObjectStreamSerialization, OnLoadedFromObjectStreamIsNotInvokedForCloneObject)
  5669. {
  5670. ClassWithObjectStreamCallback::ObjectStreamEventHandler mockEventHandler;
  5671. EXPECT_CALL(mockEventHandler, OnLoadedFromObjectStream(testing::_)).Times(0);
  5672. EXPECT_CALL(mockEventHandler, OnObjectCloned(testing::_)).Times(1);
  5673. ClassWithObjectStreamCallback::ReflectWithEventHandler(m_serializeContext.get(), &mockEventHandler);
  5674. AZStd::vector<AZ::u8> byteBuffer;
  5675. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5676. ClassWithObjectStreamCallback saveObject{ 5 };
  5677. ClassWithObjectStreamCallback cloneObject;
  5678. m_serializeContext->CloneObjectInplace(cloneObject, &saveObject);
  5679. }
  5680. TEST_F(ObjectStreamSerialization, OnClonedObjectIsInvokedForCloneObject)
  5681. {
  5682. ClassWithObjectStreamCallback::ObjectStreamEventHandler mockEventHandler;
  5683. EXPECT_CALL(mockEventHandler, OnObjectCloned(testing::_)).Times(2);
  5684. ClassWithObjectStreamCallback::ReflectWithEventHandler(m_serializeContext.get(), &mockEventHandler);
  5685. AZStd::vector<AZ::u8> byteBuffer;
  5686. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5687. ClassWithObjectStreamCallback saveObject{ 5 };
  5688. ClassWithObjectStreamCallback cloneObject;
  5689. m_serializeContext->CloneObjectInplace(cloneObject, &saveObject);
  5690. // Cloning the cloned object should increase the newly cloned object m_value by one again
  5691. ClassWithObjectStreamCallback secondCloneObject;
  5692. m_serializeContext->CloneObjectInplace(secondCloneObject, &cloneObject);
  5693. }
  5694. TEST_F(ObjectStreamSerialization, OnClonedObjectIsNotInvokedForObjectStreamLoading)
  5695. {
  5696. ClassWithObjectStreamCallback::ObjectStreamEventHandler mockEventHandler;
  5697. EXPECT_CALL(mockEventHandler, OnObjectCloned(testing::_)).Times(0);
  5698. EXPECT_CALL(mockEventHandler, OnLoadedFromObjectStream(testing::_)).Times(1);
  5699. ClassWithObjectStreamCallback::ReflectWithEventHandler(m_serializeContext.get(), &mockEventHandler);
  5700. AZStd::vector<AZ::u8> byteBuffer;
  5701. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5702. {
  5703. ClassWithObjectStreamCallback saveObject{ -396320 };
  5704. AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, &saveObject, m_serializeContext.get());
  5705. byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  5706. }
  5707. ClassWithObjectStreamCallback loadObject;
  5708. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadObject, m_serializeContext.get());
  5709. }
  5710. class GenericClassInfoExplicitReflectFixture
  5711. : public LeakDetectionFixture
  5712. {
  5713. public:
  5714. void SetUp() override
  5715. {
  5716. LeakDetectionFixture::SetUp();
  5717. m_serializeContext = AZStd::make_unique<SerializeContext>();
  5718. AZ::GenericClassInfo* genericInfo = SerializeGenericTypeInfo<AZStd::vector<AZ::u32>>::GetGenericInfo();
  5719. if (genericInfo)
  5720. {
  5721. genericInfo->Reflect(m_serializeContext.get());
  5722. }
  5723. genericInfo = SerializeGenericTypeInfo<AZStd::string>::GetGenericInfo();
  5724. if (genericInfo)
  5725. {
  5726. genericInfo->Reflect(m_serializeContext.get());
  5727. }
  5728. genericInfo = SerializeGenericTypeInfo<AZStd::unordered_map<float, float>>::GetGenericInfo();
  5729. if (genericInfo)
  5730. {
  5731. genericInfo->Reflect(m_serializeContext.get());
  5732. }
  5733. }
  5734. void TearDown() override
  5735. {
  5736. m_serializeContext->EnableRemoveReflection();
  5737. AZ::GenericClassInfo* genericInfo = SerializeGenericTypeInfo<AZStd::vector<AZ::u32>>::GetGenericInfo();
  5738. if (genericInfo)
  5739. {
  5740. genericInfo->Reflect(m_serializeContext.get());
  5741. }
  5742. genericInfo = SerializeGenericTypeInfo<AZStd::string>::GetGenericInfo();
  5743. if (genericInfo)
  5744. {
  5745. genericInfo->Reflect(m_serializeContext.get());
  5746. }
  5747. genericInfo = SerializeGenericTypeInfo<AZStd::unordered_map<float, float>>::GetGenericInfo();
  5748. if (genericInfo)
  5749. {
  5750. genericInfo->Reflect(m_serializeContext.get());
  5751. }
  5752. m_serializeContext->DisableRemoveReflection();
  5753. m_serializeContext.reset();
  5754. LeakDetectionFixture::TearDown();
  5755. }
  5756. protected:
  5757. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  5758. };
  5759. TEST_F(GenericClassInfoExplicitReflectFixture, RootVectorTest)
  5760. {
  5761. AZStd::vector<AZ::u32> rootVector{ 7, 3, 5, 7 };
  5762. {
  5763. // Serializing vector as root class
  5764. AZStd::vector<char> byteBuffer;
  5765. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  5766. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  5767. byteObjStream->WriteClass(&rootVector);
  5768. byteObjStream->Finalize();
  5769. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  5770. AZStd::vector<AZ::u32> loadedVector;
  5771. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadedVector, m_serializeContext.get());
  5772. EXPECT_EQ(rootVector, loadedVector);
  5773. }
  5774. }
  5775. TEST_F(GenericClassInfoExplicitReflectFixture, RootStringTest)
  5776. {
  5777. AZStd::string rootString("TestString");
  5778. {
  5779. // Serializing string as root class
  5780. AZStd::vector<char> byteBuffer;
  5781. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  5782. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  5783. byteObjStream->WriteClass(&rootString);
  5784. byteObjStream->Finalize();
  5785. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  5786. AZStd::string loadedString;
  5787. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadedString, m_serializeContext.get());
  5788. EXPECT_EQ(rootString, loadedString);
  5789. }
  5790. }
  5791. TEST_F(GenericClassInfoExplicitReflectFixture, RootUnorderedMapTest)
  5792. {
  5793. AZStd::unordered_map<float, float> rootMap;
  5794. rootMap.emplace(7.0f, 20.1f);
  5795. rootMap.emplace(0.0f, 17.0f);
  5796. {
  5797. // Serializing vector as root class
  5798. AZStd::vector<char> byteBuffer;
  5799. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  5800. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  5801. byteObjStream->WriteClass(&rootMap);
  5802. byteObjStream->Finalize();
  5803. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  5804. AZStd::unordered_map<float, float> loadedMap;
  5805. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadedMap, m_serializeContext.get());
  5806. EXPECT_EQ(rootMap, loadedMap);
  5807. }
  5808. }
  5809. class GenericClassInfoInheritanceFixture
  5810. : public LeakDetectionFixture
  5811. {
  5812. public:
  5813. void SetUp() override
  5814. {
  5815. LeakDetectionFixture::SetUp();
  5816. m_serializeContext = AZStd::make_unique<SerializeContext>();
  5817. StringUtils::Reflect(m_serializeContext.get());
  5818. }
  5819. void TearDown() override
  5820. {
  5821. m_serializeContext->EnableRemoveReflection();
  5822. StringUtils::Reflect(m_serializeContext.get());
  5823. m_serializeContext->DisableRemoveReflection();
  5824. m_serializeContext.reset();
  5825. LeakDetectionFixture::TearDown();
  5826. }
  5827. class StringUtils : public AZStd::string
  5828. {
  5829. public:
  5830. StringUtils() = default;
  5831. StringUtils(const char* constString)
  5832. : AZStd::string(constString)
  5833. {}
  5834. AZ_TYPE_INFO(StringUtils, "{F3CCCFC0-7890-46A4-9246-067E8A9D2FDE}");
  5835. static void Reflect(AZ::ReflectContext* context)
  5836. {
  5837. if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context))
  5838. {
  5839. serialize->Class<StringUtils, AZStd::string>();
  5840. }
  5841. }
  5842. // ... useful string manipulation functions ...
  5843. };
  5844. protected:
  5845. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  5846. };
  5847. TEST_F(GenericClassInfoInheritanceFixture, StringInheritanceTest)
  5848. {
  5849. StringUtils testStringUtils("Custom String");
  5850. // BINARY
  5851. AZStd::vector<char> byteBuffer;
  5852. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  5853. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_BINARY);
  5854. byteObjStream->WriteClass(&testStringUtils);
  5855. byteObjStream->Finalize();
  5856. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  5857. StringUtils loadStringUtils;
  5858. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadStringUtils, m_serializeContext.get());
  5859. EXPECT_EQ(testStringUtils, loadStringUtils);
  5860. }
  5861. class SerializableTupleTest
  5862. : public LeakDetectionFixture
  5863. {
  5864. public:
  5865. using FloatStringIntTuple = std::tuple<float, AZStd::string, int>;
  5866. using EntityIdEntityTuple = std::tuple<AZ::EntityId, AZ::Entity*>;
  5867. using AnyAnyAnyTuple = std::tuple<AZStd::any, AZStd::any, AZStd::any>;
  5868. using SmartPtrAnyTuple = std::tuple<AZStd::shared_ptr<AZStd::any>>;
  5869. using EmptyTuple = std::tuple<>;
  5870. using TupleCeption = std::tuple<std::tuple<AZStd::string>>;
  5871. using EntityIdVectorStringMap = AZStd::unordered_map<AZ::EntityId, AZStd::vector<AZStd::string>>;
  5872. // We must expose the class for serialization first.
  5873. void SetUp() override
  5874. {
  5875. LeakDetectionFixture::SetUp();
  5876. m_serializeContext = AZStd::make_unique<SerializeContext>();
  5877. AZ::Entity::Reflect(m_serializeContext.get());
  5878. AZ::GenericClassInfo* genericClassInfo = SerializeGenericTypeInfo<FloatStringIntTuple>::GetGenericInfo();
  5879. if (genericClassInfo)
  5880. {
  5881. genericClassInfo->Reflect(m_serializeContext.get());
  5882. }
  5883. genericClassInfo = SerializeGenericTypeInfo<EntityIdEntityTuple>::GetGenericInfo();
  5884. if (genericClassInfo)
  5885. {
  5886. genericClassInfo->Reflect(m_serializeContext.get());
  5887. }
  5888. genericClassInfo = SerializeGenericTypeInfo<AnyAnyAnyTuple>::GetGenericInfo();
  5889. if (genericClassInfo)
  5890. {
  5891. genericClassInfo->Reflect(m_serializeContext.get());
  5892. }
  5893. genericClassInfo = SerializeGenericTypeInfo<SmartPtrAnyTuple>::GetGenericInfo();
  5894. if (genericClassInfo)
  5895. {
  5896. genericClassInfo->Reflect(m_serializeContext.get());
  5897. }
  5898. genericClassInfo = SerializeGenericTypeInfo<EntityIdVectorStringMap>::GetGenericInfo();
  5899. if (genericClassInfo)
  5900. {
  5901. genericClassInfo->Reflect(m_serializeContext.get());
  5902. }
  5903. genericClassInfo = SerializeGenericTypeInfo<EmptyTuple>::GetGenericInfo();
  5904. if (genericClassInfo)
  5905. {
  5906. genericClassInfo->Reflect(m_serializeContext.get());
  5907. }
  5908. genericClassInfo = SerializeGenericTypeInfo<TupleCeption>::GetGenericInfo();
  5909. if (genericClassInfo)
  5910. {
  5911. genericClassInfo->Reflect(m_serializeContext.get());
  5912. }
  5913. }
  5914. void TearDown() override
  5915. {
  5916. m_serializeContext->EnableRemoveReflection();
  5917. AZ::Entity::Reflect(m_serializeContext.get());
  5918. AZ::GenericClassInfo* genericClassInfo = SerializeGenericTypeInfo<FloatStringIntTuple>::GetGenericInfo();
  5919. if (genericClassInfo)
  5920. {
  5921. genericClassInfo->Reflect(m_serializeContext.get());
  5922. }
  5923. genericClassInfo = SerializeGenericTypeInfo<EntityIdEntityTuple>::GetGenericInfo();
  5924. if (genericClassInfo)
  5925. {
  5926. genericClassInfo->Reflect(m_serializeContext.get());
  5927. }
  5928. genericClassInfo = SerializeGenericTypeInfo<AnyAnyAnyTuple>::GetGenericInfo();
  5929. if (genericClassInfo)
  5930. {
  5931. genericClassInfo->Reflect(m_serializeContext.get());
  5932. }
  5933. genericClassInfo = SerializeGenericTypeInfo<SmartPtrAnyTuple>::GetGenericInfo();
  5934. if (genericClassInfo)
  5935. {
  5936. genericClassInfo->Reflect(m_serializeContext.get());
  5937. }
  5938. genericClassInfo = SerializeGenericTypeInfo<EntityIdVectorStringMap>::GetGenericInfo();
  5939. if (genericClassInfo)
  5940. {
  5941. genericClassInfo->Reflect(m_serializeContext.get());
  5942. }
  5943. genericClassInfo = SerializeGenericTypeInfo<EmptyTuple>::GetGenericInfo();
  5944. if (genericClassInfo)
  5945. {
  5946. genericClassInfo->Reflect(m_serializeContext.get());
  5947. }
  5948. genericClassInfo = SerializeGenericTypeInfo<TupleCeption>::GetGenericInfo();
  5949. if (genericClassInfo)
  5950. {
  5951. genericClassInfo->Reflect(m_serializeContext.get());
  5952. }
  5953. m_serializeContext->DisableRemoveReflection();
  5954. m_serializeContext.reset();
  5955. LeakDetectionFixture::TearDown();
  5956. }
  5957. protected:
  5958. AZStd::unique_ptr<SerializeContext> m_serializeContext;
  5959. };
  5960. TEST_F(SerializableTupleTest, EmptyTupleTest)
  5961. {
  5962. EmptyTuple testTuple;
  5963. AZStd::vector<char> byteBuffer;
  5964. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5965. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  5966. objStream->WriteClass(&testTuple);
  5967. objStream->Finalize();
  5968. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  5969. EmptyTuple loadTuple;
  5970. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadTuple, m_serializeContext.get()));
  5971. EXPECT_EQ(testTuple, loadTuple);
  5972. }
  5973. TEST_F(SerializableTupleTest, BasicTypeTest)
  5974. {
  5975. FloatStringIntTuple testTuple{ 3.14f, "Tuple", -1 };
  5976. AZStd::vector<char> byteBuffer;
  5977. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5978. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  5979. objStream->WriteClass(&testTuple);
  5980. objStream->Finalize();
  5981. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  5982. FloatStringIntTuple loadTuple;
  5983. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadTuple, m_serializeContext.get()));
  5984. EXPECT_EQ(testTuple, loadTuple);
  5985. }
  5986. TEST_F(SerializableTupleTest, PointerTupleTest)
  5987. {
  5988. EntityIdEntityTuple testTuple{ AZ::Entity::MakeId(), aznew AZ::Entity("Tuple") };
  5989. AZStd::vector<char> byteBuffer;
  5990. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  5991. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  5992. objStream->WriteClass(&testTuple);
  5993. objStream->Finalize();
  5994. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  5995. EntityIdEntityTuple loadTuple;
  5996. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadTuple, m_serializeContext.get()));
  5997. EXPECT_EQ(std::get<0>(testTuple), std::get<0>(loadTuple));
  5998. EXPECT_EQ(std::get<1>(testTuple)->GetId(), std::get<1>(loadTuple)->GetId());
  5999. delete std::get<1>(testTuple);
  6000. delete std::get<1>(loadTuple);
  6001. }
  6002. TEST_F(SerializableTupleTest, TupleAnyTest)
  6003. {
  6004. AnyAnyAnyTuple testTuple{ AZStd::make_any<AZStd::string>("FirstAny"), AZStd::any(EntityIdVectorStringMap()), AZStd::make_any<AZ::Entity>("Tuple") };
  6005. AZStd::vector<char> byteBuffer;
  6006. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6007. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  6008. objStream->WriteClass(&testTuple);
  6009. objStream->Finalize();
  6010. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6011. AnyAnyAnyTuple loadTuple;
  6012. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadTuple, m_serializeContext.get()));
  6013. auto testStringPtr = AZStd::any_cast<AZStd::string>(&std::get<0>(testTuple));
  6014. ASSERT_NE(nullptr, testStringPtr);
  6015. auto loadStringPtr = AZStd::any_cast<AZStd::string>(&std::get<0>(loadTuple));
  6016. ASSERT_NE(nullptr, loadStringPtr);
  6017. auto testMapPtr = AZStd::any_cast<EntityIdVectorStringMap>(&std::get<1>(testTuple));
  6018. ASSERT_NE(nullptr, testMapPtr);
  6019. auto loadMapPtr = AZStd::any_cast<EntityIdVectorStringMap>(&std::get<1>(loadTuple));
  6020. ASSERT_NE(nullptr, loadMapPtr);
  6021. auto testEntityPtr = AZStd::any_cast<AZ::Entity>(&std::get<2>(testTuple));
  6022. ASSERT_NE(nullptr, testEntityPtr);
  6023. auto loadEntityPtr = AZStd::any_cast<AZ::Entity>(&std::get<2>(loadTuple));
  6024. ASSERT_NE(nullptr, loadEntityPtr);
  6025. EXPECT_EQ(*testStringPtr, *loadStringPtr);
  6026. EXPECT_EQ(*testMapPtr, *loadMapPtr);
  6027. EXPECT_EQ(testEntityPtr->GetId(), loadEntityPtr->GetId());
  6028. }
  6029. TEST_F(SerializableTupleTest, UniquePtrAnyTupleTest)
  6030. {
  6031. SmartPtrAnyTuple testTuple{ AZStd::make_shared<AZStd::any>(AZStd::make_any<AZStd::string>("SuperWrappedString")) };
  6032. AZStd::vector<char> byteBuffer;
  6033. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6034. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  6035. objStream->WriteClass(&testTuple);
  6036. objStream->Finalize();
  6037. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6038. SmartPtrAnyTuple loadTuple;
  6039. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadTuple, m_serializeContext.get()));
  6040. auto rawTestPtr = std::get<0>(testTuple).get();
  6041. auto rawLoadPtr = std::get<0>(loadTuple).get();
  6042. ASSERT_NE(nullptr, rawLoadPtr);
  6043. auto testStringPtr = AZStd::any_cast<AZStd::string>(rawTestPtr);
  6044. ASSERT_NE(nullptr, testStringPtr);
  6045. auto loadStringPtr = AZStd::any_cast<AZStd::string>(rawLoadPtr);
  6046. ASSERT_NE(nullptr, loadStringPtr);
  6047. EXPECT_EQ(*testStringPtr, *loadStringPtr);
  6048. }
  6049. TEST_F(SerializableTupleTest, 2Fast2TuplesTest)
  6050. {
  6051. TupleCeption testTuple{ AZStd::make_tuple(AZStd::string("InnerTupleString")) };
  6052. AZStd::vector<char> byteBuffer;
  6053. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6054. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  6055. objStream->WriteClass(&testTuple);
  6056. objStream->Finalize();
  6057. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6058. TupleCeption loadTuple;
  6059. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadTuple, m_serializeContext.get()));
  6060. EXPECT_EQ(testTuple, loadTuple);
  6061. }
  6062. class SerializableAZStdArrayTest
  6063. : public LeakDetectionFixture
  6064. {
  6065. public:
  6066. using ZeroArray = AZStd::array<float, 0>;
  6067. using FloatFourArray = AZStd::array<float, 4>;
  6068. using ZeroNestedArray = AZStd::array<AZStd::array<float, 0>, 0>;
  6069. using NestedArray = AZStd::array<AZStd::array<FloatFourArray, 3>, 2>;
  6070. // We must expose the class for serialization first.
  6071. void SetUp() override
  6072. {
  6073. LeakDetectionFixture::SetUp();
  6074. m_serializeContext = AZStd::make_unique<SerializeContext>();
  6075. AZ::GenericClassInfo* genericClassInfo = SerializeGenericTypeInfo<ZeroArray>::GetGenericInfo();
  6076. if (genericClassInfo)
  6077. {
  6078. genericClassInfo->Reflect(m_serializeContext.get());
  6079. }
  6080. genericClassInfo = SerializeGenericTypeInfo<FloatFourArray>::GetGenericInfo();
  6081. if (genericClassInfo)
  6082. {
  6083. genericClassInfo->Reflect(m_serializeContext.get());
  6084. }
  6085. genericClassInfo = SerializeGenericTypeInfo<ZeroNestedArray>::GetGenericInfo();
  6086. if (genericClassInfo)
  6087. {
  6088. genericClassInfo->Reflect(m_serializeContext.get());
  6089. }
  6090. genericClassInfo = SerializeGenericTypeInfo<NestedArray>::GetGenericInfo();
  6091. if (genericClassInfo)
  6092. {
  6093. genericClassInfo->Reflect(m_serializeContext.get());
  6094. }
  6095. }
  6096. void TearDown() override
  6097. {
  6098. m_serializeContext->EnableRemoveReflection();
  6099. AZ::GenericClassInfo* genericClassInfo = SerializeGenericTypeInfo<ZeroArray>::GetGenericInfo();
  6100. if (genericClassInfo)
  6101. {
  6102. genericClassInfo->Reflect(m_serializeContext.get());
  6103. }
  6104. genericClassInfo = SerializeGenericTypeInfo<FloatFourArray>::GetGenericInfo();
  6105. if (genericClassInfo)
  6106. {
  6107. genericClassInfo->Reflect(m_serializeContext.get());
  6108. }
  6109. genericClassInfo = SerializeGenericTypeInfo<ZeroNestedArray>::GetGenericInfo();
  6110. if (genericClassInfo)
  6111. {
  6112. genericClassInfo->Reflect(m_serializeContext.get());
  6113. }
  6114. genericClassInfo = SerializeGenericTypeInfo<NestedArray>::GetGenericInfo();
  6115. if (genericClassInfo)
  6116. {
  6117. genericClassInfo->Reflect(m_serializeContext.get());
  6118. }
  6119. m_serializeContext->DisableRemoveReflection();
  6120. m_serializeContext.reset();
  6121. LeakDetectionFixture::TearDown();
  6122. }
  6123. protected:
  6124. FloatFourArray m_array;
  6125. AZStd::unique_ptr<SerializeContext> m_serializeContext;
  6126. };
  6127. TEST_F(SerializableAZStdArrayTest, SingleEntryCount)
  6128. {
  6129. Internal::AZStdArrayEvents events;
  6130. events.OnWriteBegin(&m_array);
  6131. for (size_t i = 0; i < 16; ++i)
  6132. {
  6133. EXPECT_EQ(i, events.GetIndex());
  6134. events.Increment();
  6135. }
  6136. for (size_t i = 16; i > 8; --i)
  6137. {
  6138. EXPECT_EQ(i, events.GetIndex());
  6139. events.Decrement();
  6140. }
  6141. events.OnWriteEnd(&m_array);
  6142. EXPECT_TRUE(events.IsEmpty());
  6143. }
  6144. TEST_F(SerializableAZStdArrayTest, MultipleEntriesCount)
  6145. {
  6146. Internal::AZStdArrayEvents events;
  6147. events.OnWriteBegin(&m_array);
  6148. for (size_t i = 0; i < 8; ++i)
  6149. {
  6150. events.Increment();
  6151. }
  6152. for (size_t i = 8; i > 4; --i)
  6153. {
  6154. EXPECT_EQ(i, events.GetIndex());
  6155. events.Decrement();
  6156. }
  6157. events.OnWriteBegin(&m_array);
  6158. for (size_t i = 0; i < 16; ++i)
  6159. {
  6160. EXPECT_EQ(i, events.GetIndex());
  6161. events.Increment();
  6162. }
  6163. for (size_t i = 16; i > 8; --i)
  6164. {
  6165. EXPECT_EQ(i, events.GetIndex());
  6166. events.Decrement();
  6167. }
  6168. events.OnWriteEnd(&m_array);
  6169. EXPECT_EQ(4, events.GetIndex()); // The 8 entries on the first entry of the stack.
  6170. events.OnWriteEnd(&m_array);
  6171. EXPECT_TRUE(events.IsEmpty());
  6172. }
  6173. TEST_F(SerializableAZStdArrayTest, SingleEntryContainerInterface)
  6174. {
  6175. GenericClassInfo* containerInfo = SerializeGenericTypeInfo<decltype(m_array)>::GetGenericInfo();
  6176. ASSERT_NE(nullptr, containerInfo);
  6177. ASSERT_NE(nullptr, containerInfo->GetClassData());
  6178. SerializeContext::IDataContainer* container = containerInfo->GetClassData()->m_container;
  6179. ASSERT_NE(nullptr, container);
  6180. SerializeContext::IEventHandler* eventHandler = containerInfo->GetClassData()->m_eventHandler;
  6181. ASSERT_NE(nullptr, eventHandler);
  6182. eventHandler->OnWriteBegin(&m_array);
  6183. void* element0 = container->ReserveElement(&m_array, nullptr);
  6184. ASSERT_NE(nullptr, element0);
  6185. *reinterpret_cast<float*>(element0) = 42.0f;
  6186. container->StoreElement(&m_array, element0);
  6187. void* element1 = container->ReserveElement(&m_array, nullptr);
  6188. ASSERT_NE(nullptr, element1);
  6189. *reinterpret_cast<float*>(element1) = 142.0f;
  6190. container->StoreElement(&m_array, element1);
  6191. void* deletedElement = container->ReserveElement(&m_array, nullptr);
  6192. ASSERT_NE(nullptr, deletedElement);
  6193. *reinterpret_cast<float*>(deletedElement) = 9000.0f;
  6194. container->RemoveElement(&m_array, deletedElement, nullptr);
  6195. void* element2 = container->ReserveElement(&m_array, nullptr);
  6196. ASSERT_NE(nullptr, element2);
  6197. *reinterpret_cast<float*>(element2) = 242.0f;
  6198. container->StoreElement(&m_array, element2);
  6199. void* element3 = container->ReserveElement(&m_array, nullptr);
  6200. ASSERT_NE(nullptr, element3);
  6201. *reinterpret_cast<float*>(element3) = 342.0f;
  6202. container->StoreElement(&m_array, element2);
  6203. void* overflownElement = container->ReserveElement(&m_array, nullptr);
  6204. EXPECT_EQ(nullptr, overflownElement);
  6205. eventHandler->OnWriteEnd(&m_array);
  6206. eventHandler->OnLoadedFromObjectStream(&m_array);
  6207. EXPECT_FLOAT_EQ( 42.0f, m_array[0]);
  6208. EXPECT_FLOAT_EQ(142.0f, m_array[1]);
  6209. EXPECT_FLOAT_EQ(242.0f, m_array[2]);
  6210. EXPECT_FLOAT_EQ(342.0f, m_array[3]);
  6211. }
  6212. TEST_F(SerializableAZStdArrayTest, SimpleSerialization)
  6213. {
  6214. m_array[0] = 10.0f;
  6215. m_array[1] = 11.1f;
  6216. m_array[2] = 12.2f;
  6217. m_array[3] = 13.3f;
  6218. AZStd::vector<char> byteBuffer;
  6219. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6220. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  6221. objStream->WriteClass(&m_array);
  6222. objStream->Finalize();
  6223. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6224. FloatFourArray loadedArray;
  6225. ASSERT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadedArray, m_serializeContext.get()));
  6226. for (size_t i = 0; i < 4; ++i)
  6227. {
  6228. EXPECT_EQ(m_array[i], loadedArray[i]);
  6229. }
  6230. }
  6231. TEST_F(SerializableAZStdArrayTest, NestedSerialization)
  6232. {
  6233. NestedArray nested;
  6234. nested[0][0][0] = 0.0f;
  6235. nested[0][0][1] = 0.1f;
  6236. nested[0][0][2] = 0.2f;
  6237. nested[0][0][3] = 0.3f;
  6238. nested[0][1][0] = 1.0f;
  6239. nested[0][1][1] = 1.1f;
  6240. nested[0][1][2] = 1.2f;
  6241. nested[0][1][3] = 1.3f;
  6242. nested[0][2][0] = 2.0f;
  6243. nested[0][2][1] = 2.1f;
  6244. nested[0][2][2] = 2.2f;
  6245. nested[0][2][3] = 2.3f;
  6246. nested[1][0][0] = 10.0f;
  6247. nested[1][0][1] = 10.1f;
  6248. nested[1][0][2] = 10.2f;
  6249. nested[1][0][3] = 10.3f;
  6250. nested[1][1][0] = 11.0f;
  6251. nested[1][1][1] = 11.1f;
  6252. nested[1][1][2] = 11.2f;
  6253. nested[1][1][3] = 11.3f;
  6254. nested[1][2][0] = 12.0f;
  6255. nested[1][2][1] = 12.1f;
  6256. nested[1][2][2] = 12.2f;
  6257. nested[1][2][3] = 12.3f;
  6258. AZStd::vector<char> byteBuffer;
  6259. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6260. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  6261. objStream->WriteClass(&nested);
  6262. objStream->Finalize();
  6263. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6264. NestedArray loadedArray;
  6265. ASSERT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadedArray, m_serializeContext.get()));
  6266. for (size_t l = 0; l < 2; ++l)
  6267. {
  6268. for (size_t k = 0; k < 3; ++k)
  6269. {
  6270. for (size_t i = 0; i < 4; ++i)
  6271. {
  6272. EXPECT_EQ(nested[l][k][i], loadedArray[l][k][i]);
  6273. }
  6274. }
  6275. }
  6276. }
  6277. TEST_F(SerializableAZStdArrayTest, ZeroSerialization)
  6278. {
  6279. ZeroArray zerroArray;
  6280. AZStd::vector<char> byteBuffer;
  6281. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6282. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  6283. objStream->WriteClass(&zerroArray);
  6284. objStream->Finalize();
  6285. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6286. ZeroArray loadedArray;
  6287. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadedArray, m_serializeContext.get()));
  6288. }
  6289. TEST_F(SerializableAZStdArrayTest, ZeroNestedSerialization)
  6290. {
  6291. ZeroNestedArray zerroArray;
  6292. AZStd::vector<char> byteBuffer;
  6293. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6294. auto objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_XML);
  6295. objStream->WriteClass(&zerroArray);
  6296. objStream->Finalize();
  6297. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6298. ZeroNestedArray loadedArray;
  6299. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadedArray, m_serializeContext.get()));
  6300. }
  6301. struct VectorTest
  6302. {
  6303. AZ_RTTI(VectorTest, "{2BE9FC5C-14A6-49A7-9A2C-79F6C2F27221}");
  6304. virtual ~VectorTest() = default;
  6305. AZStd::vector<int> m_vec;
  6306. static bool Convert(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  6307. {
  6308. AZStd::vector<int> vec;
  6309. AZ::SerializeContext::DataElementNode* vecElement = classElement.FindSubElement(AZ_CRC_CE("m_vec"));
  6310. EXPECT_TRUE(vecElement != nullptr);
  6311. bool gotData = vecElement->GetData(vec);
  6312. EXPECT_TRUE(gotData);
  6313. vec.push_back(42);
  6314. bool setData = vecElement->SetData(context, vec);
  6315. EXPECT_TRUE(setData);
  6316. return true;
  6317. }
  6318. };
  6319. // Splitting these tests up to make it easier to find memory leaks for specific containers.
  6320. TEST_F(Serialization, ReserveAndFreeWithoutMemLeaks_Array) { ReserveAndFreeWithoutMemLeaks<AZStd::array<float, 5>>(); }
  6321. TEST_F(Serialization, ReserveAndFreeWithoutMemLeaks_FixedVector) { ReserveAndFreeWithoutMemLeaks<AZStd::fixed_vector<float, 5>>(); }
  6322. TEST_F(Serialization, ReserveAndFreeWithoutMemLeaks_ForwardList) { ReserveAndFreeWithoutMemLeaks<AZStd::forward_list<float>>(); }
  6323. TEST_F(Serialization, ReserveAndFreeWithoutMemLeaks_UnorderedSet) { ReserveAndFreeWithoutMemLeaks<AZStd::unordered_set<float>>(); }
  6324. TEST_F(Serialization, ReserveAndFreeWithoutMemLeaks_UnorderedMultiSet) { ReserveAndFreeWithoutMemLeaks<AZStd::unordered_multiset<float>>(); }
  6325. TEST_F(Serialization, ReserveAndFreeWithoutMemLeaks_List) { ReserveAndFreeWithoutMemLeaks<AZStd::list<float>>(); }
  6326. TEST_F(Serialization, ReserveAndFreeWithoutMemLeaks_Set) { ReserveAndFreeWithoutMemLeaks<AZStd::set<float>>(); }
  6327. TEST_F(Serialization, ReserveAndFreeWithoutMemLeaks_Vector) { ReserveAndFreeWithoutMemLeaks<AZStd::vector<float>>(); }
  6328. TEST_F(Serialization, ConvertVectorContainer)
  6329. {
  6330. // Reflect version 1
  6331. m_serializeContext->Class<VectorTest>()
  6332. ->Version(1)
  6333. ->Field("m_vec", &VectorTest::m_vec);
  6334. VectorTest test;
  6335. test.m_vec.push_back(1024);
  6336. // write test to an XML buffer
  6337. AZStd::vector<char> byteBuffer;
  6338. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  6339. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_XML);
  6340. byteObjStream->WriteClass(&test);
  6341. byteObjStream->Finalize();
  6342. // Update the version to 2 and add the converter
  6343. m_serializeContext->EnableRemoveReflection();
  6344. m_serializeContext->Class<VectorTest>();
  6345. m_serializeContext->DisableRemoveReflection();
  6346. m_serializeContext->Class<VectorTest>()
  6347. ->Version(2, &VectorTest::Convert)
  6348. ->Field("m_vec", &VectorTest::m_vec);
  6349. // Reset for read
  6350. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6351. test = VectorTest{};
  6352. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, test, m_serializeContext.get());
  6353. EXPECT_EQ(2, test.m_vec.size());
  6354. }
  6355. class SerializeVectorWithInitialElementsTest
  6356. : public LeakDetectionFixture
  6357. {
  6358. public:
  6359. // We must expose the class for serialization first.
  6360. void SetUp() override
  6361. {
  6362. LeakDetectionFixture::SetUp();
  6363. m_serializeContext = AZStd::make_unique<SerializeContext>();
  6364. VectorWrapper::Reflect(m_serializeContext.get());
  6365. }
  6366. void TearDown() override
  6367. {
  6368. m_serializeContext.reset();
  6369. LeakDetectionFixture::TearDown();
  6370. }
  6371. struct VectorWrapper
  6372. {
  6373. AZ_TYPE_INFO(VectorWrapper, "{91F69715-30C3-4F1A-90A0-5F5F7517F375}");
  6374. AZ_CLASS_ALLOCATOR(VectorWrapper, AZ::SystemAllocator);
  6375. VectorWrapper()
  6376. : m_fixedVectorInts(2, 412)
  6377. , m_vectorInts(2, 42)
  6378. {}
  6379. static void Reflect(AZ::ReflectContext* context)
  6380. {
  6381. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  6382. {
  6383. serializeContext->Class<VectorWrapper>()
  6384. ->Field("fixedVectorInts", &VectorWrapper::m_fixedVectorInts)
  6385. ->Field("VectorInts", &VectorWrapper::m_vectorInts);
  6386. }
  6387. }
  6388. AZStd::fixed_vector<int, 2> m_fixedVectorInts;
  6389. AZStd::vector<int> m_vectorInts;
  6390. };
  6391. protected:
  6392. AZStd::unique_ptr<SerializeContext> m_serializeContext;
  6393. };
  6394. TEST_F(SerializeVectorWithInitialElementsTest, CloneObjectTest)
  6395. {
  6396. VectorWrapper vectorWrapper;
  6397. ASSERT_EQ(2, vectorWrapper.m_fixedVectorInts.size());
  6398. ASSERT_EQ(2, vectorWrapper.m_vectorInts.size());
  6399. vectorWrapper.m_fixedVectorInts[1] = 256;
  6400. vectorWrapper.m_vectorInts[0] = 5;
  6401. vectorWrapper.m_vectorInts[1] = 10;
  6402. VectorWrapper* clonedWrapper = m_serializeContext->CloneObject(&vectorWrapper);
  6403. ASSERT_NE(nullptr, clonedWrapper);
  6404. EXPECT_EQ(vectorWrapper.m_vectorInts.size(), clonedWrapper->m_vectorInts.size());
  6405. EXPECT_EQ(5, clonedWrapper->m_vectorInts[0]);
  6406. EXPECT_EQ(10, clonedWrapper->m_vectorInts[1]);
  6407. EXPECT_EQ(vectorWrapper.m_fixedVectorInts.size(), clonedWrapper->m_fixedVectorInts.size());
  6408. EXPECT_EQ(256, clonedWrapper->m_fixedVectorInts[1]);
  6409. delete clonedWrapper;
  6410. }
  6411. TEST_F(SerializeVectorWithInitialElementsTest, CloneObjectInplaceTest)
  6412. {
  6413. VectorWrapper vectorWrapper;
  6414. ASSERT_EQ(2, vectorWrapper.m_fixedVectorInts.size());
  6415. ASSERT_EQ(2, vectorWrapper.m_vectorInts.size());
  6416. vectorWrapper.m_fixedVectorInts[1] = 256;
  6417. vectorWrapper.m_vectorInts[0] = 5;
  6418. vectorWrapper.m_vectorInts[1] = 10;
  6419. VectorWrapper clonedWrapper;
  6420. m_serializeContext->CloneObjectInplace(clonedWrapper, &vectorWrapper);
  6421. EXPECT_EQ(vectorWrapper.m_vectorInts.size(), clonedWrapper.m_vectorInts.size());
  6422. EXPECT_EQ(5, clonedWrapper.m_vectorInts[0]);
  6423. EXPECT_EQ(10, clonedWrapper.m_vectorInts[1]);
  6424. EXPECT_EQ(vectorWrapper.m_fixedVectorInts.size(), clonedWrapper.m_fixedVectorInts.size());
  6425. EXPECT_EQ(256, clonedWrapper.m_fixedVectorInts[1]);
  6426. }
  6427. TEST_F(SerializeVectorWithInitialElementsTest, ObjectStreamTest)
  6428. {
  6429. VectorWrapper vectorWrapper;
  6430. ASSERT_EQ(2, vectorWrapper.m_fixedVectorInts.size());
  6431. ASSERT_EQ(2, vectorWrapper.m_vectorInts.size());
  6432. vectorWrapper.m_fixedVectorInts[1] = 256;
  6433. vectorWrapper.m_vectorInts[0] = 5;
  6434. vectorWrapper.m_vectorInts[1] = 10;
  6435. AZStd::vector<char> byteBuffer;
  6436. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  6437. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_XML);
  6438. byteObjStream->WriteClass(&vectorWrapper);
  6439. byteObjStream->Finalize();
  6440. byteStream.Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6441. VectorWrapper loadedWrapper;
  6442. bool loadSuccess = AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadedWrapper, m_serializeContext.get());
  6443. EXPECT_TRUE(loadSuccess);
  6444. EXPECT_EQ(vectorWrapper.m_vectorInts.size(), loadedWrapper.m_vectorInts.size());
  6445. EXPECT_EQ(5, loadedWrapper.m_vectorInts[0]);
  6446. EXPECT_EQ(10, loadedWrapper.m_vectorInts[1]);
  6447. EXPECT_EQ(vectorWrapper.m_fixedVectorInts.size(), loadedWrapper.m_fixedVectorInts.size());
  6448. EXPECT_EQ(256, loadedWrapper.m_fixedVectorInts[1]);
  6449. }
  6450. TEST_F(SerializeVectorWithInitialElementsTest, DataPatchTest)
  6451. {
  6452. VectorWrapper modifiedWrapper;
  6453. ASSERT_EQ(2, modifiedWrapper.m_fixedVectorInts.size());
  6454. ASSERT_EQ(2, modifiedWrapper.m_vectorInts.size());
  6455. modifiedWrapper.m_fixedVectorInts[1] = 256;
  6456. modifiedWrapper.m_vectorInts[0] = 5;
  6457. modifiedWrapper.m_vectorInts[1] = 10;
  6458. modifiedWrapper.m_vectorInts.push_back(15);
  6459. VectorWrapper initialWrapper;
  6460. DataPatch patch;
  6461. patch.Create(&initialWrapper, azrtti_typeid<VectorWrapper>(), &modifiedWrapper, azrtti_typeid<VectorWrapper>(), DataPatch::FlagsMap(), DataPatch::FlagsMap(), m_serializeContext.get());
  6462. VectorWrapper* patchedWrapper = patch.Apply(&initialWrapper, m_serializeContext.get());
  6463. ASSERT_NE(nullptr, patchedWrapper);
  6464. EXPECT_EQ(modifiedWrapper.m_vectorInts.size(), patchedWrapper->m_vectorInts.size());
  6465. EXPECT_EQ(5, patchedWrapper->m_vectorInts[0]);
  6466. EXPECT_EQ(10, patchedWrapper->m_vectorInts[1]);
  6467. EXPECT_EQ(15, patchedWrapper->m_vectorInts[2]);
  6468. EXPECT_EQ(modifiedWrapper.m_fixedVectorInts.size(), patchedWrapper->m_fixedVectorInts.size());
  6469. EXPECT_EQ(256, patchedWrapper->m_fixedVectorInts[1]);
  6470. delete patchedWrapper;
  6471. }
  6472. struct TestLeafNode
  6473. {
  6474. AZ_RTTI(TestLeafNode, "{D50B136B-82E1-414F-9D84-FEC3A75DC9DF}");
  6475. TestLeafNode() = default;
  6476. TestLeafNode(int field) : m_field(field)
  6477. {}
  6478. virtual ~TestLeafNode() = default;
  6479. int m_field = 0;
  6480. };
  6481. struct TestContainer
  6482. {
  6483. AZ_RTTI(TestContainer, "{6941B3D8-1EE9-4EBD-955A-AB55CFDEE77A}");
  6484. TestContainer() = default;
  6485. virtual ~TestContainer() = default;
  6486. TestLeafNode m_node;
  6487. };
  6488. class TestLeafNodeSerializer
  6489. : public SerializeContext::IDataSerializer
  6490. {
  6491. /// Store the class data into a stream.
  6492. size_t Save(const void* classPtr, IO::GenericStream& stream, bool isDataBigEndian /*= false*/) override
  6493. {
  6494. int tempData;
  6495. tempData = reinterpret_cast<const TestLeafNode*>(classPtr)->m_field;
  6496. AZ_SERIALIZE_SWAP_ENDIAN(tempData, isDataBigEndian);
  6497. return static_cast<size_t>(stream.Write(sizeof(tempData), reinterpret_cast<void*>(&tempData)));
  6498. }
  6499. size_t DataToText(IO::GenericStream& in, IO::GenericStream& out, bool isDataBigEndian /*= false*/) override
  6500. {
  6501. if (in.GetLength() < sizeof(int))
  6502. {
  6503. return 0;
  6504. }
  6505. int tempData;
  6506. in.Read(sizeof(int), reinterpret_cast<void*>(&tempData));
  6507. char textBuffer[256];
  6508. AZ_SERIALIZE_SWAP_ENDIAN(tempData, isDataBigEndian);
  6509. char* textData = &textBuffer[0];
  6510. azsnprintf(textData, sizeof(textBuffer), "%d", tempData);
  6511. AZStd::string outText = textBuffer;
  6512. return static_cast<size_t>(out.Write(outText.size(), outText.data()));
  6513. }
  6514. size_t TextToData(const char* text, unsigned int /*textVersion*/, IO::GenericStream& stream, bool isDataBigEndian /*= false*/) override
  6515. {
  6516. int value;
  6517. value = atoi(text);
  6518. AZ_SERIALIZE_SWAP_ENDIAN(value, isDataBigEndian);
  6519. stream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  6520. return static_cast<size_t>(stream.Write(sizeof(value), reinterpret_cast<void*>(&value)));
  6521. }
  6522. bool Load(void* classPtr, IO::GenericStream& stream, unsigned int version, bool isDataBigEndian /*= false*/) override
  6523. {
  6524. int tempData = 0;
  6525. if (stream.GetLength() < sizeof(tempData))
  6526. {
  6527. return false;
  6528. }
  6529. stream.Read(sizeof(tempData), reinterpret_cast<void*>(&tempData));
  6530. EXPECT_EQ(version, 1);
  6531. AZ_SERIALIZE_SWAP_ENDIAN(tempData, isDataBigEndian);
  6532. *reinterpret_cast<TestLeafNode*>(classPtr) = TestLeafNode{ tempData };
  6533. return true;
  6534. }
  6535. bool CompareValueData(const void* lhs, const void* rhs) override
  6536. {
  6537. int tempDataLhs = reinterpret_cast<const TestLeafNode*>(lhs)->m_field;;
  6538. int tempDataRhs = reinterpret_cast<const TestLeafNode*>(rhs)->m_field;;
  6539. return tempDataLhs == tempDataRhs;
  6540. }
  6541. };
  6542. // Serializer which sets a reference bool to true on deletion to detect when it's lifetime ends.
  6543. class TestDeleterSerializer
  6544. : public SerializeContext::IDataSerializer
  6545. {
  6546. public:
  6547. TestDeleterSerializer(bool& serializerDeleted)
  6548. : m_serializerDeleted{ serializerDeleted }
  6549. {}
  6550. ~TestDeleterSerializer() override
  6551. {
  6552. m_serializerDeleted = true;
  6553. }
  6554. size_t Save(const void*, IO::GenericStream&, bool) override
  6555. {
  6556. return {};
  6557. }
  6558. size_t DataToText(IO::GenericStream&, IO::GenericStream&, bool) override
  6559. {
  6560. return {};
  6561. }
  6562. size_t TextToData(const char*, unsigned int , IO::GenericStream&, bool) override
  6563. {
  6564. return {};
  6565. }
  6566. bool Load(void*, IO::GenericStream&, unsigned int, bool) override
  6567. {
  6568. return true;
  6569. }
  6570. bool CompareValueData(const void* lhs, const void* rhs) override
  6571. {
  6572. AZ_UNUSED(lhs);
  6573. AZ_UNUSED(rhs);
  6574. return true;
  6575. }
  6576. private:
  6577. bool& m_serializerDeleted;
  6578. };
  6579. TEST_F(Serialization, ConvertWithCustomSerializer)
  6580. {
  6581. m_serializeContext->Class<TestContainer>()
  6582. ->Version(1)
  6583. ->Field("m_node", &TestContainer::m_node);
  6584. m_serializeContext->Class<TestLeafNode>()
  6585. ->Version(1)
  6586. ->Serializer<TestLeafNodeSerializer>();
  6587. const int testValue = 123;
  6588. TestContainer test;
  6589. test.m_node.m_field = testValue;
  6590. // write test to an XML buffer
  6591. AZStd::vector<char> byteBuffer;
  6592. IO::ByteContainerStream<AZStd::vector<char> > byteStream(&byteBuffer);
  6593. ObjectStream* byteObjStream = ObjectStream::Create(&byteStream, *m_serializeContext, ObjectStream::ST_XML);
  6594. byteObjStream->WriteClass(&test);
  6595. byteObjStream->Finalize();
  6596. // Update the version to 2
  6597. m_serializeContext->EnableRemoveReflection();
  6598. m_serializeContext->Class<TestContainer>();
  6599. m_serializeContext->Class<TestLeafNode>();
  6600. m_serializeContext->DisableRemoveReflection();
  6601. m_serializeContext->Class<TestContainer>()
  6602. ->Version(2)
  6603. ->Field("m_node", &TestContainer::m_node);
  6604. m_serializeContext->Class<TestLeafNode>()
  6605. ->Version(2)
  6606. ->Serializer<TestLeafNodeSerializer>();
  6607. // Reset for read
  6608. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6609. test = {};
  6610. AZ::Utils::LoadObjectFromStreamInPlace(byteStream, test, m_serializeContext.get());
  6611. EXPECT_EQ(test.m_node.m_field, testValue);
  6612. }
  6613. TEST_F(Serialization, CustomSerializerWithDefaultDeleter_IsDeletedOnUnreflect)
  6614. {
  6615. bool serializerDeleted = false;
  6616. AZ::Serialize::IDataSerializerPtr customSerializer{ new TestDeleterSerializer{ serializerDeleted }, AZ::SerializeContext::IDataSerializer::CreateDefaultDeleteDeleter() };
  6617. m_serializeContext->Class<TestLeafNode>()
  6618. ->Version(1)
  6619. ->Serializer(AZStd::move(customSerializer));
  6620. EXPECT_FALSE(serializerDeleted);
  6621. m_serializeContext->EnableRemoveReflection();
  6622. m_serializeContext->Class<TestLeafNode>();
  6623. m_serializeContext->DisableRemoveReflection();
  6624. EXPECT_TRUE(serializerDeleted);
  6625. }
  6626. TEST_F(Serialization, CustomSerializerWithNoDeleteDeleter_IsNotDeletedOnUnreflect)
  6627. {
  6628. bool serializerDeleted = false;
  6629. TestDeleterSerializer* serializerInstance = new TestDeleterSerializer{ serializerDeleted };
  6630. AZ::Serialize::IDataSerializerPtr customSerializer{ serializerInstance, AZ::SerializeContext::IDataSerializer::CreateNoDeleteDeleter() };
  6631. m_serializeContext->Class<TestLeafNode>()
  6632. ->Version(1)
  6633. ->Serializer(AZStd::move(customSerializer));
  6634. EXPECT_FALSE(serializerDeleted);
  6635. m_serializeContext->EnableRemoveReflection();
  6636. m_serializeContext->Class<TestLeafNode>();
  6637. m_serializeContext->DisableRemoveReflection();
  6638. ASSERT_FALSE(serializerDeleted);
  6639. delete serializerInstance;
  6640. }
  6641. TEST_F(Serialization, DefaultCtorThatAllocatesMemoryDoesntLeak)
  6642. {
  6643. ClassThatAllocatesMemoryInDefaultCtor::Reflect(*GetSerializeContext());
  6644. AZStd::vector<char> xmlBuffer;
  6645. IO::ByteContainerStream<AZStd::vector<char> > xmlStream(&xmlBuffer);
  6646. {
  6647. ClassThatAllocatesMemoryInDefaultCtor obj;
  6648. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, *GetSerializeContext(), ObjectStream::ST_XML);
  6649. xmlObjStream->WriteClass(&obj);
  6650. xmlObjStream->Finalize();
  6651. }
  6652. xmlStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6653. ClassThatAllocatesMemoryInDefaultCtor* deserialized = AZ::Utils::LoadObjectFromStream<ClassThatAllocatesMemoryInDefaultCtor>(xmlStream);
  6654. EXPECT_TRUE(deserialized);
  6655. if (deserialized)
  6656. {
  6657. delete deserialized;
  6658. }
  6659. EXPECT_EQ(ClassThatAllocatesMemoryInDefaultCtor::InstanceTracker::s_instanceCount, 0);
  6660. }
  6661. // Test that loading containers in-place clears any existing data in the
  6662. // containers (
  6663. template <typename T>
  6664. class GenericsLoadInPlaceHolder final
  6665. {
  6666. public:
  6667. AZ_RTTI((GenericsLoadInPlaceHolder, "{98328203-83F0-4644-B1F6-34DDF50F3416}", T));
  6668. static void Reflect(AZ::SerializeContext& sc)
  6669. {
  6670. sc.Class<GenericsLoadInPlaceHolder>()->Version(1)->Field("data", &GenericsLoadInPlaceHolder::m_data);
  6671. }
  6672. T m_data;
  6673. };
  6674. template <typename T>
  6675. class GenericsLoadInPlaceFixture
  6676. : public Serialization
  6677. {
  6678. public:
  6679. GenericsLoadInPlaceHolder<T> m_holder;
  6680. };
  6681. TYPED_TEST_SUITE_P(GenericsLoadInPlaceFixture);
  6682. TYPED_TEST_P(GenericsLoadInPlaceFixture, ClearsOnLoadInPlace)
  6683. {
  6684. using DataType = decltype(this->m_holder);
  6685. DataType::Reflect(*this->GetSerializeContext());
  6686. // Add 3 items to the container
  6687. [[maybe_unused]] typename TypeParam::iterator insertIter{};
  6688. if constexpr (AZStd::same_as<TypeParam, AZStd::forward_list<int>>)
  6689. {
  6690. insertIter = this->m_holder.m_data.before_begin();
  6691. }
  6692. for (int i = 0; i < 3; ++i)
  6693. {
  6694. if constexpr (AZStd::same_as<TypeParam, AZStd::forward_list<int>>)
  6695. {
  6696. insertIter = this->m_holder.m_data.insert_after(insertIter, i);
  6697. }
  6698. else
  6699. {
  6700. this->m_holder.m_data.insert(this->m_holder.m_data.end(), i);
  6701. }
  6702. }
  6703. // Serialize the container
  6704. AZStd::vector<char> xmlBuffer;
  6705. IO::ByteContainerStream<AZStd::vector<char>> xmlStream(&xmlBuffer);
  6706. {
  6707. ObjectStream* xmlObjStream = ObjectStream::Create(&xmlStream, *this->GetSerializeContext(), ObjectStream::ST_XML);
  6708. xmlObjStream->WriteClass(&this->m_holder);
  6709. xmlObjStream->Finalize();
  6710. }
  6711. xmlStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6712. // Put different data in a different instance
  6713. DataType got;
  6714. if constexpr (AZStd::same_as<TypeParam, AZStd::forward_list<int>>)
  6715. {
  6716. insertIter = got.m_data.before_begin();
  6717. }
  6718. for (int i = 3; i < 6; ++i)
  6719. {
  6720. if constexpr (AZStd::same_as<TypeParam, AZStd::forward_list<int>>)
  6721. {
  6722. insertIter = got.m_data.insert_after(insertIter, i);
  6723. }
  6724. else
  6725. {
  6726. got.m_data.insert(got.m_data.end(), i);
  6727. }
  6728. }
  6729. // Verify that the two containers are different
  6730. EXPECT_THAT(got.m_data, ::testing::Ne(this->m_holder.m_data));
  6731. // Deserialize the container into a new one
  6732. AZ::Utils::LoadObjectFromStreamInPlace(xmlStream, got, this->GetSerializeContext());
  6733. // Verify the two containers are the same
  6734. EXPECT_THAT(got.m_data, ::testing::ContainerEq(this->m_holder.m_data));
  6735. }
  6736. REGISTER_TYPED_TEST_SUITE_P(GenericsLoadInPlaceFixture, ClearsOnLoadInPlace);
  6737. // The test ClearsOnLoadInPlace is run once for each type in this list
  6738. typedef ::testing::Types<
  6739. AZStd::vector<int>,
  6740. AZStd::list<int>,
  6741. AZStd::forward_list<int>,
  6742. AZStd::set<int>,
  6743. AZStd::unordered_set<int>,
  6744. AZStd::unordered_multiset<int>
  6745. > TypesThatShouldBeClearedWhenLoadedInPlace;
  6746. INSTANTIATE_TYPED_TEST_SUITE_P(Clears, GenericsLoadInPlaceFixture, TypesThatShouldBeClearedWhenLoadedInPlace);
  6747. enum TestUnscopedSerializationEnum : int32_t
  6748. {
  6749. TestUnscopedSerializationEnum_Option1,
  6750. TestUnscopedSerializationEnum_Option2,
  6751. TestUnscopedSerializationEnum_Option3,
  6752. TestUnscopedSerializationEnum_Option5NotReflected = 4,
  6753. TestUnscopedSerializationEnum_Option4 = 3,
  6754. };
  6755. enum class TestScopedSerializationEnum
  6756. {
  6757. Option1,
  6758. Option2,
  6759. Option3,
  6760. Option4,
  6761. Option5NotReflected,
  6762. };
  6763. enum class TestUnsignedEnum : uint32_t
  6764. {
  6765. Option42 = 42,
  6766. };
  6767. }
  6768. namespace AZ
  6769. {
  6770. AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestUnscopedSerializationEnum, "{83383BFA-F6DA-4124-BE4F-2FAAB7C594E7}");
  6771. AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestScopedSerializationEnum, "{17341C5E-81C3-44CB-A40D-F97D49C2531D}");
  6772. AZ_TYPE_INFO_SPECIALIZE(UnitTest::TestUnsignedEnum, "{0F91A5AE-DADA-4455-B158-8DB79D277495}");
  6773. }
  6774. namespace UnitTest
  6775. {
  6776. enum class TestNoTypeInfoEnum
  6777. {
  6778. Zeroth,
  6779. Second = 2,
  6780. Fourth = 4,
  6781. };
  6782. struct NoTypeInfoNonReflectedEnumWrapper
  6783. {
  6784. AZ_TYPE_INFO(NoTypeInfoNonReflectedEnumWrapper, "{500D534D-4535-46FE-8D0C-7EC0782553F7}");
  6785. TestNoTypeInfoEnum m_value{};
  6786. };
  6787. struct TypeInfoReflectedEnumWrapper
  6788. {
  6789. AZ_TYPE_INFO(TypeInfoReflectedEnumWrapper, "{00ACD993-28B4-4951-91E8-16056EA8A8DA}");
  6790. TestScopedSerializationEnum m_value{};
  6791. };
  6792. class EnumTypeSerialization
  6793. : public LeakDetectionFixture
  6794. {
  6795. public:
  6796. void SetUp() override
  6797. {
  6798. LeakDetectionFixture::SetUp();
  6799. m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
  6800. }
  6801. void TearDown() override
  6802. {
  6803. m_serializeContext.reset();
  6804. LeakDetectionFixture::TearDown();
  6805. }
  6806. protected:
  6807. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  6808. };
  6809. TEST_F(EnumTypeSerialization, TestUnscopedEnumReflection_Succeeds)
  6810. {
  6811. m_serializeContext->Enum<TestUnscopedSerializationEnum>();
  6812. const AZ::SerializeContext::ClassData* enumClassData = m_serializeContext->FindClassData(azrtti_typeid<TestUnscopedSerializationEnum>());
  6813. ASSERT_NE(nullptr, enumClassData);
  6814. AZ::TypeId underlyingTypeId = AZ::TypeId::CreateNull();
  6815. AttributeReader attrReader(nullptr, enumClassData->FindAttribute(AZ::Serialize::Attributes::EnumUnderlyingType));
  6816. EXPECT_TRUE(attrReader.Read<AZ::TypeId>(underlyingTypeId));
  6817. EXPECT_EQ(azrtti_typeid<int32_t>(), underlyingTypeId);
  6818. // Unreflect Enum type
  6819. m_serializeContext->EnableRemoveReflection();
  6820. m_serializeContext->Enum<TestUnscopedSerializationEnum>();
  6821. m_serializeContext->DisableRemoveReflection();
  6822. enumClassData = m_serializeContext->FindClassData(azrtti_typeid<TestUnscopedSerializationEnum>());
  6823. EXPECT_EQ(nullptr, enumClassData);
  6824. }
  6825. TEST_F(EnumTypeSerialization, TestScopedEnumReflection_Succeeds)
  6826. {
  6827. m_serializeContext->Enum<TestScopedSerializationEnum>();
  6828. const AZ::SerializeContext::ClassData* enumClassData = m_serializeContext->FindClassData(azrtti_typeid<TestScopedSerializationEnum>());
  6829. ASSERT_NE(nullptr, enumClassData);
  6830. // Unreflect Enum type
  6831. m_serializeContext->EnableRemoveReflection();
  6832. m_serializeContext->Enum<TestScopedSerializationEnum>();
  6833. m_serializeContext->DisableRemoveReflection();
  6834. enumClassData = m_serializeContext->FindClassData(azrtti_typeid<TestScopedSerializationEnum>());
  6835. EXPECT_EQ(nullptr, enumClassData);
  6836. }
  6837. TEST_F(EnumTypeSerialization, TestEnumReflectionWithValues_Succeeds)
  6838. {
  6839. m_serializeContext->Enum<TestUnscopedSerializationEnum>()
  6840. ->Value("Option1", TestUnscopedSerializationEnum::TestUnscopedSerializationEnum_Option1)
  6841. ->Value("Option2", TestUnscopedSerializationEnum::TestUnscopedSerializationEnum_Option2)
  6842. ->Value("Option3", TestUnscopedSerializationEnum::TestUnscopedSerializationEnum_Option3)
  6843. ->Value("Option4", TestUnscopedSerializationEnum::TestUnscopedSerializationEnum_Option4)
  6844. ;
  6845. const AZ::SerializeContext::ClassData* enumClassData = m_serializeContext->FindClassData(azrtti_typeid<TestUnscopedSerializationEnum>());
  6846. ASSERT_NE(nullptr, enumClassData);
  6847. using EnumConstantBase = AZ::SerializeContextEnumInternal::EnumConstantBase;
  6848. using EnumConstantBasePtr = AZStd::unique_ptr<EnumConstantBase>;
  6849. AZStd::vector<AZStd::reference_wrapper<EnumConstantBase>> enumConstants;
  6850. enumConstants.reserve(4);
  6851. for (const AZ::AttributeSharedPair& attrPair : enumClassData->m_attributes)
  6852. {
  6853. if (attrPair.first == AZ::Serialize::Attributes::EnumValueKey)
  6854. {
  6855. auto enumConstantAttribute{ azrtti_cast<AZ::AttributeData<EnumConstantBasePtr>*>(attrPair.second.get()) };
  6856. ASSERT_NE(nullptr, enumConstantAttribute);
  6857. const EnumConstantBasePtr& sourceEnumConstant = enumConstantAttribute->Get(nullptr);
  6858. ASSERT_NE(nullptr, sourceEnumConstant);
  6859. enumConstants.emplace_back(*sourceEnumConstant);
  6860. }
  6861. }
  6862. ASSERT_EQ(4, enumConstants.size());
  6863. EXPECT_EQ("Option1", static_cast<EnumConstantBase&>(enumConstants[0]).GetEnumValueName());
  6864. EXPECT_EQ(0, static_cast<EnumConstantBase&>(enumConstants[0]).GetEnumValueAsUInt());
  6865. EXPECT_EQ("Option2", static_cast<EnumConstantBase&>(enumConstants[1]).GetEnumValueName());
  6866. EXPECT_EQ(1, static_cast<EnumConstantBase&>(enumConstants[1]).GetEnumValueAsUInt());
  6867. EXPECT_EQ("Option3", static_cast<EnumConstantBase&>(enumConstants[2]).GetEnumValueName());
  6868. EXPECT_EQ(2, static_cast<EnumConstantBase&>(enumConstants[2]).GetEnumValueAsUInt());
  6869. EXPECT_EQ("Option4", static_cast<EnumConstantBase&>(enumConstants[3]).GetEnumValueName());
  6870. EXPECT_EQ(3, static_cast<EnumConstantBase&>(enumConstants[3]).GetEnumValueAsUInt());
  6871. m_serializeContext->EnableRemoveReflection();
  6872. m_serializeContext->Enum<TestUnscopedSerializationEnum>();
  6873. m_serializeContext->DisableRemoveReflection();
  6874. }
  6875. TEST_F(EnumTypeSerialization, TestEnumFieldWithTypeInfoAndReflectedAsEnum_Succeeds)
  6876. {
  6877. m_serializeContext->Enum<TestScopedSerializationEnum>()
  6878. ->Value("Option1", TestScopedSerializationEnum::Option1)
  6879. ->Value("Option2", TestScopedSerializationEnum::Option2)
  6880. ->Value("Option3", TestScopedSerializationEnum::Option3)
  6881. ->Value("Option4", TestScopedSerializationEnum::Option4)
  6882. ;
  6883. m_serializeContext->Class<TypeInfoReflectedEnumWrapper>()
  6884. ->Field("m_value", &TypeInfoReflectedEnumWrapper::m_value)
  6885. ;
  6886. // The TestScopedSerializationEnum is explicitly reflected as an Enum in the SerializeContext and FindClassData
  6887. // should return the EnumType class data
  6888. const AZ::SerializeContext::ClassData* enumClassData = m_serializeContext->FindClassData(azrtti_typeid<TestScopedSerializationEnum>());
  6889. ASSERT_NE(nullptr, enumClassData);
  6890. EXPECT_EQ(azrtti_typeid<TestScopedSerializationEnum>(), enumClassData->m_typeId);
  6891. TypeInfoReflectedEnumWrapper testObject;
  6892. testObject.m_value = TestScopedSerializationEnum::Option3;
  6893. AZStd::vector<uint8_t> byteBuffer;
  6894. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6895. AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_BINARY);
  6896. objStream->WriteClass(&testObject);
  6897. objStream->Finalize();
  6898. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6899. TypeInfoReflectedEnumWrapper loadObject;
  6900. const bool loadResult = AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadObject, m_serializeContext.get());
  6901. EXPECT_TRUE(loadResult);
  6902. EXPECT_EQ(TestScopedSerializationEnum::Option3, loadObject.m_value);
  6903. m_serializeContext->EnableRemoveReflection();
  6904. m_serializeContext->Class<TypeInfoReflectedEnumWrapper>();
  6905. m_serializeContext->Enum<TestScopedSerializationEnum>();
  6906. m_serializeContext->DisableRemoveReflection();
  6907. }
  6908. TEST_F(EnumTypeSerialization, TestEnumFieldWithTypeInfoAndNotReflectedAsEnum_Succeeds)
  6909. {
  6910. m_serializeContext->Class<TypeInfoReflectedEnumWrapper>()
  6911. ->Field("m_value", &TypeInfoReflectedEnumWrapper::m_value)
  6912. ;
  6913. // The TestScopedSerializationEnum is not reflected as an Enum in the SerializeContext, but has specialized AzTypeInfo
  6914. // So FindClassData should return the underlying type in this case, which is an int
  6915. const AZ::SerializeContext::ClassData* underlyingTypeClassData = m_serializeContext->FindClassData(azrtti_typeid<TestScopedSerializationEnum>());
  6916. ASSERT_NE(nullptr, underlyingTypeClassData);
  6917. EXPECT_EQ(azrtti_typeid<int>(), underlyingTypeClassData->m_typeId);
  6918. TypeInfoReflectedEnumWrapper testObject;
  6919. testObject.m_value = TestScopedSerializationEnum::Option3;
  6920. AZStd::vector<uint8_t> byteBuffer;
  6921. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6922. AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_BINARY);
  6923. objStream->WriteClass(&testObject);
  6924. objStream->Finalize();
  6925. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6926. TypeInfoReflectedEnumWrapper loadObject;
  6927. const bool loadResult = AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadObject, m_serializeContext.get());
  6928. EXPECT_TRUE(loadResult);
  6929. EXPECT_EQ(TestScopedSerializationEnum::Option3, loadObject.m_value);
  6930. m_serializeContext->EnableRemoveReflection();
  6931. m_serializeContext->Class<TypeInfoReflectedEnumWrapper>();
  6932. m_serializeContext->DisableRemoveReflection();
  6933. }
  6934. TEST_F(EnumTypeSerialization, TestEnumFieldWithNoTypeInfo_Succeeds)
  6935. {
  6936. m_serializeContext->Class<NoTypeInfoNonReflectedEnumWrapper>()
  6937. ->Field("m_value", &NoTypeInfoNonReflectedEnumWrapper::m_value)
  6938. ;
  6939. static_assert(AZ::Internal::HasAZTypeInfo<TestNoTypeInfoEnum>::value, "Test enum type should not have AzTypeInfo");
  6940. NoTypeInfoNonReflectedEnumWrapper testObject;
  6941. testObject.m_value = TestNoTypeInfoEnum::Second;
  6942. AZStd::vector<uint8_t> byteBuffer;
  6943. AZ::IO::ByteContainerStream<decltype(byteBuffer)> byteStream(&byteBuffer);
  6944. AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&byteStream, *m_serializeContext, AZ::ObjectStream::ST_BINARY);
  6945. objStream->WriteClass(&testObject);
  6946. objStream->Finalize();
  6947. byteStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  6948. NoTypeInfoNonReflectedEnumWrapper loadObject;
  6949. const bool loadResult = AZ::Utils::LoadObjectFromStreamInPlace(byteStream, loadObject, m_serializeContext.get());
  6950. EXPECT_TRUE(loadResult);
  6951. EXPECT_EQ(TestNoTypeInfoEnum::Second, loadObject.m_value);
  6952. m_serializeContext->EnableRemoveReflection();
  6953. m_serializeContext->Class<NoTypeInfoNonReflectedEnumWrapper>();
  6954. m_serializeContext->DisableRemoveReflection();
  6955. }
  6956. TEST_F(EnumTypeSerialization, LoadIntIntoEnumTypeInfoSpecialization_Succeeds)
  6957. {
  6958. AZStd::string_view typeInfoEnumWrapperObjStreamData = R"(<ObjectStream version="3">
  6959. <Class name="TypeInfoReflectedEnumWrapper" type="{00ACD993-28B4-4951-91E8-16056EA8A8DA}">
  6960. <Class name="int" field="m_value" value="72" type="{72039442-EB38-4d42-A1AD-CB68F7E0EEF6}"/>
  6961. </Class>
  6962. </ObjectStream>
  6963. )";
  6964. m_serializeContext->Class<TypeInfoReflectedEnumWrapper>()
  6965. ->Field("m_value", &TypeInfoReflectedEnumWrapper::m_value)
  6966. ;
  6967. // Validate that the "m_value" ClassElement reflected to the TypeInfoReflectedEnumWrapper class
  6968. // is set to the Type of TestScopedSerializationEnum and not the TypeId of int
  6969. // When using enum types in fields previously it always used the underlying type for reflection
  6970. // Now if the enum type is being used in a field and has specialized AzTypeInfo, it uses the specialized TypeID
  6971. const SerializeContext::ClassData* classData = m_serializeContext->FindClassData(azrtti_typeid<TypeInfoReflectedEnumWrapper>());
  6972. ASSERT_NE(nullptr, classData);
  6973. ASSERT_EQ(1, classData->m_elements.size());
  6974. EXPECT_EQ(azrtti_typeid<TestScopedSerializationEnum>(), classData->m_elements[0].m_typeId);
  6975. EXPECT_NE(azrtti_typeid<int>(), classData->m_elements[0].m_typeId);
  6976. AZ::IO::MemoryStream memStream(typeInfoEnumWrapperObjStreamData.data(), typeInfoEnumWrapperObjStreamData.size());
  6977. TypeInfoReflectedEnumWrapper testObject;
  6978. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(memStream, testObject, m_serializeContext.get()));
  6979. EXPECT_EQ(72, static_cast<int>(testObject.m_value));
  6980. m_serializeContext->EnableRemoveReflection();
  6981. m_serializeContext->Class<TypeInfoReflectedEnumWrapper>();
  6982. m_serializeContext->DisableRemoveReflection();
  6983. }
  6984. struct TestUnsignedEnumWrapper
  6985. {
  6986. AZ_TYPE_INFO(TestUnsignedEnumWrapper, "{A5DD32CD-EC5B-4F0D-9D25-239EC76F1860}");
  6987. TestUnsignedEnum m_value{};
  6988. };
  6989. TEST_F(EnumTypeSerialization, VersionConverterRunOnEnum_ConvertsTypeSuccessfully)
  6990. {
  6991. AZStd::string_view typeInfoEnumWrapperObjStreamData = R"(<ObjectStream version="3">
  6992. <Class name="TestUnsignedEnumWrapper" type="{A5DD32CD-EC5B-4F0D-9D25-239EC76F1860}">
  6993. <Class name="unsigned int" field="m_value" value="234343" type="{43DA906B-7DEF-4ca8-9790-854106D3F983}"/>
  6994. </Class>
  6995. </ObjectStream>
  6996. )";
  6997. auto VersionConverter = [](AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) -> bool
  6998. {
  6999. if (classElement.GetVersion() < 1)
  7000. {
  7001. int enumIndex = classElement.FindElement(AZ_CRC_CE("m_value"));
  7002. if (enumIndex == -1)
  7003. {
  7004. return false;
  7005. }
  7006. AZ::SerializeContext::DataElementNode& enumValueNode = classElement.GetSubElement(enumIndex);
  7007. TestUnsignedEnum oldValue{};
  7008. EXPECT_TRUE(enumValueNode.GetData(oldValue));
  7009. EXPECT_EQ(234343U, static_cast<std::underlying_type_t<TestUnsignedEnum>>(oldValue));
  7010. EXPECT_TRUE(enumValueNode.Convert<TestUnsignedEnum>(context));
  7011. EXPECT_TRUE(enumValueNode.SetData(context, TestUnsignedEnum::Option42));
  7012. }
  7013. return true;
  7014. };
  7015. m_serializeContext->Class<TestUnsignedEnumWrapper>()
  7016. ->Version(1, VersionConverter)
  7017. ->Field("m_value", &TestUnsignedEnumWrapper::m_value)
  7018. ;
  7019. AZ::IO::MemoryStream memStream(typeInfoEnumWrapperObjStreamData.data(), typeInfoEnumWrapperObjStreamData.size());
  7020. TestUnsignedEnumWrapper testObject;
  7021. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(memStream, testObject, m_serializeContext.get()));
  7022. EXPECT_EQ(TestUnsignedEnum::Option42, testObject.m_value);
  7023. m_serializeContext->EnableRemoveReflection();
  7024. m_serializeContext->Class<TestUnsignedEnumWrapper>();
  7025. m_serializeContext->DisableRemoveReflection();
  7026. }
  7027. struct TestClassWithEnumField
  7028. {
  7029. AZ_TYPE_INFO(TestClassWithEnumField, "{F1F03A45-3E6D-44C3-A615-A556DEE18E94}");
  7030. TestUnsignedEnum m_value{};
  7031. AZStd::string m_strValue;
  7032. };
  7033. TEST_F(EnumTypeSerialization, LoadingOldVersionOfClassWithEnumFieldStoredUsingTheUnderlying_AndThatClassDoesNotHaveAVersionConverter_Succeeds)
  7034. {
  7035. AZStd::string_view testClassWithEnumFieldData = R"(<ObjectStream version="3">
  7036. <Class name="TestClassWithEnumField" type="{F1F03A45-3E6D-44C3-A615-A556DEE18E94}">
  7037. <Class name="unsigned int" field="m_value" value="42" type="{43DA906B-7DEF-4ca8-9790-854106D3F983}"/>
  7038. </Class>
  7039. </ObjectStream>
  7040. )";
  7041. m_serializeContext->Class<TestClassWithEnumField>()
  7042. ->Version(1)
  7043. ->Field("m_value", &TestClassWithEnumField::m_value)
  7044. ->Field("m_strValue", &TestClassWithEnumField::m_strValue)
  7045. ;
  7046. AZ::IO::MemoryStream memStream(testClassWithEnumFieldData.data(), testClassWithEnumFieldData.size());
  7047. TestClassWithEnumField testObject;
  7048. EXPECT_TRUE(AZ::Utils::LoadObjectFromStreamInPlace(memStream, testObject, m_serializeContext.get()));
  7049. EXPECT_EQ(TestUnsignedEnum::Option42, testObject.m_value);
  7050. m_serializeContext->EnableRemoveReflection();
  7051. m_serializeContext->Class<TestClassWithEnumField>();
  7052. m_serializeContext->DisableRemoveReflection();
  7053. }
  7054. struct TestClassWithEnumFieldThatSpecializesTypeInfo
  7055. {
  7056. AZ_TYPE_INFO(TestClassWithEnumFieldThatSpecializesTypeInfo, "{B7E066F4-3598-4678-A331-5AB8789CE391}");
  7057. TestUnsignedEnum m_value{};
  7058. };
  7059. TEST_F(EnumTypeSerialization, CloneObjectAZStdAnyOfEnum_SucceedsWithoutCrashing)
  7060. {
  7061. m_serializeContext->Class<TestClassWithEnumFieldThatSpecializesTypeInfo>()
  7062. ->Version(1)
  7063. ->Field("m_value", &TestClassWithEnumFieldThatSpecializesTypeInfo::m_value)
  7064. ;
  7065. AZStd::any testAny(AZStd::make_any<TestUnsignedEnum>(TestUnsignedEnum::Option42));
  7066. AZStd::any resultAny;
  7067. m_serializeContext->CloneObjectInplace(resultAny, &testAny);
  7068. auto resultEnum = AZStd::any_cast<TestUnsignedEnum>(&resultAny);
  7069. ASSERT_NE(nullptr, resultEnum);
  7070. EXPECT_EQ(TestUnsignedEnum::Option42, *resultEnum);
  7071. m_serializeContext->EnableRemoveReflection();
  7072. m_serializeContext->Class<TestClassWithEnumFieldThatSpecializesTypeInfo>();
  7073. m_serializeContext->DisableRemoveReflection();
  7074. }
  7075. }
  7076. namespace UnitTest
  7077. {
  7078. class AssociativeContainerSerializationFixture
  7079. : public LeakDetectionFixture
  7080. {
  7081. public:
  7082. AssociativeContainerSerializationFixture()
  7083. {
  7084. m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
  7085. m_serializeContext->RegisterGenericType<AZStd::set<int>>();
  7086. m_serializeContext->RegisterGenericType<AZStd::map<int, int>>();
  7087. m_serializeContext->RegisterGenericType<AZStd::unordered_set<int>>();
  7088. m_serializeContext->RegisterGenericType<AZStd::unordered_map<int, int>>();
  7089. }
  7090. ~AssociativeContainerSerializationFixture() override
  7091. {
  7092. m_serializeContext.reset();
  7093. }
  7094. protected:
  7095. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  7096. };
  7097. TEST_F(AssociativeContainerSerializationFixture, GetAssociativeType_ReturnsCorrectAssociativeStructure)
  7098. {
  7099. using AssociativeType = AZ::Serialize::IDataContainer::IAssociativeDataContainer::AssociativeType;
  7100. const auto setClassData = m_serializeContext->FindClassData(azrtti_typeid<AZStd::set<int>>());
  7101. ASSERT_NE(nullptr, setClassData);
  7102. const auto setDataContainer = setClassData->m_container;
  7103. ASSERT_NE(nullptr, setDataContainer);
  7104. const auto setAssociativeContainer = setClassData->m_container->GetAssociativeContainerInterface();
  7105. ASSERT_NE(nullptr, setClassData->m_container->GetAssociativeContainerInterface());
  7106. EXPECT_EQ(AssociativeType::Set, setAssociativeContainer->GetAssociativeType());
  7107. const auto mapClassData = m_serializeContext->FindClassData(azrtti_typeid<AZStd::map<int, int>>());
  7108. ASSERT_NE(nullptr, mapClassData);
  7109. const auto mapDataContainer = mapClassData->m_container;
  7110. ASSERT_NE(nullptr, mapDataContainer);
  7111. const auto mapAssociativeContainer = mapClassData->m_container->GetAssociativeContainerInterface();
  7112. ASSERT_NE(nullptr, mapClassData->m_container->GetAssociativeContainerInterface());
  7113. EXPECT_EQ(AssociativeType::Map, mapAssociativeContainer->GetAssociativeType());
  7114. const auto unorderedSetClassData = m_serializeContext->FindClassData(azrtti_typeid<AZStd::unordered_set<int>>());
  7115. ASSERT_NE(nullptr, unorderedSetClassData);
  7116. const auto unorderedSetDataContainer = unorderedSetClassData->m_container;
  7117. ASSERT_NE(nullptr, unorderedSetDataContainer);
  7118. const auto unorderedSetAssociativeContainer = unorderedSetClassData->m_container->GetAssociativeContainerInterface();
  7119. ASSERT_NE(nullptr, unorderedSetClassData->m_container->GetAssociativeContainerInterface());
  7120. EXPECT_EQ(AssociativeType::UnorderedSet, unorderedSetAssociativeContainer->GetAssociativeType());
  7121. const auto unorderedMapClassData = m_serializeContext->FindClassData(azrtti_typeid<AZStd::unordered_map<int, int>>());
  7122. ASSERT_NE(nullptr, unorderedMapClassData);
  7123. const auto unorderedMapDataContainer = unorderedMapClassData->m_container;
  7124. ASSERT_NE(nullptr, unorderedMapDataContainer);
  7125. const auto unorderedMapAssociativeContainer = unorderedMapClassData->m_container->GetAssociativeContainerInterface();
  7126. ASSERT_NE(nullptr, unorderedMapClassData->m_container->GetAssociativeContainerInterface());
  7127. EXPECT_EQ(AssociativeType::UnorderedMap, unorderedMapAssociativeContainer->GetAssociativeType());
  7128. }
  7129. }