Serialization.cpp 362 KB

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