Script.cpp 175 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500
  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 <AzCore/Script/ScriptContext.h>
  9. #include <AzCore/RTTI/BehaviorContext.h>
  10. #include <AzCore/Script/lua/lua.h>
  11. #include <AzCore/Script/ScriptContextDebug.h>
  12. #include <AzCore/UnitTest/TestTypes.h>
  13. #include <AzCore/Component/Entity.h>
  14. #include <AzCore/std/string/string.h>
  15. #include <AzCore/std/smart_ptr/shared_ptr.h>
  16. #include <AzCore/std/smart_ptr/intrusive_ptr.h>
  17. #include <AzCore/std/smart_ptr/make_shared.h>
  18. #include <AzCore/std/containers/fixed_vector.h>
  19. #include <math.h> // for pow
  20. #include <AzCore/Math/MathReflection.h>
  21. #include <AzCore/Math/Transform.h>
  22. #include <AzCore/std/any.h>
  23. // Components
  24. #include <AzCore/Component/ComponentApplication.h>
  25. #include <AzCore/Script/ScriptSystemComponent.h>
  26. #include <AzCore/Asset/AssetManager.h>
  27. #include <AzCore/Asset/AssetManagerComponent.h>
  28. #include <Tests/BehaviorContextFixture.h>
  29. namespace UnitTest
  30. {
  31. using namespace AZ;
  32. enum GlobalEnum
  33. {
  34. GE_VALUE1 = 0,
  35. GE_VALUE2,
  36. };
  37. enum class GlobalClassEnum
  38. {
  39. Value1,
  40. Value2,
  41. Value3,
  42. };
  43. struct GlobalData
  44. {
  45. AZ_TYPE_INFO(GlobalData, "{4F35A5E6-568E-43C8-851A-4D2315E9BAD0}");
  46. GlobalData()
  47. {}
  48. char data[512];
  49. };
  50. int g_globalValue = 501;
  51. int g_globalData = 0;
  52. int g_globalTestClassesConstructed = 0;
  53. int g_globalTestClassesDestructed = 0;
  54. GlobalClassEnum globalClassEnumValue = GlobalClassEnum::Value3;
  55. int globalPropertyGetter()
  56. {
  57. return g_globalValue;
  58. }
  59. void globalPropertySetter(int value)
  60. {
  61. g_globalValue = value;
  62. }
  63. int globalMethod(int a)
  64. {
  65. return a + 3;
  66. }
  67. void globalMethod1()
  68. {
  69. g_globalData = 1001;
  70. }
  71. int globalMethod2WithDefaultArgument(int value)
  72. {
  73. return value + 1;
  74. }
  75. int globalMethodContainers(const AZStd::vector<int>& value)
  76. {
  77. return value[0];
  78. }
  79. int globalMethodPair(const AZStd::pair<int, bool>& value)
  80. {
  81. return value.second ? value.first : -1;
  82. }
  83. int globalMethodToOverride(int a)
  84. {
  85. return a * 3;
  86. }
  87. void globalMethodOverride(ScriptDataContext& dc)
  88. {
  89. (void)dc;
  90. }
  91. GlobalData globalMethodLarge()
  92. {
  93. return GlobalData();
  94. }
  95. GlobalClassEnum globalMethodGetClassEnum()
  96. {
  97. return GlobalClassEnum::Value1;
  98. }
  99. void globalMethodSetClassEnum(GlobalClassEnum value)
  100. {
  101. globalClassEnumValue = value;
  102. }
  103. // Global Enum class wrapper, till the "namespace" open/close functionallity is missing
  104. struct BehaviorGlobalClassEnumWrapper
  105. {
  106. AZ_TYPE_INFO(BehaviorGlobalClassEnumWrapper,"{de36dcf3-7c25-4053-b747-1148240cda68}");
  107. };
  108. class BehaviorTestClass
  109. {
  110. public:
  111. AZ_RTTI(BehaviorTestClass, "{26398112-E4F1-4912-80E6-D81152116D02}");
  112. AZ_CLASS_ALLOCATOR(BehaviorTestClass, AZ::SystemAllocator);
  113. BehaviorTestClass()
  114. : m_data(1)
  115. , m_data1(2)
  116. , m_dataReadOnly(3)
  117. {
  118. g_globalData = 1020;
  119. g_globalTestClassesConstructed++;
  120. }
  121. BehaviorTestClass(const BehaviorTestClass& other)
  122. : m_data(other.m_data)
  123. , m_data1(other.m_data1)
  124. , m_dataReadOnly(other.m_dataReadOnly)
  125. {
  126. g_globalData = 1025;
  127. g_globalTestClassesConstructed++;
  128. }
  129. BehaviorTestClass(int data)
  130. : m_data(data)
  131. , m_data1(3)
  132. , m_dataReadOnly(4)
  133. {
  134. g_globalData = 1030;
  135. g_globalTestClassesConstructed++;
  136. }
  137. virtual ~BehaviorTestClass()
  138. {
  139. g_globalData = 1040;
  140. g_globalTestClassesDestructed++;
  141. }
  142. enum MyEnum
  143. {
  144. ME_VALUE0,
  145. ME_VALUE1,
  146. };
  147. enum class MyClassEnum
  148. {
  149. MCE_VALUE0,
  150. MCE_VALUE1,
  151. };
  152. void Method1()
  153. {
  154. g_globalData = 1050;
  155. }
  156. int Method2(int* a) const
  157. {
  158. return *a + 1;
  159. }
  160. BehaviorTestClass* GetClass()
  161. {
  162. return this;
  163. }
  164. int GetData() const
  165. {
  166. return m_data;
  167. }
  168. void SetData(int data)
  169. {
  170. m_data = data;
  171. m_data1 = m_data + 10;
  172. m_dataReadOnly = m_data1 + 100;
  173. }
  174. static void StaticMethod(int newData)
  175. {
  176. g_globalData = newData;
  177. }
  178. void SpecialScriptMethod(ScriptDataContext& dc)
  179. {
  180. dc.PushResult(303);
  181. }
  182. void MethodToOverrideInScript()
  183. {
  184. g_globalData = 1060;
  185. }
  186. void Method1ScriptOverride(ScriptDataContext&)
  187. {
  188. g_globalData = 1070;
  189. }
  190. void MethodToOverrideInScriptWithANonMember() const
  191. {
  192. g_globalData = 1080;
  193. }
  194. BehaviorTestClass AddOperator(BehaviorTestClass& rhs)
  195. {
  196. BehaviorTestClass result = *this;
  197. result.m_data += rhs.m_data;
  198. result.m_data1 += rhs.m_data1;
  199. result.m_dataReadOnly += rhs.m_dataReadOnly;
  200. return result;
  201. }
  202. AZStd::string ToString()
  203. {
  204. return AZStd::string::format("%d\n", m_data);
  205. }
  206. bool BoundsCheckMethodWithDefaultValue(float value, float epsilon, float minBounds, float maxBounds)
  207. {
  208. (void)epsilon;
  209. return value >= minBounds && value < maxBounds;
  210. }
  211. int m_data;
  212. int m_data1;
  213. int m_dataReadOnly;
  214. };
  215. class BehaviorDerivedTestClass : public BehaviorTestClass
  216. {
  217. public:
  218. AZ_CLASS_ALLOCATOR(BehaviorDerivedTestClass, AZ::SystemAllocator)
  219. AZ_RTTI(BehaviorDerivedTestClass, "{dba8a4e3-8fab-4223-94a6-874c6cff88e5}", BehaviorTestClass);
  220. int m_data;
  221. };
  222. void TestMethodToScriptOverride(const BehaviorTestClass* thisPtr, ScriptDataContext&)
  223. {
  224. (void)thisPtr;
  225. g_globalData = 1010;
  226. }
  227. void TestScriptNonIntrusiveConstructor(BehaviorTestClass* thisPtr, ScriptDataContext& dc)
  228. {
  229. new(thisPtr) BehaviorTestClass();
  230. if (dc.GetNumArguments() && dc.IsNumber(0))
  231. {
  232. int data = 0;
  233. dc.ReadArg(0, data);
  234. thisPtr->m_data = data;
  235. thisPtr->m_data1 = data * 2;
  236. thisPtr->m_dataReadOnly = data * 3;
  237. }
  238. else
  239. {
  240. thisPtr->m_data = 1000;
  241. thisPtr->m_data1 = 1005;
  242. thisPtr->m_dataReadOnly = 1007;
  243. }
  244. }
  245. class BehaviorTestBusEvents : public AZ::EBusTraits
  246. {
  247. public:
  248. //////////////////////////////////////////////////////////////////////////
  249. // Configure the EBus
  250. static const EBusAddressPolicy AddressPolicy = EBusAddressPolicy::ById;
  251. using BusIdType = int;
  252. static const bool EnableEventQueue = true;
  253. //////////////////////////////////////////////////////////////////////////
  254. virtual void OnEvent(int data) = 0;
  255. virtual int OnEventWithResult(int data)
  256. {
  257. return data + 2;
  258. }
  259. virtual int OnEventWithResultContainer(const AZStd::vector<int> values) = 0;
  260. virtual GlobalClassEnum OnEventWithClassEnumResult() = 0;
  261. virtual AZStd::string OnEventWithStringResult() { return ""; }
  262. virtual BehaviorTestClass OnEventWithClassResult() { return BehaviorTestClass(); }
  263. virtual AZStd::string OnEventWithDefaultValueAndStringResult(AZStd::string_view view1, AZStd::string_view) { return AZStd::string::format("Default Value: %s", view1.data()); }
  264. virtual void OnEventConst() const {};
  265. virtual BehaviorTestClass OnEventResultWithBehaviorClassParameter([[maybe_unused]] BehaviorTestClass data) { return BehaviorTestClass(); };
  266. };
  267. typedef AZ::EBus<BehaviorTestBusEvents> BehaviorTestBus;
  268. class BehaviorTestBusHandler : public BehaviorTestBus::Handler, public AZ::BehaviorEBusHandler
  269. {
  270. public:
  271. AZ_EBUS_BEHAVIOR_BINDER(BehaviorTestBusHandler, "{19F5C8C8-4260-46B1-B624-997CD3F10CBD}", AZ::SystemAllocator
  272. , OnEvent
  273. , OnEventWithResult
  274. , OnEventWithResultContainer
  275. , OnEventWithClassEnumResult
  276. , OnEventWithStringResult
  277. , OnEventWithClassResult
  278. , OnEventWithDefaultValueAndStringResult
  279. , OnEventResultWithBehaviorClassParameter
  280. );
  281. // User code
  282. void OnEvent(int data) override
  283. {
  284. // you can get the index yourself or use the FN_xxx enum FN_OnEvent
  285. static int eventIndex = GetFunctionIndex("OnEvent");
  286. AZ_Assert(eventIndex != -1, "We can't find event with name %s", "OnEvent");
  287. Call(eventIndex, data);
  288. }
  289. int OnEventWithResult(int data) override
  290. {
  291. int result = 0; // default result as a function hook might not exists
  292. CallResult(result, FN_OnEventWithResult, data);
  293. return result;
  294. }
  295. int OnEventWithResultContainer(const AZStd::vector<int> values) override
  296. {
  297. int result = 0;
  298. CallResult(result, FN_OnEventWithResultContainer, values);
  299. return result;
  300. }
  301. GlobalClassEnum OnEventWithClassEnumResult() override
  302. {
  303. GlobalClassEnum result = GlobalClassEnum::Value1;
  304. CallResult(result, FN_OnEventWithClassEnumResult);
  305. return result;
  306. }
  307. AZStd::string OnEventWithStringResult() override
  308. {
  309. AZStd::string result;
  310. CallResult(result, FN_OnEventWithStringResult);
  311. return result;
  312. }
  313. BehaviorTestClass OnEventWithClassResult() override
  314. {
  315. BehaviorTestClass result;
  316. CallResult(result, FN_OnEventWithClassResult);
  317. return result;
  318. }
  319. AZStd::string OnEventWithDefaultValueAndStringResult(AZStd::string_view view1, AZStd::string_view view2) override
  320. {
  321. return BehaviorTestBus::Handler::OnEventWithDefaultValueAndStringResult(view1, view2);
  322. }
  323. BehaviorTestClass OnEventResultWithBehaviorClassParameter(BehaviorTestClass data) override
  324. {
  325. BehaviorTestClass result = data;
  326. return result;
  327. }
  328. };
  329. class BehaviorTestBusHandlerWithDoc : public BehaviorTestBus::Handler, public AZ::BehaviorEBusHandler
  330. {
  331. public:
  332. AZ_EBUS_BEHAVIOR_BINDER_WITH_DOC(BehaviorTestBusHandlerWithDoc, "{C0D4FE98-DBE1-439A-ACBA-B3767863C560}", AZ::SystemAllocator
  333. , OnEvent, ({"data", "Data to pass in"})
  334. , OnEventWithResult, ({"data", "Data to pass in"})
  335. , OnEventWithResultContainer, ({ "values", "Vector of integers to forward" })
  336. , OnEventWithClassEnumResult, ()
  337. , OnEventWithStringResult, ()
  338. , OnEventWithClassResult, ()
  339. , OnEventWithDefaultValueAndStringResult, ({ "defaultView", "string_view which contains literal to print by default" }, { "unusedView", "Unused test parameter" })
  340. , OnEventResultWithBehaviorClassParameter, ()
  341. );
  342. // User code
  343. void OnEvent(int data) override
  344. {
  345. // you can get the index yourself or use the FN_xxx enum FN_OnEvent
  346. static int eventIndex = GetFunctionIndex("OnEvent");
  347. AZ_Assert(eventIndex != -1, "We can't find event with name %s", "OnEvent");
  348. Call(eventIndex, data);
  349. }
  350. int OnEventWithResult(int data) override
  351. {
  352. int result = 0; // default result as a function hook might not exists
  353. CallResult(result, FN_OnEventWithResult, data);
  354. return result;
  355. }
  356. int OnEventWithResultContainer(const AZStd::vector<int> values) override
  357. {
  358. int result = 0;
  359. CallResult(result, FN_OnEventWithResultContainer, values);
  360. return result;
  361. }
  362. GlobalClassEnum OnEventWithClassEnumResult() override
  363. {
  364. GlobalClassEnum result = GlobalClassEnum::Value1;
  365. CallResult(result, FN_OnEventWithClassEnumResult);
  366. return result;
  367. }
  368. AZStd::string OnEventWithStringResult() override
  369. {
  370. AZStd::string result;
  371. CallResult(result, FN_OnEventWithStringResult);
  372. return result;
  373. }
  374. BehaviorTestClass OnEventWithClassResult() override
  375. {
  376. BehaviorTestClass result;
  377. CallResult(result, FN_OnEventWithClassResult);
  378. return result;
  379. }
  380. AZStd::string OnEventWithDefaultValueAndStringResult(AZStd::string_view view1, AZStd::string_view view2) override
  381. {
  382. return BehaviorTestBus::Handler::OnEventWithDefaultValueAndStringResult(view1, view2);
  383. }
  384. BehaviorTestClass OnEventResultWithBehaviorClassParameter(BehaviorTestClass data) override
  385. {
  386. BehaviorTestClass result = data;
  387. return result;
  388. }
  389. };
  390. // traditional EBus Handler
  391. class NativeBehaviorTestBusHandler : public BehaviorTestBus::Handler
  392. {
  393. public:
  394. NativeBehaviorTestBusHandler()
  395. {
  396. m_enumResult = GlobalClassEnum::Value2;
  397. BehaviorTestBus::Handler::BusConnect(1);
  398. }
  399. void OnEvent(int data) override
  400. {
  401. g_globalData = 2000 + data;
  402. }
  403. int OnEventWithResult(int data) override
  404. {
  405. g_globalData = 2100 + data;
  406. return data + 3;
  407. }
  408. int OnEventWithResultContainer(const AZStd::vector<int> values) override
  409. {
  410. g_globalData = 2100 + values[0];
  411. return values[0];
  412. }
  413. GlobalClassEnum OnEventWithClassEnumResult() override
  414. {
  415. return m_enumResult;
  416. }
  417. GlobalClassEnum m_enumResult;
  418. };
  419. /// Hooks
  420. void OnEventHook(void* userData, int data)
  421. {
  422. (void)userData;
  423. g_globalData = 2200 + data;
  424. }
  425. int OnEventWithResultHook(void* userData, int data)
  426. {
  427. (void)userData;
  428. g_globalData = 2300 + data;
  429. return data + 30;
  430. }
  431. void OnEventGenericHook(void* userData, const char* eventName, int eventIndex, BehaviorArgument* result, int numParameters, BehaviorArgument* parameters)
  432. {
  433. (void)userData; (void)numParameters; (void)result; (void)eventName; (void)eventIndex;
  434. AZ_Assert(result == nullptr || strstr(eventName, "OnEventWithResult"), "We don't exepct result here");
  435. AZ_Assert(numParameters == 1, "Invalid number of parameters!");
  436. AZ_Assert(parameters[0].ConvertTo<int>(), "The parameter should be int, and convertable to it");
  437. int* intData = parameters[0].GetAsUnsafe<int>();
  438. g_globalData = 2400 + *intData;
  439. if (result)
  440. {
  441. result->StoreResult(*intData + 50);
  442. }
  443. }
  444. void globalGenericMethod(ScriptDataContext& dc)
  445. {
  446. if (dc.GetNumArguments())
  447. {
  448. if (dc.IsNumber(0))
  449. {
  450. int data;
  451. dc.ReadArg(0, data);
  452. dc.PushResult(data + 5);
  453. }
  454. }
  455. }
  456. class BehaviorTestSmartPtr
  457. {
  458. public:
  459. AZ_CLASS_ALLOCATOR(BehaviorTestSmartPtr, AZ::SystemAllocator);
  460. AZ_TYPE_INFO(BehaviorTestSmartPtr, "{b59d3416-a77c-4e71-b638-4212705a07e6}");
  461. BehaviorTestSmartPtr()
  462. : m_intrusiveRefCount(0)
  463. , m_data(303)
  464. {
  465. }
  466. //////////////////////////////////////////////////////////////////////////
  467. // instrusive_ptr
  468. // TODO: Add intrusive pointers helpers (RefCounted<T> and RefCountedThreadSave<T> or as a policy RefCounter<T, ThreadSafe>
  469. void add_ref()
  470. {
  471. ++m_intrusiveRefCount;
  472. }
  473. void release()
  474. {
  475. if (--m_intrusiveRefCount == 0)
  476. {
  477. delete this;
  478. }
  479. }
  480. int m_intrusiveRefCount;
  481. //////////////////////////////////////////////////////////////////////////
  482. void TestFunction()
  483. {
  484. g_globalData = 1090;
  485. }
  486. int m_data;
  487. };
  488. void IncrementBehaviorTestSmartPtrSharedPtr(AZStd::shared_ptr<BehaviorTestSmartPtr>& sp)
  489. {
  490. if (sp)
  491. {
  492. ++sp->m_data;
  493. }
  494. };
  495. void IncrementBehaviorTestSmartPtrIntrusivePtr(AZStd::intrusive_ptr<BehaviorTestSmartPtr>& sp)
  496. {
  497. if (sp)
  498. {
  499. ++sp->m_data;
  500. }
  501. }
  502. void PointerIsNullptr(BehaviorTestSmartPtr* value)
  503. {
  504. AZ_TEST_ASSERT(value == nullptr);
  505. }
  506. void BehaviorTestTemplatedOnDemandReflection(const AZStd::vector<int>& values)
  507. {
  508. g_globalData = 2500 + static_cast<int>(values.size());
  509. }
  510. int BehaviorGlobalMethodAfterBind()
  511. {
  512. return 3030;
  513. }
  514. int BehaviorGlobalPropertyGetAfterBind()
  515. {
  516. return g_globalData + 101;
  517. }
  518. void BehaviorGlobalPropertySetAfterBind(int data)
  519. {
  520. g_globalData = data;
  521. }
  522. struct BehaviorClassAfterBind
  523. {
  524. AZ_CLASS_ALLOCATOR(BehaviorClassAfterBind, AZ::SystemAllocator);
  525. AZ_TYPE_INFO(BehaviorClassAfterBind, "{72de521d-5880-43b7-93e9-ab06a3770946}");
  526. int m_data;
  527. };
  528. class ClassRequestBusEvents : public AZ::EBusTraits
  529. {
  530. public:
  531. virtual int GetData() = 0;
  532. virtual void SetData(int data) = 0;
  533. };
  534. using ClassRequestEBus = EBus<ClassRequestBusEvents>;
  535. class ClassInteractingWithEBus : public ClassRequestEBus::Handler
  536. {
  537. public:
  538. AZ_TYPE_INFO(ClassInteractingWithEBus, "{28d9591f-d233-442f-af62-81096b64d703}");
  539. ClassInteractingWithEBus()
  540. : m_data(0)
  541. {
  542. BusConnect();
  543. }
  544. int GetData() override { return m_data; }
  545. void SetData(int data) override { m_data = data; }
  546. int m_data;
  547. };
  548. static void ScriptErrorAssertCB(AZ::ScriptContext*, AZ::ScriptContext::ErrorType, const char*)
  549. {
  550. AZ_TEST_ASSERT(false);
  551. }
  552. class BehaviorContextTest
  553. : public BehaviorContextFixture
  554. {
  555. public:
  556. void SetUp() override
  557. {
  558. BehaviorContextFixture::SetUp();
  559. ResetGlobalVars();
  560. }
  561. void ResetGlobalVars()
  562. {
  563. g_globalValue = 501;
  564. g_globalData = 0;
  565. globalClassEnumValue = GlobalClassEnum::Value3;
  566. }
  567. void run()
  568. {
  569. // Constants/Enum
  570. m_behaviorContext->Constant("globalConstant", []() { return 3.14f; });
  571. m_behaviorContext->Constant("globalConstantMacro", BehaviorConstant(3.14f));
  572. m_behaviorContext->Enum<(int)GE_VALUE1>("GE_VALUE1");
  573. m_behaviorContext->Enum<(int)GlobalClassEnum::Value1>("Value1");
  574. m_behaviorContext->Enum<(int)GlobalClassEnum::Value2>("Value2");
  575. // Property
  576. m_behaviorContext->Property("globalProperty", &globalPropertyGetter, &globalPropertySetter)
  577. ->Attribute("GlobalPropAttr", 1);
  578. m_behaviorContext->Property("globalPropertyLambda", []() { return g_globalValue; }, [](int v) { g_globalValue = v; });
  579. m_behaviorContext->Property("globalPropertyMacro", BehaviorValueProperty(&g_globalValue));
  580. m_behaviorContext->Property("globalPropertyReadOnly", BehaviorValueGetter(&g_globalValue), nullptr); // read only property
  581. // Property by address???
  582. m_behaviorContext->Class<GlobalData>();
  583. // Method
  584. const int defaultIntValue = 20;
  585. m_behaviorContext->Method("globalMethod", &globalMethod, m_behaviorContext->MakeDefaultValues(555))
  586. ->Attribute("GlobalMethodAttr", 5);
  587. m_behaviorContext->Method("globalMethod1", &globalMethod1);
  588. m_behaviorContext->Method("globalMethod2WithDefaultArgument", &globalMethod2WithDefaultArgument, { {{"Value", "An Integer argument", m_behaviorContext->MakeDefaultValue(defaultIntValue)}} });
  589. m_behaviorContext->Method("globalMethodContainers", &globalMethodContainers);
  590. m_behaviorContext->Method("globalMethodPair", &globalMethodPair);
  591. m_behaviorContext->Method("globalMethodToOverride", &globalMethodToOverride)
  592. ->Attribute(Script::Attributes::MethodOverride, &globalMethodOverride);
  593. m_behaviorContext->Method("globalMethodLarge", &globalMethodLarge);
  594. m_behaviorContext->Method("TestTemplatedOnDemandReflection", &BehaviorTestTemplatedOnDemandReflection);
  595. m_behaviorContext->Method("IncrementTestSmartPtrSharedPtr", &IncrementBehaviorTestSmartPtrSharedPtr);
  596. m_behaviorContext->Method("IncrementTestSmartPtrIntrusivePtr", &IncrementBehaviorTestSmartPtrIntrusivePtr);
  597. m_behaviorContext->Method("globalMethodGetClassEnum", &globalMethodGetClassEnum);
  598. m_behaviorContext->Method("globalMethodSetClassEnum", &globalMethodSetClassEnum);
  599. m_behaviorContext->Method("PointerIsNullptr", &PointerIsNullptr);
  600. // Class
  601. m_behaviorContext->Class<BehaviorTestClass>()->
  602. Constructor<int>()->
  603. Attribute("ClassAttr",10)->
  604. Attribute(AZ::Script::Attributes::Storage,AZ::Script::Attributes::StorageType::Value)->
  605. Attribute(AZ::Script::Attributes::ConstructorOverride,&TestScriptNonIntrusiveConstructor)->
  606. Constant("epsilon", BehaviorConstant(0.001f))->
  607. Enum<(int)BehaviorTestClass::ME_VALUE0>("ME_VALUE0")->
  608. Enum<(int)BehaviorTestClass::MyClassEnum::MCE_VALUE0>("MCE_VALUE0")->
  609. Enum<(int)BehaviorTestClass::MyClassEnum::MCE_VALUE1>("MCE_VALUE1")->
  610. Method("Method1", &BehaviorTestClass::Method1)->
  611. Attribute("MethodAttr", 20)->
  612. Method("Method2", &BehaviorTestClass::Method2)->
  613. Method("SpecialScriptMethod", &BehaviorTestClass::SpecialScriptMethod)->
  614. Method("OverrideMethod", &BehaviorTestClass::MethodToOverrideInScript)->
  615. Attribute(Script::Attributes::MethodOverride, &BehaviorTestClass::Method1ScriptOverride)->
  616. Method("OverrideMethod1", &BehaviorTestClass::MethodToOverrideInScriptWithANonMember)->
  617. Attribute(Script::Attributes::MethodOverride, &TestMethodToScriptOverride)->
  618. Method("GetClass", &BehaviorTestClass::GetClass)->
  619. Method("AddOperator", &BehaviorTestClass::AddOperator)->
  620. Attribute(AZ::Script::Attributes::Operator,AZ::Script::Attributes::OperatorType::Add)->
  621. Method("ToString", &BehaviorTestClass::ToString)->
  622. Method("StaticMethod", &BehaviorTestClass::StaticMethod)->
  623. Method("MemberWithDefaultValues", &BehaviorTestClass::BoundsCheckMethodWithDefaultValue, { {{"value", "Value which will be checked to be within the two bounds arguments"}, {"delta", "The epsilon value", m_behaviorContext->MakeDefaultValue(0.1f)},
  624. {"minBound", "The minimum bounds value,", m_behaviorContext->MakeDefaultValue(0.0f)}, {"maxBound", "The maximum bounds value", m_behaviorContext->MakeDefaultValue(1.0f)}} })->
  625. Property("data", &BehaviorTestClass::GetData, &BehaviorTestClass::SetData)->
  626. Attribute("PropAttr", 30)->
  627. Property("data1", BehaviorValueProperty(&BehaviorTestClass::m_data1))->
  628. Property("dataReadOnly", BehaviorValueGetter(&BehaviorTestClass::m_dataReadOnly), nullptr);
  629. m_behaviorContext->Class<BehaviorDerivedTestClass>()->
  630. Property("derivedData", BehaviorValueProperty(&BehaviorDerivedTestClass::m_data));
  631. m_behaviorContext->Class<BehaviorTestSmartPtr>()->
  632. Method("TestFunction", &BehaviorTestSmartPtr::TestFunction)->
  633. Property("data", BehaviorValueProperty(&BehaviorTestSmartPtr::m_data));
  634. // Class Global Class enum wrapper
  635. m_behaviorContext->Class<BehaviorGlobalClassEnumWrapper>()
  636. ->Constant("VALUE1", BehaviorConstant(GlobalClassEnum::Value1))
  637. ->Constant("VALUE2", BehaviorConstant(GlobalClassEnum::Value2))
  638. ;
  639. // EBus
  640. const AZStd::string_view defaultStringViewValue = "DEFAULT!!!!";
  641. AZStd::string expectedDefaultValueAndStringResult = AZStd::string::format("Default Value: %s", defaultStringViewValue.data());
  642. BehaviorDefaultValuePtr defaultStringViewBehaviorValue = m_behaviorContext->MakeDefaultValue(defaultStringViewValue);
  643. BehaviorDefaultValuePtr superDefaultStringViewBehaviorValue = m_behaviorContext->MakeDefaultValue(AZStd::string_view("SUPER DEFAULT!!!!"));
  644. m_behaviorContext->EBus<BehaviorTestBus>("TestBus")
  645. ->Attribute("EBusAttr", 40)
  646. ->Handler<BehaviorTestBusHandler>()
  647. ->Attribute("HandlerAttr", 50)
  648. ->Event("OnEvent", &BehaviorTestBus::Events::OnEvent)
  649. ->Attribute("EventAttr", 60)
  650. ->Event("OnEventWithResult", &BehaviorTestBus::Events::OnEventWithResult)
  651. ->Event("OnEventWithResultContainer", &BehaviorTestBus::Events::OnEventWithResultContainer)
  652. ->Event("OnEventWithClassEnumResult", &BehaviorTestBus::Events::OnEventWithClassEnumResult)
  653. ->Event("OnEventWithStringResult", &BehaviorTestBus::Events::OnEventWithStringResult)
  654. ->Event("OnEventResultWithBehaviorClassParameter", &BehaviorTestBus::Events::OnEventResultWithBehaviorClassParameter)
  655. ->Event("OnEventWithDefaultValueAndStringResult", &BehaviorTestBus::Events::OnEventWithDefaultValueAndStringResult,
  656. { {{"view1", "string_view without string trait", defaultStringViewBehaviorValue, AZ::BehaviorParameter::TR_NONE, AZ::BehaviorParameter::TR_STRING},
  657. {"view2", "string_view with string trait", superDefaultStringViewBehaviorValue}} }) // Remove string trait from parameter
  658. ->Event("OnEventConst", &BehaviorTestBus::Events::OnEventConst)
  659. ;
  660. // Calls
  661. BehaviorMethod* method = m_behaviorContext->m_methods.find("globalMethod")->second;
  662. int result = 0;
  663. method->InvokeResult(result,3);
  664. AZ_TEST_ASSERT(result == 6);
  665. // check with default values
  666. method->InvokeResult(result);
  667. AZ_TEST_ASSERT(result == 558);
  668. // Check attr
  669. AZ_Assert(method->m_attributes[0].first == Crc32("GlobalMethodAttr"), "Expected attribute");
  670. AttributeData<int>* attrData = azrtti_cast<AttributeData<int>*>(method->m_attributes[0].second);
  671. AZ_Assert(attrData != nullptr, "This must be a valid attribute!");
  672. int attrValue = attrData->Get(nullptr);
  673. (void)attrValue;
  674. AZ_Assert(attrValue == 5, "Data should be 5");
  675. method = m_behaviorContext->m_methods.find("globalMethod1")->second;
  676. method->Invoke();
  677. method = m_behaviorContext->m_methods.find("globalMethod2WithDefaultArgument")->second;
  678. int defaultValueMethodResult = 0;
  679. method->InvokeResult(defaultValueMethodResult);
  680. EXPECT_EQ(defaultIntValue + 1, defaultValueMethodResult);
  681. AZStd::vector<int> values = { 10, 11, 12 };
  682. method = m_behaviorContext->m_methods.find("globalMethodContainers")->second;
  683. method->InvokeResult(result, values);
  684. // Global property
  685. BehaviorProperty* prop = m_behaviorContext->m_properties.find("globalProperty")->second;
  686. prop->m_setter->Invoke(3);
  687. prop->m_getter->InvokeResult(result);
  688. // Check attr
  689. AZ_Assert(prop->m_attributes[0].first == Crc32("GlobalPropAttr"), "Expected attribute");
  690. attrData = azrtti_cast<AttributeData<int>*>(prop->m_attributes[0].second);
  691. AZ_Assert(attrData != nullptr, "This must be a valid attribute!");
  692. attrValue = attrData->Get(nullptr);
  693. AZ_Assert(attrValue == 1, "Data should be 1");
  694. // Global read only property
  695. prop = m_behaviorContext->m_properties.find("globalPropertyReadOnly")->second;
  696. AZ_Assert(prop->m_setter == nullptr, "This property should be read only!");
  697. prop->m_getter->InvokeResult(result);
  698. // Constant
  699. prop = m_behaviorContext->m_properties.find("globalConstant")->second;
  700. float fResult = 0.0f;
  701. prop->m_getter->InvokeResult(fResult);
  702. // Enum
  703. GlobalClassEnum enumResult = GlobalClassEnum::Value2;
  704. method = m_behaviorContext->m_methods.find("globalMethodGetClassEnum")->second;
  705. method->InvokeResult(enumResult);
  706. AZ_TEST_ASSERT(enumResult == GlobalClassEnum::Value1);
  707. method = m_behaviorContext->m_methods.find("globalMethodSetClassEnum")->second;
  708. method->Invoke(GlobalClassEnum::Value2);
  709. // Classes
  710. BehaviorClass* behaviorClass = m_behaviorContext->m_classes.find("BehaviorTestClass")->second;
  711. BehaviorObject classInstance = behaviorClass->Create();
  712. {
  713. // Check attr
  714. AZ_Assert(behaviorClass->m_attributes[0].first == Crc32("ClassAttr"), "Expected attribute");
  715. attrData = azrtti_cast<AttributeData<int>*>(behaviorClass->m_attributes[0].second);
  716. AZ_Assert(attrData != nullptr, "This must be a valid attribute!");
  717. attrValue = attrData->Get(classInstance.m_address);
  718. AZ_Assert(attrValue == 10, "Data should be 10");
  719. }
  720. method = behaviorClass->m_methods.find("Method1")->second;
  721. method->Invoke(classInstance);
  722. {
  723. // Check attr
  724. AZ_Assert(method->m_attributes[0].first == Crc32("MethodAttr"), "Expected attribute");
  725. attrData = azrtti_cast<AttributeData<int>*>(method->m_attributes[0].second);
  726. AZ_Assert(attrData != nullptr, "This must be a valid attribute!");
  727. attrValue = attrData->Get(classInstance.m_address);
  728. AZ_Assert(attrValue == 20, "Data should be 20");
  729. }
  730. method = behaviorClass->m_methods.find("Method2")->second;
  731. EXPECT_TRUE(method->m_isConst);
  732. // Generic class instance
  733. int v = 5;
  734. method->InvokeResult(result, classInstance, &v);
  735. // Generic result
  736. BehaviorObject tc;
  737. method = behaviorClass->m_methods.find("GetClass")->second;
  738. method->InvokeResult(tc, classInstance);
  739. EXPECT_TRUE(method->IsMember());
  740. method = behaviorClass->m_methods.find("StaticMethod")->second;
  741. EXPECT_FALSE(method->IsMember());
  742. method = behaviorClass->m_methods.find("MemberWithDefaultValues")->second;
  743. EXPECT_TRUE(method->IsMember());
  744. bool withinBounds = false;
  745. method->InvokeResult(withinBounds, classInstance, 0.4f);
  746. EXPECT_TRUE(withinBounds);
  747. method->InvokeResult(withinBounds, classInstance, -1.1f);
  748. EXPECT_FALSE(withinBounds);
  749. // Class property
  750. prop = behaviorClass->m_properties.find("data")->second;
  751. EXPECT_TRUE(prop->m_getter->m_isConst);
  752. EXPECT_FALSE(prop->m_setter->m_isConst);
  753. prop->m_setter->Invoke(classInstance,12);
  754. prop->m_getter->InvokeResult(result,classInstance);
  755. {
  756. // Check attr
  757. AZ_Assert(prop->m_attributes[0].first == Crc32("PropAttr"), "Expected attribute");
  758. attrData = azrtti_cast<AttributeData<int>*>(prop->m_attributes[0].second);
  759. AZ_Assert(attrData != nullptr, "This must be a valid attribute!");
  760. attrValue = attrData->Get(classInstance.m_address);
  761. AZ_Assert(attrValue == 30, "Data should be 30");
  762. }
  763. // Class value property
  764. prop = behaviorClass->m_properties.find("data1")->second;
  765. prop->m_setter->Invoke(classInstance, 30);
  766. prop->m_getter->InvokeResult(result, classInstance);
  767. // Class value read only property
  768. prop = behaviorClass->m_properties.find("dataReadOnly")->second;
  769. AZ_Assert(prop->m_setter == nullptr, "Setter should be null!");
  770. prop->m_getter->InvokeResult(result, classInstance);
  771. // Test function conversion of parameters using RTTI (it this case base classes)
  772. method = behaviorClass->m_methods.find("Method1")->second;
  773. BehaviorDerivedTestClass tt;
  774. method->Invoke(&tt);
  775. //////////////////////////////////////////////////////////////////////////
  776. // EBus
  777. //////////////////////////////////////////////////////////////////////////
  778. // EBus - send events
  779. BehaviorTestBus::BusIdType testId = 1;
  780. BehaviorEBus* behaviorEBus = m_behaviorContext->m_ebuses.find("TestBus")->second;
  781. {
  782. // Check attr
  783. AZ_Assert(behaviorEBus->m_attributes[0].first == Crc32("EBusAttr"), "Expected attribute");
  784. attrData = azrtti_cast<AttributeData<int>*>(behaviorEBus->m_attributes[0].second);
  785. AZ_Assert(attrData != nullptr, "This must be a valid attribute!");
  786. attrValue = attrData->Get(nullptr);
  787. AZ_Assert(attrValue == 40, "Data should be 40");
  788. }
  789. // create handler for events
  790. BehaviorEBusHandler* testBusHandler = nullptr;
  791. behaviorEBus->m_createHandler->InvokeResult(testBusHandler);
  792. testBusHandler->InstallHook("OnEvent", &OnEventHook);
  793. testBusHandler->InstallHook("OnEventWithResult", &OnEventWithResultHook);
  794. // generic event handler
  795. BehaviorEBusHandler* genericTestBusHandler = nullptr;
  796. behaviorEBus->m_createHandler->InvokeResult(genericTestBusHandler);
  797. genericTestBusHandler->InstallGenericHook("OnEvent", &OnEventGenericHook);
  798. genericTestBusHandler->InstallGenericHook("OnEventWithResult", &OnEventGenericHook);
  799. {
  800. // Check attr
  801. AZ_Assert(behaviorEBus->m_createHandler->m_attributes[0].first == Crc32("HandlerAttr"), "Expected attribute");
  802. attrData = azrtti_cast<AttributeData<int>*>(behaviorEBus->m_createHandler->m_attributes[0].second);
  803. AZ_Assert(attrData != nullptr, "This must be a valid attribute!");
  804. attrValue = attrData->Get(nullptr);
  805. AZ_Assert(attrValue == 50, "Data should be 50");
  806. }
  807. // connect handlers to receive events
  808. testBusHandler->Connect(testId);
  809. genericTestBusHandler->Connect(testId);
  810. // fire some events
  811. BehaviorEBusEventSender* ebusSender = &behaviorEBus->m_events.find("OnEvent")->second;
  812. method = ebusSender->m_broadcast;
  813. method->Invoke(10);
  814. {
  815. // Check attr
  816. AZ_Assert(ebusSender->m_attributes[0].first == Crc32("EventAttr"), "Expected attribute");
  817. attrData = azrtti_cast<AttributeData<int>*>(ebusSender->m_attributes[0].second);
  818. AZ_Assert(attrData != nullptr, "This must be a valid attribute!");
  819. attrValue = attrData->Get(nullptr);
  820. AZ_Assert(attrValue == 60, "Data should be 60");
  821. }
  822. method = behaviorEBus->m_events.find("OnEventWithResult")->second.m_broadcast;
  823. method->InvokeResult(result, 11);
  824. method = behaviorEBus->m_events.find("OnEventWithResult")->second.m_event;
  825. method->InvokeResult(result, testId, 15);
  826. method = behaviorEBus->m_events.find("OnEvent")->second.m_queueBroadcast;
  827. method->Invoke(1);
  828. method = behaviorEBus->m_events.find("OnEvent")->second.m_queueEvent;
  829. method->Invoke(testId, 2);
  830. method = behaviorEBus->m_events.find("OnEventWithDefaultValueAndStringResult")->second.m_broadcast;
  831. AZStd::string defaultStringResultValue;
  832. method->InvokeResult(defaultStringResultValue);
  833. EXPECT_EQ(expectedDefaultValueAndStringResult, defaultStringResultValue);
  834. method = behaviorEBus->m_events.find("OnEventWithDefaultValueAndStringResult")->second.m_event;
  835. defaultStringResultValue.clear();
  836. method->InvokeResult(defaultStringResultValue, testId);
  837. EXPECT_EQ(expectedDefaultValueAndStringResult, defaultStringResultValue);
  838. EXPECT_EQ(3u, method->GetNumArguments());
  839. EXPECT_EQ(1u, method->GetMinNumberOfArguments());
  840. EXPECT_TRUE(method->HasResult());
  841. const AZ::BehaviorParameter* stringResultParam = method->GetResult();
  842. EXPECT_NE(nullptr, stringResultParam);
  843. EXPECT_TRUE(AZ::BehaviorContextHelper::IsStringParameter(*stringResultParam));
  844. // The first string_view param has removed the TR_STRING trait
  845. const AZ::BehaviorParameter* stringView1Param = method->GetArgument(1);
  846. EXPECT_NE(nullptr, stringView1Param);
  847. EXPECT_FALSE(AZ::BehaviorContextHelper::IsStringParameter(*stringView1Param));
  848. // The second string_view param has the TR_STRING trait
  849. const AZ::BehaviorParameter* stringView2Param = method->GetArgument(2);
  850. EXPECT_NE(nullptr, stringView2Param);
  851. EXPECT_TRUE(AZ::BehaviorContextHelper::IsStringParameter(*stringView2Param));
  852. method = behaviorEBus->m_events.find("OnEventConst")->second.m_event;
  853. EXPECT_TRUE(method->m_isConst);
  854. method = behaviorEBus->m_events.find("OnEventConst")->second.m_broadcast;
  855. EXPECT_TRUE(method->m_isConst);
  856. method = behaviorEBus->m_events.find("OnEventConst")->second.m_queueEvent;
  857. EXPECT_TRUE(method->m_isConst);
  858. method = behaviorEBus->m_events.find("OnEventConst")->second.m_queueBroadcast;
  859. EXPECT_TRUE(method->m_isConst);
  860. BehaviorTestBus::ExecuteQueuedEvents();
  861. delete testBusHandler;
  862. delete genericTestBusHandler;
  863. // class enums
  864. {
  865. NativeBehaviorTestBusHandler nativeTestBusHandler;
  866. ebusSender = &behaviorEBus->m_events.find("OnEventWithClassEnumResult")->second;
  867. method = ebusSender->m_broadcast;
  868. GlobalClassEnum classEnumResult = GlobalClassEnum::Value1;
  869. method->InvokeResult(classEnumResult);
  870. AZ_TEST_ASSERT(classEnumResult == GlobalClassEnum::Value2);
  871. }
  872. behaviorClass->Destroy(classInstance);
  873. m_behaviorContext->Method("globalGenericMethod", &globalGenericMethod);
  874. {
  875. ScriptContext sc;
  876. sc.BindTo(m_behaviorContext);
  877. // global methods
  878. sc.Execute("value = globalMethod(12)");
  879. sc.Execute("value = globalGenericMethod(value)");
  880. sc.Execute("value = globalMethodToOverride(20)");
  881. sc.Execute("value = globalMethodLarge()");
  882. // global method with a vector (OnDemandReflection)
  883. sc.Execute("intVector = vector_int()");
  884. sc.Execute("intVector:push_back(74)");
  885. AZ_TEST_START_TRACE_SUPPRESSION;
  886. ScriptContext::ErrorHook oldHook = sc.GetErrorHook();
  887. sc.SetErrorHook(ScriptErrorAssertCB);
  888. sc.Execute("intVector.push_back(74)"); // missing self pointer
  889. sc.SetErrorHook(oldHook);
  890. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  891. // test index operators
  892. sc.Execute("globalProperty = intVector[1]"); // read a value using custom operator
  893. AZ_TEST_ASSERT(g_globalValue == 74);
  894. //sc.Execute("intVector[6] = 128"); // write a value (set and resize) using custom operator
  895. //sc.Execute("globalProperty = intVector[2]");
  896. //AZ_TEST_ASSERT(g_globalValue == 0); // on resize we initialize with default value
  897. //sc.Execute("globalProperty = intVector[6]");
  898. //AZ_TEST_ASSERT(g_globalValue == 128);
  899. sc.Execute("pair = pair_int_bool()");
  900. sc.Execute("pair.first = 7; pair.second = true;");
  901. sc.Execute("globalProperty = globalMethodPair(pair)");
  902. EXPECT_EQ(7, g_globalValue);
  903. sc.Execute("TestTemplatedOnDemandReflection(intVector)");
  904. // global properties
  905. sc.Execute("value = globalProperty");
  906. sc.Execute("globalProperty = value + 10");
  907. // classes
  908. sc.Execute("testClass = BehaviorTestClass(11)");
  909. // class methods
  910. sc.Execute("testClass:Method1()");
  911. sc.Execute("testClass:Method2(12)");
  912. sc.Execute("value = testClass:SpecialScriptMethod(11)");
  913. sc.Execute("value = testClass:OverrideMethod(12)");
  914. sc.Execute("value = testClass:OverrideMethod1(13)");
  915. sc.Execute("testClass1 = testClass:GetClass()");
  916. // Test static methods
  917. sc.Execute("BehaviorTestClass.StaticMethod(1090)");
  918. EXPECT_EQ(1090, g_globalData);
  919. AZ_TEST_START_TRACE_SUPPRESSION;
  920. sc.Execute("testClass:StaticMethod(1090)");
  921. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  922. AZ_TEST_START_TRACE_SUPPRESSION;
  923. sc.Execute("BehaviorTestClass.Method1(nil)");
  924. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  925. // class properties
  926. sc.Execute("value = testClass.data");
  927. sc.Execute("testClass.data = value + 11");
  928. // class operators
  929. sc.Execute("testClass1 = BehaviorTestClass() testClass1.data = 203");
  930. sc.Execute("testClass2 = testClass1 + testClass");
  931. sc.Execute("testClass1.data = testClass2.data + 23");
  932. // derived classes
  933. sc.Execute("derivedTestClass = BehaviorDerivedTestClass()");
  934. sc.Execute("derivedTestClass.derivedData = 101");
  935. sc.Execute("derivedTestClass.data = 13");
  936. // smart ptr
  937. sc.Execute("smartIntrusivePtr = intrusive_ptr_BehaviorTestSmartPtr(BehaviorTestSmartPtr())");
  938. sc.Execute("IncrementTestSmartPtrIntrusivePtr(smartIntrusivePtr)"); // pass the smartPointer to a function as a smart pointer
  939. sc.Execute("rawPointer = smartIntrusivePtr:get() rawPointer:TestFunction()"); // get the raw pointer and call a function
  940. sc.Execute("smartIntrusivePtr:TestFunction()"); // call the wrapped function directly from the smart pointer
  941. sc.Execute("PointerIsNullptr(nil)");
  942. // ebus
  943. NativeBehaviorTestBusHandler myTestBusHandler;
  944. // broadcast
  945. sc.Execute("TestBus.Broadcast.OnEvent(10)");
  946. // class enum
  947. sc.Execute("eventClassResult = TestBus.Broadcast.OnEventWithClassEnumResult()");
  948. sc.Execute("globalMethodSetClassEnum(eventClassResult)");
  949. // events
  950. sc.Execute("TestBus.Event.OnEvent(0,20)"); // send event to ID 0 (not listener)
  951. sc.Execute("TestBus.Event.OnEvent(1,30)"); // send event to ID 1
  952. // queue broadcast
  953. sc.Execute("TestBus.QueueBroadcast.OnEvent(50)");
  954. // queue event
  955. sc.Execute("TestBus.QueueEvent.OnEvent(1,60)");
  956. // queue function
  957. sc.Execute("function QueuedFunctionOnTestBus(a,b,c)\
  958. globalProperty = a + b + c\
  959. end\
  960. TestBus.QueueFunction(QueuedFunctionOnTestBus,1,2,3)");
  961. BehaviorTestBus::ExecuteQueuedEvents();
  962. myTestBusHandler.BusDisconnect();
  963. //////////////////////////////////////////////////////////////////////////
  964. // handling ebus multiple return values
  965. NativeBehaviorTestBusHandler myTestBusHandler1;
  966. NativeBehaviorTestBusHandler myTestBusHandler2;
  967. myTestBusHandler1.m_enumResult = GlobalClassEnum::Value1;
  968. myTestBusHandler2.m_enumResult = GlobalClassEnum::Value2;
  969. // use a table as result container
  970. sc.Execute("eventClassResult = { TestBus.Broadcast.OnEventWithClassEnumResult() }");
  971. globalClassEnumValue = GlobalClassEnum::Value3;
  972. sc.Execute("globalMethodSetClassEnum(eventClassResult[1])");
  973. AZ_TEST_ASSERT(globalClassEnumValue == GlobalClassEnum::Value2);
  974. sc.Execute("globalMethodSetClassEnum(eventClassResult[2])");
  975. AZ_TEST_ASSERT(globalClassEnumValue == GlobalClassEnum::Value1);
  976. // use multiple variables as result container
  977. sc.Execute("result1, result2 = TestBus.Broadcast.OnEventWithClassEnumResult()");
  978. globalClassEnumValue = GlobalClassEnum::Value3;
  979. sc.Execute("globalMethodSetClassEnum(result1)");
  980. AZ_TEST_ASSERT(globalClassEnumValue == GlobalClassEnum::Value2);
  981. sc.Execute("globalMethodSetClassEnum(result2)");
  982. AZ_TEST_ASSERT(globalClassEnumValue == GlobalClassEnum::Value1);
  983. // collect garbage before running next test so any destructors get called
  984. sc.Execute(R"LUA(
  985. collectgarbage()
  986. )LUA");
  987. g_globalTestClassesConstructed = 0;
  988. g_globalTestClassesDestructed = 0;
  989. // test whether the behavior parameters that are passed by value have their
  990. // constructors/destructors called equally
  991. sc.Execute(R"LUA(
  992. local behaviorParameter = BehaviorTestClass();
  993. local result = TestBus.Broadcast.OnEventResultWithBehaviorClassParameter(behaviorParameter);
  994. behaviorParameter = nil;
  995. result = nil;
  996. collectgarbage();
  997. )LUA");
  998. AZ_TEST_ASSERT(g_globalTestClassesConstructed > 0);
  999. AZ_TEST_ASSERT(g_globalTestClassesDestructed > 0);
  1000. AZ_TEST_ASSERT(g_globalTestClassesConstructed == g_globalTestClassesDestructed);
  1001. myTestBusHandler1.BusDisconnect();
  1002. myTestBusHandler2.BusDisconnect();
  1003. //////////////////////////////////////////////////////////////////////////
  1004. // create handler
  1005. sc.Execute(R"LUA(
  1006. testBusHandler = {}
  1007. function testBusHandler:OnEvent(data)
  1008. globalProperty = data
  1009. globalProperty = TestBus.GetCurrentBusId()
  1010. end
  1011. function testBusHandler:OnEventWithClassEnumResult()
  1012. return BehaviorGlobalClassEnumWrapper.VALUE2
  1013. end
  1014. function testBusHandler:OnEventWithStringResult()
  1015. return 'success';
  1016. end
  1017. function testBusHandler:OnEventWithClassResult()
  1018. local result = BehaviorTestClass(100);
  1019. result.data = 100;
  1020. return result;
  1021. end
  1022. testBusHandler = TestBus.Connect(testBusHandler,1)
  1023. )LUA");
  1024. // check if we can handle event
  1025. BehaviorTestBus::Broadcast(&BehaviorTestBus::Events::OnEvent, 101);
  1026. // broadcast a class enum
  1027. GlobalClassEnum globalClassEnumResult = GlobalClassEnum::Value1;
  1028. BehaviorTestBus::BroadcastResult(globalClassEnumResult, &BehaviorTestBus::Events::OnEventWithClassEnumResult);
  1029. AZ_TEST_ASSERT(globalClassEnumResult == GlobalClassEnum::Value2);
  1030. AZStd::string stringResult;
  1031. BehaviorTestBus::BroadcastResult(stringResult, &BehaviorTestBus::Events::OnEventWithStringResult);
  1032. EXPECT_STREQ("success", stringResult.c_str());
  1033. BehaviorTestClass classResult;
  1034. BehaviorTestBus::BroadcastResult(classResult, &BehaviorTestBus::Events::OnEventWithClassResult);
  1035. EXPECT_EQ(100, classResult.m_data);
  1036. // disconnect
  1037. sc.Execute("testBusHandler:Disconnect()");
  1038. // test events
  1039. BehaviorTestBus::Broadcast(&BehaviorTestBus::Events::OnEvent, 201); // it should have no effect
  1040. //////////////////////////////////////////////////////////////////////////
  1041. // Test reflecting after the bind
  1042. m_behaviorContext->Method("BehaviorGlobalMethodAfterBind", &BehaviorGlobalMethodAfterBind);
  1043. sc.Execute("afterBindValue = BehaviorGlobalMethodAfterBind()");
  1044. m_behaviorContext->Property("globalPropertyAfterBind", &BehaviorGlobalPropertyGetAfterBind, &BehaviorGlobalPropertySetAfterBind);
  1045. sc.Execute("globalPropertyAfterBind = afterBindValue");
  1046. AZ_TEST_ASSERT(g_globalData == 3030);
  1047. m_behaviorContext->Class<BehaviorClassAfterBind>()->
  1048. Property("data", BehaviorValueProperty(&BehaviorClassAfterBind::m_data));
  1049. sc.Execute("classAfterBind = BehaviorClassAfterBind() classAfterBind.data = 1012 globalPropertyAfterBind = classAfterBind.data");
  1050. AZ_TEST_ASSERT(g_globalData == 1012);
  1051. //////////////////////////////////////////////////////////////////////////
  1052. //////////////////////////////////////////////////////////////////////////
  1053. // Classes using EBuses for communication and virtual ebus properties
  1054. m_behaviorContext->Class<ClassInteractingWithEBus>()->
  1055. RequestBus("ClassRequestEBus");
  1056. m_behaviorContext->EBus<ClassRequestEBus>("ClassRequestEBus")->
  1057. Attribute(AZ::Script::Attributes::DisallowBroadcast, true)->
  1058. Event("GetData", &ClassRequestEBus::Events::GetData)->
  1059. Event("SetData", &ClassRequestEBus::Events::SetData)->
  1060. VirtualProperty("data", "GetData", "SetData");
  1061. BehaviorClass* classInteractingWithEBus = m_behaviorContext->m_classes.find("ClassInteractingWithEBus")->second;
  1062. AZ_TEST_ASSERT(classInteractingWithEBus->m_requestBuses.size() == 1);
  1063. AZ_TEST_ASSERT(classInteractingWithEBus->m_requestBuses.find("ClassRequestEBus") != classInteractingWithEBus->m_requestBuses.end());
  1064. BehaviorEBus* classRequestBus = m_behaviorContext->m_ebuses.find("ClassRequestEBus")->second;
  1065. AZ_TEST_ASSERT(classRequestBus->m_virtualProperties.size() == 1);
  1066. const BehaviorEBus::VirtualProperty& virtualEBusProperty = classRequestBus->m_virtualProperties.find("data")->second;
  1067. AZ_TEST_START_TRACE_SUPPRESSION;
  1068. sc.Execute("ClassRequestEBus.Broadcast.GetData()");
  1069. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  1070. {
  1071. ClassInteractingWithEBus listenerClassInstance; // setup a listener, otherwise property value can't be stored
  1072. listenerClassInstance.m_data = 1010;
  1073. // get the value of the ebus property. In practice those request buses use ID to identify a single handler, then we just use m_event instead of m_broadcast
  1074. int data = 0;
  1075. virtualEBusProperty.m_getter->m_broadcast->InvokeResult(data);
  1076. AZ_TEST_ASSERT(data == 1010);
  1077. // set the value of the ebus property.
  1078. virtualEBusProperty.m_setter->m_broadcast->Invoke(3030);
  1079. AZ_TEST_ASSERT(listenerClassInstance.m_data == 3030);
  1080. }
  1081. //////////////////////////////////////////////////////////////////////////
  1082. }
  1083. }
  1084. };
  1085. TEST_F(BehaviorContextTest, LuaTest)
  1086. {
  1087. run();
  1088. }
  1089. TEST_F(BehaviorContextTest, LuaBehaviorEBusHandlerWithDocMacroCompilesSuccessfully)
  1090. {
  1091. AZ::BehaviorContext behaviorContext;
  1092. behaviorContext.EBus<BehaviorTestBus>("TestBusWithEbusHandlerThatSupportsNameAndTooltip")
  1093. ->Handler<BehaviorTestBusHandlerWithDoc>()
  1094. ;
  1095. auto BehaviorEBusFoundIt = behaviorContext.m_ebuses.find("TestBusWithEbusHandlerThatSupportsNameAndTooltip");
  1096. ASSERT_NE(behaviorContext.m_ebuses.end(), BehaviorEBusFoundIt);
  1097. AZ::BehaviorEBus* behaviorEBus = BehaviorEBusFoundIt->second;
  1098. ASSERT_NE(nullptr, behaviorEBus->m_createHandler);
  1099. AZ::BehaviorEBusHandler* handlerResult{};
  1100. EXPECT_TRUE(behaviorEBus->m_createHandler->InvokeResult(handlerResult));
  1101. ASSERT_NE(nullptr, handlerResult);
  1102. auto handlerDeleter = [behaviorEBus](AZ::BehaviorEBusHandler* handler)
  1103. {
  1104. behaviorEBus->m_destroyHandler->Invoke(handler);
  1105. };
  1106. AZStd::unique_ptr<AZ::BehaviorEBusHandler, decltype(handlerDeleter)> ebusHandler(handlerResult, AZStd::move(handlerDeleter));
  1107. const AZ::BehaviorEBusHandler::EventArray handlerEvents = ebusHandler->GetEvents();
  1108. auto stringViewEventIt = AZStd::find_if(handlerEvents.begin(), handlerEvents.end(), [](const AZ::BehaviorEBusHandler::BusForwarderEvent& handlerEvent)
  1109. {
  1110. return strcmp(handlerEvent.m_name, "OnEventWithDefaultValueAndStringResult") == 0;
  1111. });
  1112. ASSERT_NE(handlerEvents.end(), stringViewEventIt);
  1113. ASSERT_EQ(AZ::eBehaviorBusForwarderEventIndices::ParameterFirst + 2, stringViewEventIt->m_metadataParameters.size());
  1114. EXPECT_EQ("defaultView", stringViewEventIt->m_metadataParameters[AZ::eBehaviorBusForwarderEventIndices::ParameterFirst].m_name);
  1115. EXPECT_EQ("string_view which contains literal to print by default", stringViewEventIt->m_metadataParameters[AZ::eBehaviorBusForwarderEventIndices::ParameterFirst].m_toolTip);
  1116. EXPECT_EQ("unusedView", stringViewEventIt->m_metadataParameters[AZ::eBehaviorBusForwarderEventIndices::ParameterFirst + 1].m_name);
  1117. EXPECT_EQ("Unused test parameter", stringViewEventIt->m_metadataParameters[AZ::eBehaviorBusForwarderEventIndices::ParameterFirst + 1].m_toolTip);
  1118. }
  1119. } // namespace Unittest
  1120. #if !defined(AZCORE_EXCLUDE_LUA)
  1121. namespace UnitTest
  1122. {
  1123. class IncompleteType;
  1124. }
  1125. namespace AZ
  1126. {
  1127. AZ_TYPE_INFO_SPECIALIZE(UnitTest::IncompleteType, "{53CC592A-E4B8-4F89-A293-87C7838A6108}");
  1128. AZ_TYPE_INFO_SPECIALIZE(UnitTest::GlobalEnum, "{8A34A34C-B547-4724-8D3B-E12B8774E338}");
  1129. }
  1130. using namespace AZ;
  1131. namespace UnitTest
  1132. {
  1133. int s_globalVar = 0;
  1134. bool s_globalVarBool = false;
  1135. float s_globalVar1 = 0.0f;
  1136. float s_globalVar2ReadOnly = 10.0f;
  1137. float s_globalVar3WriteOnly = 0.0f;
  1138. AZStd::string s_globalVarString;
  1139. int s_globalField = 0;
  1140. int s_globalField1 = 12;
  1141. int s_globalField2 = 0;
  1142. static int s_errorCount = 0;
  1143. IncompleteType* s_globalIncompletePtr = static_cast<IncompleteType*>(AZ_INVALID_POINTER);
  1144. IncompleteType* s_globalIncompletePtr1 = nullptr;
  1145. void GlobalVarSet(int v)
  1146. {
  1147. s_globalVar = v;
  1148. }
  1149. int GlobalVarGet()
  1150. {
  1151. return s_globalVar;
  1152. }
  1153. void GlobalVarStringSet(const char* v)
  1154. {
  1155. s_globalVarString = v;
  1156. }
  1157. const char* GlobalVarStringGet()
  1158. {
  1159. return s_globalVarString.c_str();
  1160. }
  1161. void GlobalCheckString(AZStd::string globalVarString)
  1162. {
  1163. AZ_TEST_ASSERT(s_globalVarString == globalVarString);
  1164. }
  1165. void GlobalCheckStringRef(const AZStd::string& globalVarString)
  1166. {
  1167. AZ_TEST_ASSERT(s_globalVarString == globalVarString);
  1168. }
  1169. int GlobalFunc0()
  1170. {
  1171. return 0;
  1172. }
  1173. int GlobalFunc1(int)
  1174. {
  1175. return 1;
  1176. }
  1177. int GlobalFunc2(int, float)
  1178. {
  1179. return 2;
  1180. }
  1181. int GlobalFunc3(int, float, bool)
  1182. {
  1183. return 3;
  1184. }
  1185. int GlobalFunc4(int, float, bool, int)
  1186. {
  1187. return 4;
  1188. }
  1189. int GlobalFunc5(int, float, bool, int, float)
  1190. {
  1191. return 5;
  1192. }
  1193. int GlobalFunc0Override()
  1194. {
  1195. return 10;
  1196. }
  1197. void GlobalVoidFunc0()
  1198. {
  1199. s_globalVar = 0;
  1200. }
  1201. void GlobalVoidFunc1(int v)
  1202. {
  1203. s_globalVar = v;
  1204. }
  1205. void GlobalVoidFunc2(int v, float) { s_globalVar = v; }
  1206. void GlobalVoidFunc3(int v, float, bool) { s_globalVar = v; }
  1207. void GlobalVoidFunc4(int v, float, bool, int) { s_globalVar = v; }
  1208. void GlobalVoidFunc5(int v, float, bool, int, float) { s_globalVar = v; }
  1209. void GlobalEnumFunc(GlobalEnum value) { s_globalVar = static_cast<int>(value); }
  1210. void VariadicFunc(ScriptDataContext& context)
  1211. {
  1212. s_globalVar = context.GetNumArguments();
  1213. context.PushResult(s_globalVar * 2);
  1214. }
  1215. class ScriptClass2;
  1216. class ScriptClass4;
  1217. class ScriptClass5;
  1218. class ScriptBindTest
  1219. : public BehaviorContextFixture
  1220. {
  1221. static ScriptBindTest* s_scriptBindInstance;
  1222. public:
  1223. AZStd::fixed_vector<ScriptClass2*, 10> scriptClass2Instances;
  1224. AZStd::fixed_vector< AZStd::shared_ptr<ScriptClass4>, 10 > scriptClass4lockedInstances;
  1225. int scriptClass4numInstances = 0;
  1226. AZStd::fixed_vector< AZStd::intrusive_ptr<ScriptClass5>, 10 > scriptClass5lockedInstances;
  1227. int scriptClass5numInstances = 0;
  1228. void SetUp() override;
  1229. void TearDown() override;
  1230. void ResetGlobalVars();
  1231. static ScriptBindTest* GetScriptBindInstance()
  1232. {
  1233. return s_scriptBindInstance;
  1234. }
  1235. static bool EnumClass(const char* name, const AZ::Uuid& /*typeid*/, void* /*userData*/);
  1236. static bool EnumMethod(const AZ::Uuid* /*type id*/, const char* name, const char* dbgParamInfo, void* /*userData*/);
  1237. static bool EnumProperty(const AZ::Uuid* /*type id*/, const char* name, bool isRead, bool isWrite, void* /*userData*/);
  1238. static void ScriptErrorCB(AZ::ScriptContext*, AZ::ScriptContext::ErrorType, const char* details);
  1239. void run();
  1240. };
  1241. ScriptBindTest* ScriptBindTest::s_scriptBindInstance = nullptr;
  1242. class ScriptClass* s_scriptClassInstance = nullptr;
  1243. class ScriptClass
  1244. {
  1245. public:
  1246. AZ_TYPE_INFO(ScriptClass, "{7b91cb47-a271-4031-8114-56d38efabc4f}");
  1247. AZ_CLASS_ALLOCATOR(ScriptClass, SystemAllocator);
  1248. enum LocalEnum
  1249. {
  1250. SC_ET_VALUE2 = 2,
  1251. SC_ET_VALUE3,
  1252. };
  1253. ScriptClass()
  1254. : m_data(0)
  1255. , m_data1(0.0f)
  1256. , m_data2ReadOnly(11.0f)
  1257. , m_data3WriteOnly(0.0f)
  1258. {
  1259. if (s_scriptClassInstance == nullptr)
  1260. {
  1261. s_scriptClassInstance = this;
  1262. }
  1263. }
  1264. ScriptClass(float dataReadOnly)
  1265. : m_data(0)
  1266. , m_data1(0.0f)
  1267. , m_data2ReadOnly(dataReadOnly)
  1268. , m_data3WriteOnly(0.0f)
  1269. {
  1270. if (s_scriptClassInstance == nullptr)
  1271. {
  1272. s_scriptClassInstance = this;
  1273. }
  1274. }
  1275. ~ScriptClass()
  1276. {
  1277. if (s_scriptClassInstance == this)
  1278. {
  1279. s_scriptClassInstance = nullptr;
  1280. }
  1281. }
  1282. int MemberFunc0() { return 0; }
  1283. int MemberFunc1(int) { return 1; }
  1284. int MemberFunc2(int, float) { return 2; }
  1285. int MemberFunc3(int, float, bool) { return 3; }
  1286. int MemberFunc4(int, float, bool, int) { return 4; }
  1287. int MemberFunc5(int, float, bool, int, float) { return 5; }
  1288. void MemberVoidFunc0() { m_data = 0; }
  1289. void MemberVoidFunc1(int v) { m_data = v; }
  1290. void MemberVoidFunc2(int v, float) { m_data = v; }
  1291. void MemberVoidFunc3(int v, float, bool) { m_data = v; }
  1292. void MemberVoidFunc4(int v, float, bool, int) { m_data = v; }
  1293. void MemberVoidFunc5(int v, float, bool, int, float) { m_data = v; }
  1294. int GetData() const { return m_data; }
  1295. void SetData(int data) { m_data = data; }
  1296. void VariadicFunc(ScriptDataContext& context)
  1297. {
  1298. s_globalVar = context.GetNumArguments();
  1299. }
  1300. int m_data;
  1301. float m_data1;
  1302. float m_data2ReadOnly;
  1303. float m_data3WriteOnly;
  1304. struct ScriptClassNested
  1305. {
  1306. ScriptClassNested()
  1307. : m_data(100) {}
  1308. int m_data;
  1309. };
  1310. };
  1311. void* ScriptClassAllocate(void* userData)
  1312. {
  1313. (void)userData;
  1314. return azmalloc(sizeof(ScriptClass),AZStd::alignment_of<ScriptClass>::value,AZ::SystemAllocator);
  1315. }
  1316. void ScriptClassFree(void* obj, void* userData)
  1317. {
  1318. (void)userData;
  1319. azfree(obj, AZ::SystemAllocator, sizeof(ScriptClass), AZStd::alignment_of<ScriptClass>::value);
  1320. }
  1321. class ScriptClass1
  1322. {
  1323. public:
  1324. AZ_CLASS_ALLOCATOR(ScriptClass1, SystemAllocator);
  1325. ScriptClass1()
  1326. : m_data(0.0f) {}
  1327. float m_data;
  1328. };
  1329. class ScriptClass2
  1330. {
  1331. public:
  1332. AZ_TYPE_INFO(ScriptClass2, "{b4482151-b246-4c95-9ab3-db4589b3ffa0}");
  1333. AZ_CLASS_ALLOCATOR(ScriptClass2, SystemAllocator);
  1334. ScriptClass2(int data)
  1335. : m_data(data)
  1336. {
  1337. ScriptBindTest::GetScriptBindInstance()->scriptClass2Instances.push_back(this);
  1338. }
  1339. ScriptClass2(const ScriptClass2& rhs)
  1340. {
  1341. m_data = rhs.m_data;
  1342. ScriptBindTest::GetScriptBindInstance()->scriptClass2Instances.push_back(this);
  1343. }
  1344. ~ScriptClass2()
  1345. {
  1346. auto& scriptClass2Instances = ScriptBindTest::GetScriptBindInstance()->scriptClass2Instances;
  1347. auto instanceIt = AZStd::find(scriptClass2Instances.begin(), scriptClass2Instances.end(), this);
  1348. if (instanceIt != scriptClass2Instances.end())
  1349. {
  1350. scriptClass2Instances.erase(instanceIt);
  1351. }
  1352. }
  1353. void VariadicFunc(ScriptDataContext& context)
  1354. {
  1355. (void)context;
  1356. }
  1357. bool operator<(const ScriptClass2& rhs) const { return m_data < rhs.m_data; }
  1358. bool operator<=(const ScriptClass2& rhs) const { return m_data < rhs.m_data; }
  1359. bool operator==(const ScriptClass2& rhs) const { return m_data == rhs.m_data; }
  1360. ScriptClass2 ScriptAdd(const ScriptClass2& rhs) const { return ScriptClass2(m_data + rhs.m_data); }
  1361. ScriptClass2 ScriptSub(const ScriptClass2& rhs) const { return ScriptClass2(m_data - rhs.m_data); }
  1362. ScriptClass2 ScriptMul(const ScriptClass2& rhs) const { return ScriptClass2(m_data * rhs.m_data); }
  1363. ScriptClass2 ScriptDiv(const ScriptClass2& rhs) const { return ScriptClass2(m_data / rhs.m_data); }
  1364. ScriptClass2 ScriptMod(const ScriptClass2& rhs) const { return ScriptClass2(m_data % rhs.m_data); }
  1365. ScriptClass2 ScriptPow(const ScriptClass2& rhs) const { return ScriptClass2((int)pow((float)m_data, rhs.m_data)); }
  1366. ScriptClass2 ScriptUnary() const
  1367. {
  1368. return ScriptClass2(-m_data);
  1369. }
  1370. ScriptClass2 ScriptConcat(const ScriptClass2& rhs) const { return ScriptClass2(m_data + rhs.m_data); }
  1371. int ScriptLength() const { return m_data; }
  1372. const char* ToString() const { return "This is ScriptClass2"; }
  1373. ScriptClass2* Forward() { return this; }
  1374. int m_data;
  1375. };
  1376. class ScriptClass3* s_scriptClass3Instance = nullptr;
  1377. class ScriptClass3
  1378. {
  1379. public:
  1380. AZ_TYPE_INFO(ScriptClass3, "{058b255b-1abf-4831-9ea9-8b8cb6a7a634}");
  1381. AZ_CLASS_ALLOCATOR(ScriptClass3, SystemAllocator);
  1382. ScriptClass3()
  1383. {
  1384. m_bool = false;
  1385. m_intData = 0;
  1386. m_floatData = 0.0f;
  1387. m_incompletePtr = nullptr;
  1388. }
  1389. ScriptClass3(ScriptDataContext& ctx)
  1390. {
  1391. m_bool = false;
  1392. m_intData = 0;
  1393. m_floatData = 0.0f;
  1394. m_incompletePtr = nullptr;
  1395. // unpack variadic parameters
  1396. AZ_TEST_ASSERT(ctx.GetNumArguments() == 4);
  1397. AZ_TEST_ASSERT(ctx.IsBoolean(0));
  1398. AZ_TEST_ASSERT(ctx.IsNumber(1));
  1399. AZ_TEST_ASSERT(ctx.IsNumber(2));
  1400. AZ_TEST_ASSERT(ctx.IsRegisteredClass(3) == false);
  1401. ctx.ReadArg(0, m_bool);
  1402. ctx.ReadArg(1, m_intData);
  1403. ctx.ReadArg(2, m_floatData);
  1404. ctx.ReadArg(3, m_incompletePtr);
  1405. m_scriptClass2 = nullptr;
  1406. if (s_scriptClass3Instance == nullptr)
  1407. {
  1408. s_scriptClass3Instance = this;
  1409. }
  1410. }
  1411. ~ScriptClass3()
  1412. {
  1413. if (s_scriptClass3Instance == this)
  1414. {
  1415. s_scriptClass3Instance = nullptr;
  1416. }
  1417. }
  1418. const char* ToString() const { return "This is ScriptClass3"; }
  1419. bool m_bool;
  1420. int m_intData;
  1421. float m_floatData;
  1422. IncompleteType* m_incompletePtr;
  1423. ScriptClass2* m_scriptClass2;
  1424. private:
  1425. // TODO: Simulate private copy constructor when AZStd::is_copy_constructible works
  1426. //ScriptClass3(const ScriptClass3&) = delete;
  1427. };
  1428. class ScriptClass4
  1429. {
  1430. public:
  1431. AZ_TYPE_INFO(ScriptClass4, "{4ecb714f-c73d-4a80-84d4-b55b145c3033}");
  1432. AZ_CLASS_ALLOCATOR(ScriptClass4, SystemAllocator);
  1433. ScriptClass4(int data)
  1434. : m_data(data)
  1435. {
  1436. int& numClass4Instances = ScriptBindTest::GetScriptBindInstance()->scriptClass4numInstances;
  1437. numClass4Instances++;
  1438. }
  1439. ~ScriptClass4()
  1440. {
  1441. int& numClass4Instances = ScriptBindTest::GetScriptBindInstance()->scriptClass4numInstances;
  1442. numClass4Instances--;
  1443. }
  1444. static void HoldInstance(const AZStd::shared_ptr<ScriptClass4>& ptr)
  1445. {
  1446. auto& class4lockedInstances = ScriptBindTest::GetScriptBindInstance()->scriptClass4lockedInstances;
  1447. class4lockedInstances.push_back(ptr);
  1448. }
  1449. void CopyData(AZStd::shared_ptr<ScriptClass4> rhs)
  1450. {
  1451. m_data = rhs->m_data;
  1452. }
  1453. int m_data;
  1454. };
  1455. class ScriptClass5
  1456. {
  1457. public:
  1458. AZ_TYPE_INFO(ScriptClass5, "{99a1e378-d457-45d0-bd49-72b21d3368c5}");
  1459. AZ_CLASS_ALLOCATOR(ScriptClass5, SystemAllocator);
  1460. ScriptClass5(int data)
  1461. : m_data(data)
  1462. , m_refCount(0)
  1463. {
  1464. int& numClass5Instances = ScriptBindTest::GetScriptBindInstance()->scriptClass5numInstances;
  1465. numClass5Instances++;
  1466. }
  1467. ~ScriptClass5()
  1468. {
  1469. int& numClass5Instances = ScriptBindTest::GetScriptBindInstance()->scriptClass5numInstances;
  1470. numClass5Instances--;
  1471. }
  1472. void add_ref() { m_refCount++; }
  1473. void release()
  1474. {
  1475. m_refCount--;
  1476. if (m_refCount == 0)
  1477. {
  1478. delete this;
  1479. }
  1480. }
  1481. static void HoldInstance(const AZStd::intrusive_ptr<ScriptClass5>& ptr)
  1482. {
  1483. auto& class5lockedInstances = ScriptBindTest::GetScriptBindInstance()->scriptClass5lockedInstances;
  1484. class5lockedInstances.push_back(ptr);
  1485. }
  1486. void CopyData(const AZStd::intrusive_ptr<ScriptClass5>& rhs)
  1487. {
  1488. m_data = rhs->m_data;
  1489. }
  1490. int m_data;
  1491. int m_refCount;
  1492. };
  1493. struct ScriptValueClass
  1494. {
  1495. AZ_TYPE_INFO(ScriptValueClass, "{78b1baa9-483b-42c7-8c1e-4eba903bd529}");
  1496. AZ_CLASS_ALLOCATOR(ScriptValueClass, SystemAllocator);
  1497. ScriptValueClass()
  1498. : m_data(10)
  1499. {
  1500. }
  1501. ScriptValueClass(const ScriptValueClass& rhs)
  1502. {
  1503. (void)rhs;
  1504. AZ_TEST_ASSERT(false); // we should not make copies
  1505. }
  1506. int m_data;
  1507. };
  1508. struct ScriptValueHolder
  1509. {
  1510. AZ_TYPE_INFO(ScriptValueHolder, "{86887e28-dfc6-4619-87d8-3658da0996ec}");
  1511. AZ_CLASS_ALLOCATOR(ScriptValueHolder, SystemAllocator);
  1512. ScriptValueHolder()
  1513. {
  1514. }
  1515. ScriptValueHolder(const ScriptValueHolder& rhs)
  1516. {
  1517. (void)rhs;
  1518. AZ_TEST_ASSERT(false); // we should not make copies
  1519. }
  1520. ScriptValueClass m_value;
  1521. };
  1522. class ScriptUnregisteredBaseClass
  1523. {
  1524. public:
  1525. AZ_RTTI(ScriptUnregisteredBaseClass, "{0ebe10b0-617b-4086-bff1-d51523db8cd6}");
  1526. ScriptUnregisteredBaseClass()
  1527. : m_baseData(1) {}
  1528. virtual ~ScriptUnregisteredBaseClass() {}
  1529. virtual int GetData() const { return m_baseData; }
  1530. int m_baseData;
  1531. };
  1532. class ScriptUnregisteredDerivedClass
  1533. : public ScriptUnregisteredBaseClass
  1534. {
  1535. public:
  1536. AZ_RTTI(ScriptUnregisteredDerivedClass, "{5aba38c7-ae10-46d1-bc8e-3a0a00a3a97c}", ScriptUnregisteredBaseClass);
  1537. ScriptUnregisteredDerivedClass()
  1538. : m_derivedData(10) {}
  1539. int GetData() const override { return m_derivedData; }
  1540. int m_derivedData;
  1541. };
  1542. int GetUnregisteredScriptBaseData(ScriptUnregisteredBaseClass* base)
  1543. {
  1544. return base->GetData();
  1545. }
  1546. int GetUnregisteredScriptDerivedData(ScriptUnregisteredDerivedClass* derived)
  1547. {
  1548. return derived->m_derivedData;
  1549. }
  1550. ScriptUnregisteredBaseClass* s_globalUnregBaseClass = nullptr;
  1551. ScriptUnregisteredDerivedClass* s_globalUnregDerivedClass = nullptr;
  1552. class ScriptRegisteredBaseClass
  1553. {
  1554. public:
  1555. AZ_RTTI(ScriptRegisteredBaseClass, "{73c2f822-d1ef-4abc-accb-cb36599f6b66}");
  1556. AZ_CLASS_ALLOCATOR(ScriptRegisteredBaseClass, SystemAllocator);
  1557. ScriptRegisteredBaseClass()
  1558. : m_baseData(2) {}
  1559. virtual ~ScriptRegisteredBaseClass() {}
  1560. virtual int VirtualFunction()
  1561. {
  1562. return 0;
  1563. }
  1564. int m_baseData;
  1565. };
  1566. ScriptRegisteredBaseClass* s_globalRegisteredBaseClass = nullptr;
  1567. class ScriptRegisteredDerivedClass
  1568. : public ScriptRegisteredBaseClass
  1569. {
  1570. public:
  1571. AZ_RTTI(ScriptRegisteredDerivedClass, "{9f42df41-fdcc-44aa-909f-1f675804653c}", ScriptRegisteredBaseClass);
  1572. AZ_CLASS_ALLOCATOR(ScriptRegisteredDerivedClass, SystemAllocator);
  1573. ScriptRegisteredDerivedClass()
  1574. : m_derivedData(11) {}
  1575. ~ScriptRegisteredDerivedClass() override {}
  1576. int VirtualFunction() override
  1577. {
  1578. return 1;
  1579. }
  1580. int m_derivedData;
  1581. };
  1582. class AbstractClass
  1583. {
  1584. public:
  1585. AZ_RTTI(AbstractClass, "{d7082d66-108f-4177-8fb3-5cf25b510aa7}");
  1586. virtual ~AbstractClass() {}
  1587. virtual int PureCall() = 0;
  1588. };
  1589. class AbstractImplementation
  1590. : public AbstractClass
  1591. {
  1592. public:
  1593. AZ_RTTI(AbstractImplementation, "{62e1514d-57be-49c5-b829-d937f07276cd}", AbstractClass);
  1594. AZ_CLASS_ALLOCATOR(AbstractImplementation, SystemAllocator);
  1595. int PureCall() override { return 5; }
  1596. };
  1597. AZStd::shared_ptr<ScriptClass4> s_scriptMemberShared;
  1598. AZStd::intrusive_ptr<ScriptClass5> s_scriptMemberIntrusive;
  1599. void ScriptBindTest::SetUp()
  1600. {
  1601. BehaviorContextFixture::SetUp();
  1602. ResetGlobalVars();
  1603. s_scriptBindInstance = this;
  1604. s_scriptMemberShared = AZStd::shared_ptr<ScriptClass4>(aznew ScriptClass4(10));
  1605. s_scriptMemberIntrusive = AZStd::intrusive_ptr<ScriptClass5>(aznew ScriptClass5(10));
  1606. }
  1607. void ScriptBindTest::TearDown()
  1608. {
  1609. s_scriptMemberShared.reset();
  1610. s_scriptMemberIntrusive.reset();
  1611. s_scriptBindInstance = nullptr;
  1612. BehaviorContextFixture::TearDown();
  1613. }
  1614. void ScriptBindTest::ResetGlobalVars()
  1615. {
  1616. s_globalVar = 0;
  1617. s_globalVarBool = false;
  1618. s_globalVar1 = 0.0f;
  1619. s_globalVar2ReadOnly = 10.0f;
  1620. s_globalVar3WriteOnly = 0.0f;
  1621. s_globalVarString = AZStd::string();
  1622. s_globalField = 0;
  1623. s_globalField1 = 12;
  1624. s_globalField2 = 0;
  1625. s_errorCount = 0;
  1626. s_globalIncompletePtr = static_cast<IncompleteType*>(AZ_INVALID_POINTER);
  1627. s_globalIncompletePtr1 = nullptr;
  1628. }
  1629. bool ScriptBindTest::EnumClass(const char* name, const AZ::Uuid& /*typeid*/, void* /*userData*/)
  1630. {
  1631. AZ_TEST_ASSERT(name != nullptr);
  1632. return true;
  1633. }
  1634. bool ScriptBindTest::EnumMethod(const AZ::Uuid* /*type id*/, const char* name, const char* dbgParamInfo, void* /*userData*/)
  1635. {
  1636. // make sure the debug info works
  1637. if (strcmp(name, "GlobalFunc5") == 0)
  1638. {
  1639. AZ_TEST_ASSERT(strcmp(dbgParamInfo, "int NumberArguments (int intValue,float floatValue,bool Value,int intValue2,float floatValue2") == 0);
  1640. }
  1641. return true;
  1642. }
  1643. bool ScriptBindTest::EnumProperty(const AZ::Uuid* /*type id*/, const char* name, bool isRead, bool isWrite, void* /*userData*/)
  1644. {
  1645. if (strcmp(name, "globalVar") == 0)
  1646. {
  1647. AZ_TEST_ASSERT(isWrite && isRead);
  1648. }
  1649. if (strcmp(name, "globalVar2") == 0)
  1650. {
  1651. AZ_TEST_ASSERT(!isWrite && isRead);
  1652. }
  1653. if (strcmp(name, "globalVar3") == 0)
  1654. {
  1655. AZ_TEST_ASSERT(isWrite && !isRead);
  1656. }
  1657. return true;
  1658. }
  1659. void ScriptBindTest::ScriptErrorCB(AZ::ScriptContext*, AZ::ScriptContext::ErrorType, const char* details)
  1660. {
  1661. (void)details;
  1662. s_errorCount++;
  1663. AZ_Warning("Script", false, "%s", details);
  1664. }
  1665. void ScriptBindTest::run()
  1666. {
  1667. AZ::Uuid ch = AzTypeInfo<char>::Uuid();
  1668. AZ::Uuid ch1 = AzTypeInfo<const char*>::Uuid();
  1669. (void)ch; (void)ch1;
  1670. // enum
  1671. m_behaviorContext->Enum<GE_VALUE1>("GE_VALUE1")->
  1672. Enum<GE_VALUE2>("GE_VALUE2");
  1673. // constant
  1674. m_behaviorContext->Constant("PI", BehaviorConstant(3.14f));
  1675. // property
  1676. m_behaviorContext->Property("globalVar", &GlobalVarGet, &GlobalVarSet);
  1677. m_behaviorContext->Property("globalVar1", BehaviorValueProperty(&s_globalVar1));
  1678. m_behaviorContext->Property("globalVarBool", BehaviorValueProperty(&s_globalVarBool));
  1679. m_behaviorContext->Property("globalVar2", BehaviorValueGetter(&s_globalVar2ReadOnly), nullptr);
  1680. m_behaviorContext->Property("globalVar3", nullptr, BehaviorValueSetter(&s_globalVar3WriteOnly));
  1681. m_behaviorContext->Property("globalVarString", &GlobalVarStringGet, &GlobalVarStringSet);
  1682. // field
  1683. m_behaviorContext->Property("globalField", BehaviorValueProperty(&s_globalField));
  1684. m_behaviorContext->Property("globalField1", BehaviorValueGetter(&s_globalField1), nullptr);
  1685. m_behaviorContext->Property("globalField2", nullptr, BehaviorValueSetter(&s_globalField2));
  1686. m_behaviorContext->Property("globalIncomplete", BehaviorValueProperty(&s_globalIncompletePtr)); // unregistered type (passed as light userdata)
  1687. m_behaviorContext->Property("globalIncomplete1", BehaviorValueProperty(&s_globalIncompletePtr1)); // unregistered type (passed as light userdata)
  1688. // method
  1689. m_behaviorContext->Method("GlobalFunc0", &GlobalFunc0);
  1690. m_behaviorContext->Method("GlobalFunc1", &GlobalFunc1);
  1691. m_behaviorContext->Method("GlobalFunc2", &GlobalFunc2);
  1692. m_behaviorContext->Method("GlobalFunc3", &GlobalFunc3);
  1693. m_behaviorContext->Method("GlobalFunc4", &GlobalFunc4);
  1694. m_behaviorContext->Method("GlobalFunc5", &GlobalFunc5, nullptr, "int NumberArguments (int intValue,float floatValue,bool Value,int intValue2,float floatValue2");
  1695. m_behaviorContext->Method("GlobalVoidFunc0", &GlobalVoidFunc0);
  1696. m_behaviorContext->Method("GlobalVoidFunc1", &GlobalVoidFunc1);
  1697. m_behaviorContext->Method("GlobalVoidFunc2", &GlobalVoidFunc2);
  1698. m_behaviorContext->Method("GlobalVoidFunc3", &GlobalVoidFunc3);
  1699. m_behaviorContext->Method("GlobalVoidFunc4", &GlobalVoidFunc4);
  1700. m_behaviorContext->Method("GlobalVoidFunc5", &GlobalVoidFunc5);
  1701. m_behaviorContext->Method("GlobalEnumFunc", &GlobalEnumFunc);
  1702. m_behaviorContext->Method("GlobalCheckString", &GlobalCheckString);
  1703. m_behaviorContext->Method("GlobalCheckStringRef", &GlobalCheckStringRef);
  1704. // clases
  1705. m_behaviorContext->Class<ScriptClass>()->
  1706. Allocator(&ScriptClassAllocate, &ScriptClassFree)->
  1707. Enum<ScriptClass::SC_ET_VALUE2>("SC_ET_VALUE2")->
  1708. Enum<ScriptClass::SC_ET_VALUE3>("SC_ET_VALUE3")->
  1709. Constant("EPSILON", BehaviorConstant(0.001f))->
  1710. Method("MemberFunc0", &ScriptClass::MemberFunc0)->
  1711. Method("MemberFunc1", &ScriptClass::MemberFunc1)->
  1712. Method("MemberFunc2", &ScriptClass::MemberFunc2)->
  1713. Method("MemberFunc3", &ScriptClass::MemberFunc3)->
  1714. Method("MemberFunc4", &ScriptClass::MemberFunc4)->
  1715. Method("MemberFunc5", &ScriptClass::MemberFunc5)->
  1716. Method("MemberVoidFunc0", &ScriptClass::MemberVoidFunc0)->
  1717. Method("MemberVoidFunc1", &ScriptClass::MemberVoidFunc1)->
  1718. Method("MemberVoidFunc2", &ScriptClass::MemberVoidFunc2)->
  1719. Method("MemberVoidFunc3", &ScriptClass::MemberVoidFunc3)->
  1720. Method("MemberVoidFunc4", &ScriptClass::MemberVoidFunc4)->
  1721. Method("MemberVoidFunc5", &ScriptClass::MemberVoidFunc5)->
  1722. Method("VariadicFunc", &ScriptClass::VariadicFunc)->
  1723. Property("data", &ScriptClass::GetData, &ScriptClass::SetData)->
  1724. Property("data1", BehaviorValueProperty(&ScriptClass::m_data1))->
  1725. Property("data2", BehaviorValueGetter(&ScriptClass::m_data2ReadOnly), nullptr)->
  1726. Property("data3", nullptr, BehaviorValueSetter(&ScriptClass::m_data3WriteOnly));//->
  1727. //Class<ScriptClass::ScriptClassNested,ScriptContext::SP_RAW_SCRIPT_OWN>()->
  1728. // Field("data",&ScriptClass::ScriptClassNested::m_data)->
  1729. //ClassEnd();
  1730. m_behaviorContext->Class<ScriptClass2>()->
  1731. Constructor<int>()->
  1732. Method("Add", &ScriptClass2::ScriptAdd)->
  1733. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Add)->
  1734. Method("Sub", &ScriptClass2::ScriptSub)->
  1735. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Sub)->
  1736. Method("Mul", &ScriptClass2::ScriptMul)->
  1737. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Mul)->
  1738. Method("Div", &ScriptClass2::ScriptDiv)->
  1739. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Div)->
  1740. Method("Mod", &ScriptClass2::ScriptMod)->
  1741. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Mod)->
  1742. Method("Pow", &ScriptClass2::ScriptPow)->
  1743. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Pow)->
  1744. Method("Unary", &ScriptClass2::ScriptUnary)->
  1745. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Unary)->
  1746. Method("Concat", &ScriptClass2::ScriptConcat)->
  1747. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Concat)->
  1748. Method("Length", &ScriptClass2::ScriptLength)->
  1749. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)->
  1750. Method("Equal", &ScriptClass2::operator==)->
  1751. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)->
  1752. Method("LessEqual", &ScriptClass2::operator<=)->
  1753. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::LessEqualThan)->
  1754. Method("LessThan", &ScriptClass2::operator<)->
  1755. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::LessThan)->
  1756. Method("ToString", &ScriptClass2::ToString)->
  1757. Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)->
  1758. Method("Forward", &ScriptClass2::Forward)->
  1759. Property("data", BehaviorValueProperty(&ScriptClass2::m_data));
  1760. m_behaviorContext->Class<ScriptClass3>()->
  1761. Constructor<ScriptDataContext&>()->
  1762. Property("boolData", BehaviorValueProperty(&ScriptClass3::m_bool))->
  1763. Property("intData", BehaviorValueProperty(&ScriptClass3::m_intData))->
  1764. Property("floatData", BehaviorValueProperty(&ScriptClass3::m_floatData))->
  1765. Property("scriptClass2", BehaviorValueProperty(&ScriptClass3::m_scriptClass2));
  1766. m_behaviorContext->Class<ScriptClass4>()->
  1767. Constructor<int>()->
  1768. Method("CopyData", &ScriptClass4::CopyData)->
  1769. Property("data", BehaviorValueProperty(&ScriptClass4::m_data));
  1770. m_behaviorContext->Property("scriptClass4Member", BehaviorValueProperty(&s_scriptMemberShared));
  1771. m_behaviorContext->Method("HoldScriptClass4", &ScriptClass4::HoldInstance);
  1772. m_behaviorContext->Class<ScriptClass5>()->
  1773. Constructor<int>()->
  1774. Method("CopyData", &ScriptClass5::CopyData)->
  1775. Property("data", BehaviorValueProperty(&ScriptClass5::m_data));
  1776. m_behaviorContext->Property("scriptClass5Member", BehaviorValueProperty(&s_scriptMemberIntrusive));
  1777. m_behaviorContext->Method("HoldScriptClass5", &ScriptClass5::HoldInstance);
  1778. // Variadic method
  1779. m_behaviorContext->Method("VariadicFunc", &VariadicFunc);
  1780. // Check nested classes
  1781. m_behaviorContext->Class<ScriptValueClass>()->
  1782. Property("data", BehaviorValueProperty(&ScriptValueClass::m_data));
  1783. m_behaviorContext->Class<ScriptValueHolder>()->
  1784. Property("value", BehaviorValueProperty(&ScriptValueHolder::m_value));
  1785. // test class pointer casting for unregistered classes
  1786. m_behaviorContext->Property("globalUnregBaseClass", BehaviorValueProperty(&s_globalUnregBaseClass));
  1787. m_behaviorContext->Property("globalUnregDerivedClass", BehaviorValueProperty(&s_globalUnregDerivedClass));
  1788. m_behaviorContext->Method("GetUnregisteredScriptBaseData", &GetUnregisteredScriptBaseData);
  1789. m_behaviorContext->Method("GetUnregisteredScriptDerivedData", &GetUnregisteredScriptDerivedData);
  1790. // register a base and derived class test
  1791. m_behaviorContext->Class<ScriptRegisteredBaseClass>()->
  1792. Property("baseData", BehaviorValueProperty(&ScriptRegisteredBaseClass::m_baseData))->
  1793. Method("VirtualFunction", &ScriptRegisteredBaseClass::VirtualFunction);
  1794. // when using AZ_RTTI the bind will discover the 'ScriptRegisteredBaseClass' and import it's bindings
  1795. // into 'ScriptRegisteredDerivedClass' class so we access it (like in C++)
  1796. m_behaviorContext->Class<ScriptRegisteredDerivedClass>()->
  1797. Property("derivedData", BehaviorValueProperty(&ScriptRegisteredDerivedClass::m_derivedData));
  1798. // add a function that makes a derived class (can change at runtime) and return pointer to a base class.
  1799. m_behaviorContext->Property("globalRegisteredBaseClass", BehaviorValueProperty(&s_globalRegisteredBaseClass));
  1800. // abstract classes
  1801. m_behaviorContext->Class<AbstractClass>()->
  1802. Method("PureCall", &AbstractClass::PureCall);
  1803. m_behaviorContext->Class<AbstractImplementation>();
  1804. // create the lua script context and Bind it the behavior
  1805. ScriptContext script;
  1806. script.BindTo(m_behaviorContext);
  1807. // test globalVar with functions get and set
  1808. AZ_TEST_ASSERT(s_globalVar == 0);
  1809. script.Execute("globalVar = 5");
  1810. AZ_TEST_ASSERT(s_globalVar == 5);
  1811. script.Execute("globalVar = globalVar + 1");
  1812. AZ_TEST_ASSERT(s_globalVar == 6);
  1813. // test globalVar1 with variable address only
  1814. AZ_TEST_ASSERT(s_globalVar1 == 0.0f);
  1815. script.Execute("globalVar1 = 5");
  1816. AZ_TEST_ASSERT(s_globalVar1 == 5.0f);
  1817. script.Execute("globalVar1 = globalVar1 + 1.0");
  1818. AZ_TEST_ASSERT(s_globalVar1 == 6.0f);
  1819. // test globalVar2ReadOnly
  1820. s_globalVar1 = 0.0f;
  1821. AZ_TEST_ASSERT(s_globalVar2ReadOnly == 10.0f);
  1822. script.Execute("globalVar1 = globalVar2");
  1823. AZ_TEST_ASSERT(s_globalVar1 == 10.0f);
  1824. //script.Execute("globalVar2 = 5.0"); //- this will cause script error (we can improve the message by providing a fake set function);
  1825. // test globalVar2WriteOnly
  1826. AZ_TEST_ASSERT(s_globalVar3WriteOnly == 0.0f);
  1827. script.Execute("globalVar3 = 100");
  1828. AZ_TEST_ASSERT(s_globalVar3WriteOnly == 100.0f);
  1829. //script.Execute("print(\"globalVar3 is \",globalVar3)"); //- this will cause script error (we can improve the message by providing a fake set function);
  1830. // globalField with functions get and set
  1831. AZ_TEST_ASSERT(s_globalField == 0);
  1832. script.Execute("globalField = 5");
  1833. AZ_TEST_ASSERT(s_globalField == 5);
  1834. script.Execute("globalField = globalField +1");
  1835. AZ_TEST_ASSERT(s_globalField == 6);
  1836. // globalField1 read only
  1837. s_globalVar1 = 0.0f;
  1838. AZ_TEST_ASSERT(s_globalField1 == 12.0f);
  1839. script.Execute("globalVar1 = globalField1");
  1840. AZ_TEST_ASSERT(s_globalVar1 == 12.0f);
  1841. //script.Execute("globalField1 = 10.0"); //- this will cause script error (we can improve the message by providing a fake set function);
  1842. // globalField2 write only
  1843. AZ_TEST_ASSERT(s_globalField2 == 0.0f);
  1844. script.Execute("globalField2 = 100");
  1845. AZ_TEST_ASSERT(s_globalField2 == 100.0f);
  1846. //script.Execute("print(\"globalField2 is \",globalField2)"); //- this will cause script error (we can improve the message by providing a fake set function);
  1847. // s_globalVarString test
  1848. AZ_TEST_ASSERT(s_globalVarString.empty());
  1849. script.Execute("globalVarString = \"Hello\"");
  1850. AZ_TEST_ASSERT(s_globalVarString.compare("Hello") == 0);
  1851. // incomplete types passed by a light-user data (pointer reference)
  1852. AZ_TEST_ASSERT(s_globalIncompletePtr == reinterpret_cast<IncompleteType*>(AZ_INVALID_POINTER));
  1853. AZ_TEST_ASSERT(s_globalIncompletePtr1 == nullptr);
  1854. script.Execute("globalIncomplete1 = globalIncomplete");
  1855. AZ_TEST_ASSERT(s_globalIncompletePtr1 == s_globalIncompletePtr);
  1856. // enum
  1857. s_globalVar = 100;
  1858. script.Execute("globalVar = 0");
  1859. AZ_TEST_ASSERT(s_globalVar == 0);
  1860. s_globalVar = 100;
  1861. script.Execute("globalVar = GE_VALUE1");
  1862. AZ_TEST_ASSERT(s_globalVar == GE_VALUE1);
  1863. s_globalVar = 100;
  1864. script.Execute("globalVar = GE_VALUE2");
  1865. AZ_TEST_ASSERT(s_globalVar == GE_VALUE2);
  1866. s_globalVar = 100;
  1867. script.Execute("GlobalEnumFunc(GE_VALUE2)");
  1868. AZ_TEST_ASSERT(s_globalVar == GE_VALUE2);
  1869. // constant
  1870. s_globalVar1 = 0.0f;
  1871. script.Execute("globalVar1 = PI");
  1872. AZ_TEST_ASSERT_FLOAT_CLOSE(s_globalVar1, 3.14f);
  1873. // methods
  1874. s_globalVar = 5;
  1875. script.Execute("globalVar = GlobalFunc0()");
  1876. AZ_TEST_ASSERT(s_globalVar == 0);
  1877. s_globalVar = 0;
  1878. script.Execute("globalVar = GlobalFunc1(2)");
  1879. AZ_TEST_ASSERT(s_globalVar == 1);
  1880. s_globalVar = 0;
  1881. script.Execute("globalVar = GlobalFunc2(2,3)");
  1882. AZ_TEST_ASSERT(s_globalVar == 2);
  1883. s_globalVar = 0;
  1884. script.Execute("globalVar = GlobalFunc3(2,3,true)");
  1885. AZ_TEST_ASSERT(s_globalVar == 3);
  1886. s_globalVar = 0;
  1887. script.Execute("globalVar = GlobalFunc4(2,3,false,4)");
  1888. AZ_TEST_ASSERT(s_globalVar == 4);
  1889. s_globalVar = 0;
  1890. script.Execute("globalVar = GlobalFunc5(2,3,true,5,2)");
  1891. AZ_TEST_ASSERT(s_globalVar == 5);
  1892. s_globalVar = 5;
  1893. script.Execute("GlobalVoidFunc0()");
  1894. AZ_TEST_ASSERT(s_globalVar == 0);
  1895. s_globalVar = 0;
  1896. script.Execute("GlobalVoidFunc1(2)");
  1897. AZ_TEST_ASSERT(s_globalVar == 2);
  1898. s_globalVar = 0;
  1899. script.Execute("GlobalVoidFunc2(10,1)");
  1900. AZ_TEST_ASSERT(s_globalVar == 10);
  1901. s_globalVar = 0;
  1902. script.Execute("GlobalVoidFunc3(15,3,true)");
  1903. AZ_TEST_ASSERT(s_globalVar == 15);
  1904. s_globalVar = 0;
  1905. script.Execute("GlobalVoidFunc4(21,4,false,2)");
  1906. AZ_TEST_ASSERT(s_globalVar == 21);
  1907. s_globalVar = 0;
  1908. script.Execute("GlobalVoidFunc5(101,102,true,2,1)");
  1909. AZ_TEST_ASSERT(s_globalVar == 101);
  1910. script.Execute("GlobalCheckString(globalVarString)");
  1911. script.Execute("GlobalCheckStringRef(globalVarString)");
  1912. // test a variadic function
  1913. s_globalVar = 5;
  1914. script.Execute("globalVar1 = VariadicFunc()");
  1915. AZ_TEST_ASSERT(s_globalVar == 0);
  1916. AZ_TEST_ASSERT_FLOAT_CLOSE(s_globalVar1, 0.0f);
  1917. s_globalVar = 0;
  1918. script.Execute("globalVar1 = VariadicFunc(101,102,true,2,1)");
  1919. AZ_TEST_ASSERT(s_globalVar == 5);
  1920. AZ_TEST_ASSERT_FLOAT_CLOSE(s_globalVar1, 10.0f);
  1921. s_globalVar = 0;
  1922. script.Execute("globalVar1 = VariadicFunc(101,102)");
  1923. AZ_TEST_ASSERT(s_globalVar == 2);
  1924. AZ_TEST_ASSERT_FLOAT_CLOSE(s_globalVar1, 4.0f);
  1925. //////////////////////////////////////////////////////////////////////////
  1926. // Classes
  1927. s_globalVar = 0;
  1928. script.Execute("globalVar = scriptClass4Member.data");
  1929. AZ_TEST_ASSERT(s_globalVar == 10);
  1930. script.Execute("scriptClass4Member = nil");
  1931. AZ_TEST_ASSERT(s_scriptMemberShared == nullptr);
  1932. script.Execute("scriptClass4Member = shared_ptr_ScriptClass4(ScriptClass4(12))");
  1933. AZ_TEST_ASSERT(s_scriptMemberShared->m_data == 12);
  1934. // test invalid assignment
  1935. {
  1936. s_errorCount = 0;
  1937. auto originalErrorCB = script.GetErrorHook();
  1938. script.SetErrorHook(&ScriptErrorCB);
  1939. script.Execute("scriptClass4Member = ScriptClass5(12)");
  1940. script.SetErrorHook(originalErrorCB);
  1941. AZ_TEST_ASSERT(s_errorCount == 1);
  1942. }
  1943. script.Execute("scriptClass4Member = nil");
  1944. script.GarbageCollect();
  1945. AZ_TEST_ASSERT(scriptClass4numInstances == 0)
  1946. // test assignments of nil to intrusive pointer
  1947. s_globalVar = 0;
  1948. script.Execute("globalVar = scriptClass5Member.data");
  1949. AZ_TEST_ASSERT(s_globalVar == 10);
  1950. script.Execute("scriptClass5Member = nil");
  1951. AZ_TEST_ASSERT(s_scriptMemberShared == nullptr);
  1952. script.Execute("scriptClass5Member = intrusive_ptr_ScriptClass5(ScriptClass5(12))");
  1953. AZ_TEST_ASSERT(s_scriptMemberIntrusive->m_data == 12);
  1954. // test invalid assignment
  1955. {
  1956. s_errorCount = 0;
  1957. auto originalErrorCB = script.GetErrorHook();
  1958. script.SetErrorHook(&ScriptErrorCB);
  1959. script.Execute("scriptClass5Member = ScriptClass4(12)");
  1960. script.SetErrorHook(originalErrorCB);
  1961. AZ_TEST_ASSERT(s_errorCount == 1);
  1962. }
  1963. AZ_TEST_ASSERT(s_scriptMemberIntrusive->m_data == 12);
  1964. script.Execute("scriptClass5Member = nil");
  1965. script.GarbageCollect();
  1966. AZ_TEST_ASSERT(scriptClass5numInstances == 0)
  1967. // debug print
  1968. AZ_TEST_ASSERT(script.GetDebugContext() == nullptr);
  1969. script.EnableDebug();
  1970. if (script.GetDebugContext() != nullptr) // debug is NOT supported in release builds
  1971. {
  1972. script.GetDebugContext()->EnumRegisteredGlobals(&EnumMethod, &EnumProperty);
  1973. script.GetDebugContext()->EnumRegisteredClasses(&EnumClass, &EnumMethod, &EnumProperty);
  1974. script.DisableDebug();
  1975. AZ_TEST_ASSERT(script.GetDebugContext() == nullptr);
  1976. }
  1977. // create a ScriptClass instance from the script
  1978. AZ_TEST_ASSERT(s_scriptClassInstance == nullptr);
  1979. script.Execute("sc = ScriptClass()");
  1980. AZ_TEST_ASSERT(s_scriptClassInstance != nullptr);
  1981. // enum
  1982. s_globalVar = 0;
  1983. script.Execute("globalVar = sc.SC_ET_VALUE2");
  1984. AZ_TEST_ASSERT(s_globalVar == 2);
  1985. s_globalVar = 0;
  1986. script.Execute("globalVar = sc.SC_ET_VALUE3");
  1987. AZ_TEST_ASSERT(s_globalVar == 3);
  1988. // constant
  1989. s_globalVar1 = 0.0f;
  1990. script.Execute("globalVar1 = sc.EPSILON");
  1991. AZ_TEST_ASSERT_FLOAT_CLOSE(s_globalVar1, 0.001f);
  1992. // methods
  1993. s_globalVar = 1;
  1994. script.Execute("globalVar = sc:MemberFunc0()");
  1995. AZ_TEST_ASSERT(s_globalVar == 0);
  1996. s_globalVar = 0;
  1997. script.Execute("globalVar = sc:MemberFunc1(1)");
  1998. AZ_TEST_ASSERT(s_globalVar == 1);
  1999. s_globalVar = 0;
  2000. script.Execute("globalVar = sc:MemberFunc2(2,2.0)");
  2001. AZ_TEST_ASSERT(s_globalVar == 2);
  2002. s_globalVar = 0;
  2003. script.Execute("globalVar = sc:MemberFunc3(3,3.0,false)");
  2004. AZ_TEST_ASSERT(s_globalVar == 3);
  2005. s_globalVar = 0;
  2006. script.Execute("globalVar = sc:MemberFunc4(4,4.0,true,40)");
  2007. AZ_TEST_ASSERT(s_globalVar == 4);
  2008. s_globalVar = 0;
  2009. script.Execute("globalVar = sc:MemberFunc5(5,5.0,false,50,50.0)");
  2010. AZ_TEST_ASSERT(s_globalVar == 5);
  2011. s_scriptClassInstance->m_data = 10;
  2012. script.Execute("sc:MemberVoidFunc0()");
  2013. AZ_TEST_ASSERT(s_scriptClassInstance->m_data == 0);
  2014. s_scriptClassInstance->m_data = 0;
  2015. script.Execute("sc:MemberVoidFunc1(11)");
  2016. AZ_TEST_ASSERT(s_scriptClassInstance->m_data == 11);
  2017. s_scriptClassInstance->m_data = 0;
  2018. script.Execute("sc:MemberVoidFunc2(7,11)");
  2019. AZ_TEST_ASSERT(s_scriptClassInstance->m_data == 7);
  2020. s_scriptClassInstance->m_data = 0;
  2021. script.Execute("sc:MemberVoidFunc3(13,11,false)");
  2022. AZ_TEST_ASSERT(s_scriptClassInstance->m_data == 13);
  2023. s_scriptClassInstance->m_data = 0;
  2024. script.Execute("sc:MemberVoidFunc4(21,11,false,40)");
  2025. AZ_TEST_ASSERT(s_scriptClassInstance->m_data == 21);
  2026. s_scriptClassInstance->m_data = 0;
  2027. script.Execute("sc:MemberVoidFunc5(30,11,false,50,50.0)");
  2028. AZ_TEST_ASSERT(s_scriptClassInstance->m_data == 30);
  2029. // test number of arguments in a variadic function
  2030. s_globalVar = 0;
  2031. script.Execute("sc:VariadicFunc(30,11,false)");
  2032. AZ_TEST_ASSERT(s_globalVar == 3);
  2033. s_scriptClassInstance->m_data = 0;
  2034. s_globalVar = 1;
  2035. script.Execute("globalVar = sc.data");
  2036. AZ_TEST_ASSERT(s_globalVar == 0);
  2037. script.Execute("sc.data = 10");
  2038. script.Execute("globalVar = sc.data");
  2039. AZ_TEST_ASSERT(s_globalVar == 10);
  2040. s_globalVar1 = 3.0f;
  2041. script.Execute("globalVar1 = sc.data1");
  2042. AZ_TEST_ASSERT(s_globalVar1 == 0.0f);
  2043. script.Execute("sc.data1 = 11 ");
  2044. script.Execute("globalVar1 = sc.data1");
  2045. AZ_TEST_ASSERT(s_globalVar1 == 11.0f);
  2046. s_globalVar1 = 0.0f;
  2047. script.Execute("globalVar1 = sc.data2");
  2048. AZ_TEST_ASSERT(s_globalVar1 == 11.0f);
  2049. AZ_TEST_ASSERT(s_scriptClassInstance->m_data3WriteOnly == 0.0f);
  2050. script.Execute("sc.data3 = 101");
  2051. AZ_TEST_ASSERT(s_scriptClassInstance->m_data3WriteOnly == 101.0f);
  2052. s_globalVarString.clear();
  2053. script.Execute("globalVarString = tostring(sc)");
  2054. AZ_TEST_ASSERT(s_globalVarString.find("ScriptClass") != AZStd::string::npos);
  2055. AZ_TEST_ASSERT(s_globalVarString.find("LuaUserData") != AZStd::string::npos);
  2056. // release test
  2057. script.Execute("sc = nil");
  2058. script.GarbageCollect();
  2059. AZ_TEST_ASSERT(s_scriptClassInstance == nullptr);
  2060. //////////////////////////////////////////////////////////////////////////
  2061. AZ_TEST_ASSERT(scriptClass2Instances.size() == 0);
  2062. script.Execute("sc2 = ScriptClass2(10)");
  2063. AZ_TEST_ASSERT(scriptClass2Instances.size() == 1);
  2064. AZ_TEST_ASSERT(scriptClass2Instances[0]->m_data == 10);
  2065. script.Execute("sc21 = ScriptClass2(20)");
  2066. AZ_TEST_ASSERT(scriptClass2Instances.size() == 2);
  2067. AZ_TEST_ASSERT(scriptClass2Instances[1]->m_data == 20);
  2068. // addition
  2069. script.Execute("sc22 = sc2 + sc21");
  2070. AZ_TEST_ASSERT(scriptClass2Instances.size() == 3);
  2071. AZ_TEST_ASSERT(scriptClass2Instances[2]->m_data == 30);
  2072. script.Execute("sc22 = nil collectgarbage(\"collect\")");
  2073. AZ_TEST_ASSERT(scriptClass2Instances.size() == 2);
  2074. // sub
  2075. script.Execute("sc22 = sc2 - sc21");
  2076. AZ_TEST_ASSERT(scriptClass2Instances.size() == 3);
  2077. AZ_TEST_ASSERT(scriptClass2Instances[2]->m_data == -10);
  2078. script.Execute("sc22 = nil collectgarbage(\"collect\")");
  2079. AZ_TEST_ASSERT(scriptClass2Instances.size() == 2);
  2080. // mul
  2081. script.Execute("sc22 = sc2 * sc21");
  2082. AZ_TEST_ASSERT(scriptClass2Instances.size() == 3);
  2083. AZ_TEST_ASSERT(scriptClass2Instances[2]->m_data == 200);
  2084. script.Execute("sc22 = nil collectgarbage(\"collect\")");
  2085. AZ_TEST_ASSERT(scriptClass2Instances.size() == 2);
  2086. // div
  2087. script.Execute("sc22 = sc21 / sc2");
  2088. AZ_TEST_ASSERT(scriptClass2Instances.size() == 3);
  2089. AZ_TEST_ASSERT(scriptClass2Instances[2]->m_data == 2);
  2090. script.Execute("sc22 = nil collectgarbage(\"collect\")");
  2091. AZ_TEST_ASSERT(scriptClass2Instances.size() == 2);
  2092. // mod
  2093. script.Execute("sc21.data = 3 sc22 = sc2 % sc21 sc21.data = 20");
  2094. AZ_TEST_ASSERT(scriptClass2Instances.size() == 3);
  2095. AZ_TEST_ASSERT(scriptClass2Instances[2]->m_data == 1);
  2096. script.Execute("sc22 = nil collectgarbage(\"collect\")");
  2097. AZ_TEST_ASSERT(scriptClass2Instances.size() == 2);
  2098. // pow
  2099. script.Execute("sc21.data = 2 sc22 = sc2 ^ sc21 sc21.data = 20");
  2100. AZ_TEST_ASSERT(scriptClass2Instances.size() == 3);
  2101. AZ_TEST_ASSERT(scriptClass2Instances[2]->m_data == 100);
  2102. script.Execute("sc22 = nil collectgarbage(\"collect\")");
  2103. AZ_TEST_ASSERT(scriptClass2Instances.size() == 2);
  2104. // unary
  2105. script.Execute("sc22 = -sc2");
  2106. AZ_TEST_ASSERT(scriptClass2Instances.size() == 3);
  2107. AZ_TEST_ASSERT(scriptClass2Instances[2]->m_data == -10);
  2108. script.Execute("sc22 = nil collectgarbage(\"collect\")");
  2109. AZ_TEST_ASSERT(scriptClass2Instances.size() == 2);
  2110. // concat
  2111. script.Execute("sc22 = sc2 .. sc21");
  2112. AZ_TEST_ASSERT(scriptClass2Instances.size() == 3);
  2113. AZ_TEST_ASSERT(scriptClass2Instances[2]->m_data == 30);
  2114. script.Execute("sc22 = nil collectgarbage(\"collect\")");
  2115. AZ_TEST_ASSERT(scriptClass2Instances.size() == 2);
  2116. // compare
  2117. s_globalVarBool = true;
  2118. script.Execute("globalVarBool = (sc2 == sc21)");
  2119. AZ_TEST_ASSERT(!s_globalVarBool);
  2120. script.Execute("sc21.data = 10 globalVarBool = (sc2 == sc21) sc21.data = 20");
  2121. AZ_TEST_ASSERT(s_globalVarBool);
  2122. // compare less than
  2123. s_globalVarBool = false;
  2124. script.Execute("globalVarBool = (sc2 < sc21)");
  2125. AZ_TEST_ASSERT(s_globalVarBool);
  2126. script.Execute("globalVarBool = (sc21 < sc2)");
  2127. AZ_TEST_ASSERT(!s_globalVarBool);
  2128. // compare less than
  2129. s_globalVarBool = false;
  2130. script.Execute("globalVarBool = (sc2 <= sc21)");
  2131. AZ_TEST_ASSERT(s_globalVarBool);
  2132. script.Execute("globalVarBool = (sc21 <= sc2)");
  2133. AZ_TEST_ASSERT(!s_globalVarBool);
  2134. // len
  2135. s_globalVar = 0;
  2136. script.Execute("globalVar = #sc2");
  2137. AZ_TEST_ASSERT(s_globalVar == 10);
  2138. // len
  2139. s_globalVarString.clear();
  2140. script.Execute("globalVarString = tostring(sc2)");
  2141. AZ_TEST_ASSERT(s_globalVarString.compare("This is ScriptClass2") == 0);
  2142. // test pass object by pointer (when it's script owned) back to script
  2143. // we should make sure that we find the original instance
  2144. script.Execute("sc2F = sc2:Forward()");
  2145. // release test
  2146. script.Execute("sc2 = nil sc21 = nil");
  2147. script.GarbageCollect();
  2148. AZ_TEST_ASSERT(scriptClass2Instances.size() == 1);
  2149. script.Execute("sc2F = nil");
  2150. script.GarbageCollect();
  2151. AZ_TEST_ASSERT(scriptClass2Instances.size() == 0);
  2152. // test class with variadic constructor
  2153. AZ_TEST_ASSERT(s_scriptClass3Instance == nullptr);
  2154. script.Execute("sc3 = ScriptClass3(true,10,20.0,globalIncomplete)");
  2155. AZ_TEST_ASSERT(s_scriptClass3Instance != nullptr);
  2156. AZ_TEST_ASSERT(s_scriptClass3Instance->m_bool == true)
  2157. AZ_TEST_ASSERT(s_scriptClass3Instance->m_intData == 10)
  2158. AZ_TEST_ASSERT(s_scriptClass3Instance->m_floatData == 20.0f)
  2159. AZ_TEST_ASSERT(s_scriptClass3Instance->m_incompletePtr == s_globalIncompletePtr);
  2160. AZ_TEST_ASSERT(s_scriptClass3Instance->m_scriptClass2 == nullptr);
  2161. // we need to transfer the ownership of the object
  2162. script.Execute("sc3.scriptClass2 = ScriptClass2(333):ReleaseOwnership()");
  2163. AZ_TEST_ASSERT(s_scriptClass3Instance->m_scriptClass2 != nullptr);
  2164. AZ_TEST_ASSERT(s_scriptClass3Instance->m_scriptClass2->m_data == 333);
  2165. script.Execute("sc3.scriptClass2.data = 444");
  2166. AZ_TEST_ASSERT(s_scriptClass3Instance->m_scriptClass2->m_data == 444);
  2167. ScriptClass2* scriptClass2ToDelete = s_scriptClass3Instance->m_scriptClass2; // we Lua released the ownership
  2168. script.Execute("sc3.scriptClass2 = nil");
  2169. AZ_TEST_ASSERT(s_scriptClass3Instance->m_scriptClass2 == nullptr);
  2170. script.Execute("sc3 = nil collectgarbage(\"collect\")");
  2171. delete scriptClass2ToDelete;
  2172. AZ_TEST_ASSERT(s_scriptClass3Instance == nullptr);
  2173. // test a class with shared_ptr owner policy
  2174. AZ_TEST_ASSERT(scriptClass4numInstances == 0);
  2175. script.Execute("sc4 = shared_ptr_ScriptClass4(ScriptClass4(101))"); // create an instance and DON'T HOLD A SHARED PTR
  2176. AZ_TEST_ASSERT(scriptClass4numInstances == 1);
  2177. AZ_TEST_ASSERT(scriptClass4lockedInstances.empty());
  2178. script.Execute("sc41 = shared_ptr_ScriptClass4(ScriptClass4(201)) HoldScriptClass4(sc41)"); // create an instance and HOLD A SHARED PTR
  2179. AZ_TEST_ASSERT(scriptClass4numInstances == 2);
  2180. AZ_TEST_ASSERT(scriptClass4lockedInstances.size() == 1);
  2181. AZ_TEST_ASSERT(scriptClass4lockedInstances[0]->m_data == 201);
  2182. script.Execute("sc41:CopyData(sc4)");
  2183. AZ_TEST_ASSERT(scriptClass4lockedInstances[0]->m_data == 101);
  2184. script.Execute("sc4 = nil sc41 = nil collectgarbage(\"collect\")"); // this should release and delete sc4 but NOT sc41
  2185. AZ_TEST_ASSERT(scriptClass4numInstances == 1);
  2186. AZ_TEST_ASSERT(scriptClass4lockedInstances.size() == 1);
  2187. scriptClass4lockedInstances.clear();
  2188. AZ_TEST_ASSERT(scriptClass4numInstances == 0);
  2189. // test a class with intrusive_ptr owner policy
  2190. AZ_TEST_ASSERT(scriptClass5numInstances == 0);
  2191. script.Execute("sc5 = intrusive_ptr_ScriptClass5(ScriptClass5(101))"); // create an instance and DON'T HOLD A INTRUSIVE PTR (check constructor)
  2192. AZ_TEST_ASSERT(scriptClass5numInstances == 1);
  2193. AZ_TEST_ASSERT(scriptClass5lockedInstances.empty());
  2194. script.Execute("sc51 = intrusive_ptr_ScriptClass5(ScriptClass5(201)) HoldScriptClass5(sc51)"); // create an instance and HOLD A INTRUSIVE PTR (check constructor)
  2195. AZ_TEST_ASSERT(scriptClass5numInstances == 2);
  2196. AZ_TEST_ASSERT(scriptClass5lockedInstances.size() == 1);
  2197. AZ_TEST_ASSERT(scriptClass5lockedInstances[0]->m_data == 201);
  2198. script.Execute("sc51:CopyData(sc5)");
  2199. AZ_TEST_ASSERT(scriptClass5lockedInstances[0]->m_data == 101);
  2200. script.Execute("sc5 = nil sc51 = nil collectgarbage(\"collect\")"); // this should release and delete sc4 but NOT sc41
  2201. AZ_TEST_ASSERT(scriptClass5numInstances == 1);
  2202. AZ_TEST_ASSERT(scriptClass5lockedInstances.size() == 1);
  2203. scriptClass5lockedInstances.clear();
  2204. AZ_TEST_ASSERT(scriptClass5numInstances == 0);
  2205. // Check nested classes
  2206. // create valueHolder
  2207. script.Execute("valueHolder = ScriptValueHolder()");
  2208. // test reading user value data type
  2209. script.Execute("globalVar1 = valueHolder.value.data");
  2210. AZ_TEST_ASSERT(s_globalVar1 == 10.0f);
  2211. // test writing user value data type
  2212. script.Execute("valueHolder.value.data = 5");
  2213. script.Execute("globalVar1 = valueHolder.value.data");
  2214. AZ_TEST_ASSERT(s_globalVar1 == 5.0f);
  2215. // create user value type
  2216. script.Execute("userValueType = ScriptValueClass()");
  2217. // test reading user value data type
  2218. s_globalVar1 = 0.0f;
  2219. script.Execute("globalVar1 = userValueType.data");
  2220. AZ_TEST_ASSERT(s_globalVar1 == 10.0f);
  2221. // test assignment of value types
  2222. s_globalVar1 = 0.0f;
  2223. script.Execute("valueHolder.value = userValueType");
  2224. script.Execute("globalVar1 = valueHolder.value.data");
  2225. AZ_TEST_ASSERT(s_globalVar1 == 10.0f);
  2226. // make sure we copy the userValueType, not store a reference to it!
  2227. script.Execute("userValueType.data = 100");
  2228. script.Execute("globalVar1 = valueHolder.value.data");
  2229. AZ_TEST_ASSERT(s_globalVar1 == 10.0f);
  2230. // now store a reference and make sure it works
  2231. script.Execute("userValueTypeRef = valueHolder.value");
  2232. script.Execute("userValueTypeRef.data = 100");
  2233. script.Execute("globalVar1 = valueHolder.value.data");
  2234. AZ_TEST_ASSERT(s_globalVar1 == 100.0f);
  2235. script.Execute("valueHolder = nil userValueType = nil");
  2236. // test class pointer casting for unregistered classes
  2237. ScriptUnregisteredBaseClass ubc;
  2238. ScriptUnregisteredDerivedClass udc;
  2239. s_globalUnregBaseClass = &udc;
  2240. s_globalUnregDerivedClass = &udc;
  2241. s_globalVar = 0;
  2242. script.Execute("globalVar = GetUnregisteredScriptBaseData(globalUnregDerivedClass)"); // using downcast
  2243. AZ_TEST_ASSERT(s_globalVar == 10);
  2244. s_globalVar = 0;
  2245. script.Execute("globalVar = GetUnregisteredScriptBaseData(globalUnregBaseClass)");
  2246. AZ_TEST_ASSERT(s_globalVar == 10);
  2247. s_globalVar = 0;
  2248. script.Execute("globalVar = GetUnregisteredScriptDerivedData(globalUnregBaseClass)"); // using RTTI upcast
  2249. AZ_TEST_ASSERT(s_globalVar == 10);
  2250. // register a base and derived class test
  2251. // test that derived classes copy the base class properties
  2252. s_globalVar = 0;
  2253. script.Execute("derivedWithBase = ScriptRegisteredDerivedClass()");
  2254. script.Execute("globalVar = derivedWithBase.baseData"); // access base class data (RTTI is needed to be discovered and imported into top class metatable)
  2255. AZ_TEST_ASSERT(s_globalVar == 2);
  2256. // check that virtual functions work properly.
  2257. script.Execute("globalRegisteredBaseClass = derivedWithBase"); // this will cast ScriptRegisteredDerivedClass to ScriptRegisteredBaseClass
  2258. script.Execute("registeredBase = globalRegisteredBaseClass"); // this should cast back to the top known/registered class using AZRTTI.
  2259. script.Execute("globalVar = registeredBase:VirtualFunction()");
  2260. AZ_TEST_ASSERT(s_globalVar == 1);
  2261. script.Execute("globalVar = derivedWithBase:VirtualFunction()");
  2262. AZ_TEST_ASSERT(s_globalVar == 1);
  2263. script.Execute("globalRegisteredBaseClass = nil registeredBase = nil derivedWithBase = nil");
  2264. // abstract classes
  2265. s_globalVar = 0;
  2266. script.Execute("abstract = AbstractImplementation()");
  2267. script.Execute("globalVar = abstract:PureCall()");
  2268. AZ_TEST_ASSERT(s_globalVar == 5);
  2269. script.Execute("abstract = nil");
  2270. s_globalVarString.set_capacity(0); // free all memory
  2271. }
  2272. TEST_F(ScriptBindTest, LuaTest)
  2273. {
  2274. run();
  2275. }
  2276. class ScriptContextTest
  2277. : public LeakDetectionFixture
  2278. {
  2279. public:
  2280. void run()
  2281. {
  2282. ScriptContext script;
  2283. const char code[] = "\
  2284. GlobalValueA = 6\
  2285. GlobalValueB = 12.4\
  2286. GlobalValueC = \"GlobalTest\"\
  2287. GlobalTable = {\
  2288. valueA = 5,\
  2289. valueB = 11.3,\
  2290. valueC = \"TableTest\",\
  2291. SubTable = {\
  2292. valueA = 6,\
  2293. valueB = 12.4,\
  2294. SubTable = {\
  2295. valueA = 7,\
  2296. },\
  2297. },\
  2298. }\
  2299. function GlobalTable.TableFunction (a)\
  2300. return a\
  2301. end\
  2302. function GlobalFunction ()\
  2303. return 25\
  2304. end\
  2305. function GlobalSquare (a)\
  2306. return a,a*a\
  2307. end\
  2308. function GlobalFast (a)\
  2309. return a*2\
  2310. end\
  2311. GlobalTableWithMeta = {}\
  2312. setmetatable(GlobalTableWithMeta,GlobalTable)\
  2313. ";
  2314. script.Execute(code);
  2315. ScriptDataContext dc;
  2316. bool status;
  2317. int intResult = 0;
  2318. float floatResult = 0.f;
  2319. const char* stringResult = nullptr;
  2320. // inspect test
  2321. // global int
  2322. status = script.FindGlobal("GlobalValueA", dc);
  2323. AZ_TEST_ASSERT(status);
  2324. AZ_TEST_ASSERT(dc.IsNumber(0));
  2325. status = dc.ReadValue(0, intResult);
  2326. AZ_TEST_ASSERT(status);
  2327. AZ_TEST_ASSERT(intResult == 6);
  2328. // global float
  2329. status = script.FindGlobal("GlobalValueB", dc);
  2330. AZ_TEST_ASSERT(status);
  2331. AZ_TEST_ASSERT(dc.IsNumber(0));
  2332. status = dc.ReadValue(0, floatResult);
  2333. AZ_TEST_ASSERT(status);
  2334. AZ_TEST_ASSERT_FLOAT_CLOSE(floatResult, 12.4f);
  2335. // string value
  2336. status = script.FindGlobal("GlobalValueC", dc);
  2337. AZ_TEST_ASSERT(status);
  2338. AZ_TEST_ASSERT(dc.IsString(0));
  2339. status = dc.ReadValue(0, stringResult);
  2340. AZ_TEST_ASSERT(status);
  2341. AZ_TEST_ASSERT(strcmp(stringResult, "GlobalTest") == 0);
  2342. // table value
  2343. status = script.FindGlobal("GlobalTable", dc);
  2344. AZ_TEST_ASSERT(status);
  2345. AZ_TEST_ASSERT(dc.IsTable(0));
  2346. AZ_TEST_ASSERT(dc.CheckTableElement(0, "valueA"));
  2347. status = dc.ReadTableElement(0, "valueA", intResult);
  2348. AZ_TEST_ASSERT(status);
  2349. AZ_TEST_ASSERT(intResult == 5);
  2350. AZ_TEST_ASSERT(dc.CheckTableElement(0, "valueB"));
  2351. status = dc.ReadTableElement(0, "valueB", floatResult);
  2352. AZ_TEST_ASSERT(status);
  2353. AZ_TEST_ASSERT_FLOAT_CLOSE(floatResult, 11.3f);
  2354. AZ_TEST_ASSERT(dc.CheckTableElement(0, "valueC"));
  2355. status = dc.ReadTableElement(0, "valueC", stringResult);
  2356. AZ_TEST_ASSERT(status);
  2357. AZ_TEST_ASSERT(strcmp(stringResult, "TableTest") == 0);
  2358. // inspect table
  2359. {
  2360. ScriptDataContext dcTable;
  2361. dc.InspectTable(0, dcTable);
  2362. const char* fieldName;
  2363. int fieldIndex;
  2364. int valueIndex;
  2365. while (dcTable.InspectNextElement(valueIndex, fieldName, fieldIndex))
  2366. {
  2367. AZ_TEST_ASSERT(fieldIndex == -1); // we don't have indexed elements
  2368. if (strcmp(fieldName, "valueA") == 0)
  2369. {
  2370. AZ_TEST_ASSERT(dcTable.IsNumber(valueIndex));
  2371. int intValue = 0;
  2372. dcTable.ReadValue(valueIndex, intValue);
  2373. AZ_TEST_ASSERT(intValue == 5);
  2374. }
  2375. else if (strcmp(fieldName, "valueB") == 0)
  2376. {
  2377. AZ_TEST_ASSERT(dcTable.IsNumber(valueIndex));
  2378. float floatValue = 0.f;
  2379. dcTable.ReadValue(valueIndex, floatValue);
  2380. AZ_TEST_ASSERT(fabsf(floatValue - 11.3f) < 0.001f);
  2381. }
  2382. else if (strcmp(fieldName, "valueC") == 0)
  2383. {
  2384. AZ_TEST_ASSERT(dcTable.IsString(valueIndex));
  2385. const char* stringValue;
  2386. dcTable.ReadValue(valueIndex, stringValue);
  2387. AZ_TEST_ASSERT(strcmp(stringResult, "TableTest") == 0);
  2388. }
  2389. else if (strcmp(fieldName, "SubTable") == 0)
  2390. {
  2391. AZ_TEST_ASSERT(dcTable.IsTable(valueIndex));
  2392. ScriptDataContext subTable;
  2393. dcTable.InspectTable(valueIndex, subTable);
  2394. while (subTable.InspectNextElement(valueIndex, fieldName, fieldIndex))
  2395. {
  2396. AZ_TEST_ASSERT(fieldIndex == -1); // we don't have indexed elements
  2397. if (strcmp(fieldName, "valueA") == 0)
  2398. {
  2399. AZ_TEST_ASSERT(subTable.IsNumber(valueIndex));
  2400. int intValue = 0;
  2401. subTable.ReadValue(valueIndex, intValue);
  2402. AZ_TEST_ASSERT(intValue == 6);
  2403. }
  2404. else if (strcmp(fieldName, "valueB") == 0)
  2405. {
  2406. AZ_TEST_ASSERT(subTable.IsNumber(valueIndex));
  2407. float floatValue = 0.f;
  2408. subTable.ReadValue(valueIndex, floatValue);
  2409. AZ_TEST_ASSERT(fabsf(floatValue - 12.4f) < 0.001f);
  2410. }
  2411. else if (strcmp(fieldName, "SubTable") == 0)
  2412. {
  2413. ScriptDataContext subTable1;
  2414. subTable.InspectTable(valueIndex, subTable1);
  2415. while (subTable1.InspectNextElement(valueIndex, fieldName, fieldIndex))
  2416. {
  2417. AZ_TEST_ASSERT(fieldIndex == -1); // we don't have indexed elements
  2418. if (strcmp(fieldName, "valueA") == 0)
  2419. {
  2420. AZ_TEST_ASSERT(subTable1.IsNumber(valueIndex));
  2421. int intValue = 0;
  2422. subTable1.ReadValue(valueIndex, intValue);
  2423. AZ_TEST_ASSERT(intValue == 7);
  2424. }
  2425. }
  2426. }
  2427. }
  2428. }
  2429. else if (strcmp(fieldName, "TableFunction") == 0)
  2430. {
  2431. AZ_TEST_ASSERT(dcTable.IsFunction(valueIndex));
  2432. ScriptDataContext callContext;
  2433. dcTable.Call(valueIndex, callContext);
  2434. callContext.PushArg(11);
  2435. callContext.CallExecute();
  2436. AZ_TEST_ASSERT(callContext.GetNumResults() == 1);
  2437. int intValue = 0;
  2438. callContext.ReadResult(0, intValue);
  2439. AZ_TEST_ASSERT(intValue == 11);
  2440. }
  2441. else
  2442. {
  2443. AZ_TEST_ASSERT(false);
  2444. }
  2445. }
  2446. }
  2447. // table replace
  2448. dc.AddReplaceTableElement(0, "valueA", 4);
  2449. status = dc.ReadTableElement(0, "valueA", intResult);
  2450. AZ_TEST_ASSERT(status);
  2451. AZ_TEST_ASSERT(intResult == 4);
  2452. // table add
  2453. AZ_TEST_ASSERT(dc.CheckTableElement(0, "valueD") == false);
  2454. dc.AddReplaceTableElement(0, "valueD", 11);
  2455. AZ_TEST_ASSERT(dc.CheckTableElement(0, "valueD"));
  2456. dc.ReadTableElement(0, "valueD", intResult);
  2457. AZ_TEST_ASSERT(intResult == 11);
  2458. // global function call (no arguments 1 result)
  2459. status = script.FindGlobal("GlobalFunction", dc);
  2460. AZ_TEST_ASSERT(status);
  2461. {
  2462. ScriptDataContext callContext;
  2463. status = dc.Call(0, callContext);
  2464. AZ_TEST_ASSERT(status);
  2465. status = callContext.CallExecute();
  2466. AZ_TEST_ASSERT(status);
  2467. AZ_TEST_ASSERT(callContext.GetNumResults() == 1);
  2468. AZ_TEST_ASSERT(callContext.IsNumber(0));
  2469. callContext.ReadResult(0, intResult);
  2470. AZ_TEST_ASSERT(intResult == 25);
  2471. }
  2472. // global function call (1 argument 2 results)
  2473. {
  2474. ScriptDataContext callContext;
  2475. status = script.FindGlobal("GlobalSquare", dc);
  2476. AZ_TEST_ASSERT(status);
  2477. status = dc.Call(0, callContext);
  2478. AZ_TEST_ASSERT(status);
  2479. AZ_TEST_ASSERT(callContext.GetNumArguments() == 0);
  2480. callContext.PushArg(3);
  2481. AZ_TEST_ASSERT(callContext.GetNumArguments() == 1);
  2482. status = callContext.CallExecute();
  2483. AZ_TEST_ASSERT(status);
  2484. AZ_TEST_ASSERT(callContext.GetNumResults() == 2);
  2485. AZ_TEST_ASSERT(callContext.IsNumber(0));
  2486. AZ_TEST_ASSERT(callContext.IsNumber(1));
  2487. int intResult2 = 0;
  2488. callContext.ReadResult(0, intResult);
  2489. callContext.ReadResult(1, intResult2);
  2490. AZ_TEST_ASSERT(intResult == 3);
  2491. AZ_TEST_ASSERT(intResult2 == 9);
  2492. }
  2493. // global cached function call
  2494. int cachedIndex = script.CacheGlobal("GlobalFast");
  2495. AZ_TEST_ASSERT(cachedIndex != -1);
  2496. int value = 2;
  2497. for (int i = 0; i < 6; ++i)
  2498. {
  2499. ScriptDataContext callContext;
  2500. status = script.FindGlobal(cachedIndex, dc);
  2501. AZ_TEST_ASSERT(status);
  2502. status = dc.Call(0, callContext);
  2503. AZ_TEST_ASSERT(status);
  2504. callContext.PushArg(value);
  2505. status = callContext.CallExecute();
  2506. AZ_TEST_ASSERT(status);
  2507. AZ_TEST_ASSERT(callContext.GetNumResults() == 1);
  2508. AZ_TEST_ASSERT(callContext.IsNumber(0));
  2509. callContext.ReadResult(0, value);
  2510. }
  2511. AZ_TEST_ASSERT(value == 128);
  2512. script.ReleaseCached(cachedIndex);
  2513. // metatable inspect
  2514. status = script.FindGlobal("GlobalTableWithMeta", dc);
  2515. AZ_TEST_ASSERT(status);
  2516. AZ_TEST_ASSERT(dc.IsTable(0));
  2517. {
  2518. ScriptDataContext dcTable;
  2519. dc.InspectTable(0, dcTable);
  2520. const char* fieldName;
  2521. int fieldIndex;
  2522. int valueIndex;
  2523. while (dcTable.InspectNextElement(valueIndex, fieldName, fieldIndex))
  2524. {
  2525. AZ_TEST_ASSERT(false); // this table doesn't have any elements
  2526. }
  2527. status = dc.InspectMetaTable(0, dcTable);
  2528. AZ_TEST_ASSERT(status);
  2529. while (dcTable.InspectNextElement(valueIndex, fieldName, fieldIndex))
  2530. {
  2531. if (strcmp(fieldName, "valueA") == 0)
  2532. {
  2533. AZ_TEST_ASSERT(dcTable.IsNumber(valueIndex));
  2534. int intValue = 0;
  2535. dcTable.ReadValue(valueIndex, intValue);
  2536. AZ_TEST_ASSERT(intValue == 4);
  2537. }
  2538. else if (strcmp(fieldName, "valueB") == 0)
  2539. {
  2540. AZ_TEST_ASSERT(dcTable.IsNumber(valueIndex));
  2541. float floatValue = 0.f;
  2542. dcTable.ReadValue(valueIndex, floatValue);
  2543. AZ_TEST_ASSERT(fabsf(floatValue - 11.3f) < 0.001f);
  2544. }
  2545. else if (strcmp(fieldName, "valueC") == 0)
  2546. {
  2547. AZ_TEST_ASSERT(dcTable.IsString(valueIndex));
  2548. const char* stringValue;
  2549. dcTable.ReadValue(valueIndex, stringValue);
  2550. AZ_TEST_ASSERT(strcmp(stringResult, "TableTest") == 0);
  2551. }
  2552. else if (strcmp(fieldName, "valueD") == 0)
  2553. {
  2554. AZ_TEST_ASSERT(dcTable.IsNumber(valueIndex));
  2555. int intValue = 0;
  2556. dcTable.ReadValue(valueIndex, intValue);
  2557. AZ_TEST_ASSERT(intValue == 11);
  2558. }
  2559. else if (strcmp(fieldName, "SubTable") == 0)
  2560. {
  2561. AZ_TEST_ASSERT(dcTable.IsTable(valueIndex));
  2562. ScriptDataContext subTable;
  2563. dcTable.InspectTable(valueIndex, subTable);
  2564. while (subTable.InspectNextElement(valueIndex, fieldName, fieldIndex))
  2565. {
  2566. AZ_TEST_ASSERT(fieldIndex == -1); // we don't have indexed elements
  2567. if (strcmp(fieldName, "valueA") == 0)
  2568. {
  2569. AZ_TEST_ASSERT(subTable.IsNumber(valueIndex));
  2570. int intValue = 0;
  2571. subTable.ReadValue(valueIndex, intValue);
  2572. AZ_TEST_ASSERT(intValue == 6);
  2573. }
  2574. else if (strcmp(fieldName, "valueB") == 0)
  2575. {
  2576. AZ_TEST_ASSERT(subTable.IsNumber(valueIndex));
  2577. float floatValue = 0.f;
  2578. subTable.ReadValue(valueIndex, floatValue);
  2579. AZ_TEST_ASSERT(fabsf(floatValue - 12.4f) < 0.001f);
  2580. }
  2581. else if (strcmp(fieldName, "SubTable") == 0)
  2582. {
  2583. ScriptDataContext subTable1;
  2584. subTable.InspectTable(valueIndex, subTable1);
  2585. while (subTable1.InspectNextElement(valueIndex, fieldName, fieldIndex))
  2586. {
  2587. AZ_TEST_ASSERT(fieldIndex == -1); // we don't have indexed elements
  2588. if (strcmp(fieldName, "valueA") == 0)
  2589. {
  2590. AZ_TEST_ASSERT(subTable1.IsNumber(valueIndex));
  2591. int intValue = 0;
  2592. subTable1.ReadValue(valueIndex, intValue);
  2593. AZ_TEST_ASSERT(intValue == 7);
  2594. }
  2595. }
  2596. }
  2597. }
  2598. }
  2599. else if (strcmp(fieldName, "TableFunction") == 0)
  2600. {
  2601. AZ_TEST_ASSERT(dcTable.IsFunction(valueIndex));
  2602. ScriptDataContext callContext;
  2603. dcTable.Call(valueIndex, callContext);
  2604. callContext.PushArg(11);
  2605. callContext.CallExecute();
  2606. AZ_TEST_ASSERT(callContext.GetNumResults() == 1);
  2607. int intValue = 0;
  2608. callContext.ReadResult(0, intValue);
  2609. AZ_TEST_ASSERT(intValue == 11);
  2610. }
  2611. else
  2612. {
  2613. AZ_TEST_ASSERT(false);
  2614. }
  2615. }
  2616. }
  2617. // script loaders
  2618. // from load function
  2619. // from data buffer
  2620. // from string
  2621. }
  2622. };
  2623. TEST_F(ScriptContextTest, LuaTest)
  2624. {
  2625. run();
  2626. }
  2627. class ScriptDebugTest
  2628. : public LeakDetectionFixture
  2629. {
  2630. int m_numBreakpointHits;
  2631. static ScriptContext* s_currentSC;
  2632. public:
  2633. ScriptDebugTest()
  2634. : m_numBreakpointHits(0) {}
  2635. bool EnumLocal(const char* name, ScriptDataContext& dataContext)
  2636. {
  2637. AZ_TEST_ASSERT(strcmp(name, "a") == 0 || strcmp(name, "result") == 0);
  2638. //AZ_Printf("Script","Local variable %s = ",name);
  2639. if (dataContext.IsNumber(0))
  2640. {
  2641. double number = 0.;
  2642. dataContext.ReadValue(0, number);
  2643. //AZ_Printf("Script","%f [number]\n",number);
  2644. AZ_TEST_ASSERT(number == 10.0);
  2645. }
  2646. return true;
  2647. }
  2648. void BreakpointCallback(ScriptContextDebug* debugContext, const ScriptContextDebug::Breakpoint* breakpoint)
  2649. {
  2650. //AZ_Printf("Script","\nBreakpoint at '%s(%d)' triggered!",breakpoint->m_sourceName,breakpoint->m_lineNumber);
  2651. AZ_TEST_ASSERT(breakpoint->m_sourceName == "DebugCode");
  2652. if (m_numBreakpointHits == 0)
  2653. {
  2654. AZ_TEST_ASSERT(breakpoint->m_lineNumber == 23);
  2655. ScriptContextDebug::EnumLocalCallback enumCB = AZStd::bind(&ScriptDebugTest::EnumLocal, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
  2656. debugContext->EnumLocals(enumCB);
  2657. debugContext->StepInto(); // go inside the script to line 20
  2658. }
  2659. else if (m_numBreakpointHits == 1)
  2660. {
  2661. char stackOutput[2048];
  2662. debugContext->StackTrace(stackOutput, AZ_ARRAY_SIZE(stackOutput));
  2663. AZ_Printf("Script", "%s", stackOutput);
  2664. AZ_TEST_ASSERT(strstr(stackOutput, "GlobalFunction") != nullptr);
  2665. AZ_TEST_ASSERT(breakpoint->m_lineNumber == 20);
  2666. }
  2667. else if (m_numBreakpointHits == 2)
  2668. {
  2669. AZ_TEST_ASSERT(breakpoint->m_lineNumber == 23);
  2670. // check A a local variable
  2671. ScriptContextDebug::DebugValue value;
  2672. value.m_name = "a";
  2673. bool valueResult = debugContext->GetValue(value);
  2674. AZ_TEST_ASSERT(valueResult);
  2675. AZ_TEST_ASSERT(value.m_type == LUA_TNUMBER);
  2676. AZ_TEST_ASSERT(value.m_value.find("11.0") != OSString::npos);
  2677. value.m_value = "3.0"; // modify the value
  2678. debugContext->SetValue(value);
  2679. debugContext->StepOver(); // same place as before, but now step over to line 24
  2680. }
  2681. else if (m_numBreakpointHits == 3)
  2682. {
  2683. AZ_TEST_ASSERT(breakpoint->m_lineNumber == 24);
  2684. }
  2685. else if (m_numBreakpointHits == 4)
  2686. {
  2687. AZ_TEST_ASSERT(breakpoint->m_lineNumber == 23);
  2688. debugContext->StepOut(); // same place as before, but now step out to line 28
  2689. }
  2690. else if (m_numBreakpointHits == 5)
  2691. {
  2692. AZ_TEST_ASSERT(breakpoint->m_lineNumber == 28);
  2693. }
  2694. else if (m_numBreakpointHits == 6)
  2695. {
  2696. // called from C->script->C->script scenario
  2697. char stackOutput[2048];
  2698. debugContext->StackTrace(stackOutput, AZ_ARRAY_SIZE(stackOutput));
  2699. AZ_Printf("Script", "%s", stackOutput);
  2700. AZ_TEST_ASSERT(strstr(stackOutput, "GlobalMult") != nullptr);
  2701. AZ_TEST_ASSERT(breakpoint->m_lineNumber == 23);
  2702. }
  2703. ++m_numBreakpointHits;
  2704. }
  2705. static int CallCFuncOperation(int value)
  2706. {
  2707. int result = 0;
  2708. // call a script function
  2709. if (s_currentSC)
  2710. {
  2711. ScriptDataContext call;
  2712. if (s_currentSC->Call("GlobalFast", call))
  2713. {
  2714. call.PushArg(value);
  2715. if (call.CallExecute())
  2716. {
  2717. if (call.GetNumResults())
  2718. {
  2719. call.ReadResult(0, result);
  2720. }
  2721. }
  2722. }
  2723. }
  2724. return result;
  2725. }
  2726. void run()
  2727. {
  2728. BehaviorContext behaviorContext;
  2729. behaviorContext.Class<ScriptClass>()->
  2730. Allocator(&ScriptClassAllocate, &ScriptClassFree)->
  2731. Enum<ScriptClass::SC_ET_VALUE2>("SC_ET_VALUE2")->
  2732. Enum<ScriptClass::SC_ET_VALUE3>("SC_ET_VALUE3")->
  2733. Constant("EPSILON", BehaviorConstant(0.001f))->
  2734. Method("MemberFunc0", &ScriptClass::MemberFunc0)->
  2735. Method("MemberFunc1", &ScriptClass::MemberFunc1)->
  2736. Method("MemberFunc2", &ScriptClass::MemberFunc2)->
  2737. Method("MemberFunc3", &ScriptClass::MemberFunc3)->
  2738. Method("MemberFunc4", &ScriptClass::MemberFunc4)->
  2739. Method("MemberFunc5", &ScriptClass::MemberFunc5)->
  2740. Method("MemberVoidFunc0", &ScriptClass::MemberVoidFunc0)->
  2741. Method("MemberVoidFunc1", &ScriptClass::MemberVoidFunc1)->
  2742. Method("MemberVoidFunc2", &ScriptClass::MemberVoidFunc2)->
  2743. Method("MemberVoidFunc3", &ScriptClass::MemberVoidFunc3)->
  2744. Method("MemberVoidFunc4", &ScriptClass::MemberVoidFunc4)->
  2745. Method("MemberVoidFunc5", &ScriptClass::MemberVoidFunc5)->
  2746. Method("VariadicFunc", &ScriptClass::VariadicFunc)->
  2747. Property("data", &ScriptClass::GetData, &ScriptClass::SetData)->
  2748. Property("data1", BehaviorValueProperty(&ScriptClass::m_data1))->
  2749. Property("data2", BehaviorValueGetter(&ScriptClass::m_data2ReadOnly), nullptr)->
  2750. Property("data3", nullptr, BehaviorValueSetter(&ScriptClass::m_data3WriteOnly));
  2751. behaviorContext.Property("globalField", BehaviorValueProperty(&s_globalField));
  2752. behaviorContext.Method("CallCFuncOperation", &CallCFuncOperation);
  2753. behaviorContext.Class<ScriptValueClass>()->
  2754. Property("data", BehaviorValueProperty(&ScriptValueClass::m_data));
  2755. behaviorContext.Class<ScriptValueHolder>()->
  2756. Property("value", BehaviorValueProperty(&ScriptValueHolder::m_value));
  2757. ScriptContext script;
  2758. script.BindTo(&behaviorContext);
  2759. const char code[] = "GlobalValueA = 6\n\
  2760. GlobalValueB = 12.4\n\
  2761. GlobalValueC = \"GlobalTest\"\n\
  2762. GlobalTable = {\n\
  2763. valueA = 5,\n\
  2764. valueB = 11.3,\n\
  2765. valueC = \"TableTest\",\n\
  2766. SubTable = {\n\
  2767. valueA = 6,\n\
  2768. valueB = 12.4,\n\
  2769. SubTable = {\n\
  2770. valueA = 7,\n\
  2771. },\n\
  2772. },\n\
  2773. }\n\
  2774. function GlobalTable.TableFunction (a)\n\
  2775. return a\n\
  2776. end\n\
  2777. function GlobalFunction ()\n\
  2778. return 25\n\
  2779. end\n\
  2780. function GlobalMult (a)\n\
  2781. local result = a*GlobalFunction()\n\
  2782. return result\n\
  2783. end\n\
  2784. function GlobalFast (a)\n\
  2785. local result = GlobalMult(a)*2\n\
  2786. return result\n\
  2787. end\n\
  2788. Result=GlobalFast(10)\n\
  2789. Result=GlobalFast(11)\n\
  2790. Result=GlobalFast(12)\n\
  2791. GlobalValueB=Result*2\n\
  2792. GlobalTableDerived={}\n\
  2793. setmetatable(GlobalTableDerived,GlobalTable)";
  2794. const char code2[] = "function CallACFunction(a)\n\
  2795. return CallCFuncOperation(a)\n\
  2796. end\n\
  2797. Result = CallACFunction(10)";
  2798. // enable script debug
  2799. script.EnableDebug();
  2800. // get debug context
  2801. ScriptContextDebug* debugContext = script.GetDebugContext();
  2802. if (debugContext == nullptr)
  2803. {
  2804. return; // don't test when not supported.
  2805. }
  2806. // add a breakpoint code line 23 (return a*a)
  2807. ScriptContextDebug::Breakpoint bp;
  2808. bp.m_sourceName = "DebugCode";
  2809. bp.m_lineNumber = 23;
  2810. debugContext->AddBreakpoint(bp);
  2811. // enable breakpoints
  2812. ScriptContextDebug::BreakpointCallback breakpointCallback = AZStd::bind(&ScriptDebugTest::BreakpointCallback, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
  2813. debugContext->EnableBreakpoints(breakpointCallback);
  2814. // enabled 'advanced' stack tracing
  2815. debugContext->EnableStackRecord();
  2816. // execute the code (that will trigger a breakpoint)
  2817. script.Execute(code, "DebugCode");
  2818. // now check debug break with script1->C Code->script2
  2819. s_currentSC = &script;
  2820. script.Execute(code2, "DebugCode2");
  2821. s_currentSC = nullptr;
  2822. // disable breakpoints (not this doesn't delete them, just disables them)
  2823. debugContext->DisableBreakpoints();
  2824. // test get value from globals, tables, function, and user class
  2825. ScriptContextDebug::DebugValue values[9];
  2826. bool getValueResult;
  2827. // make sure we detect non existing variables
  2828. values[0].m_name = "InvalidVariable";
  2829. getValueResult = debugContext->GetValue(values[0]);
  2830. AZ_TEST_ASSERT(getValueResult == false);
  2831. // get global number
  2832. values[0].m_name = "GlobalValueA";
  2833. getValueResult = debugContext->GetValue(values[0]);
  2834. AZ_TEST_ASSERT(getValueResult);
  2835. AZ_TEST_ASSERT(values[0].m_type == LUA_TNUMBER);
  2836. AZ_TEST_ASSERT(values[0].m_value.find("6.0") != OSString::npos);
  2837. // get global string
  2838. values[1].m_name = "GlobalValueC";
  2839. getValueResult = debugContext->GetValue(values[1]);
  2840. AZ_TEST_ASSERT(getValueResult);
  2841. AZ_TEST_ASSERT(values[1].m_type == LUA_TSTRING);
  2842. AZ_TEST_ASSERT(values[1].m_value == "GlobalTest");
  2843. // get global table
  2844. values[2].m_name = "GlobalTable";
  2845. getValueResult = debugContext->GetValue(values[2]);
  2846. AZ_TEST_ASSERT(getValueResult);
  2847. AZ_TEST_ASSERT(values[2].m_type == LUA_TTABLE);
  2848. AZ_TEST_ASSERT(values[2].m_elements.size() == 5); // valueA,valueB,valueC,SubTable and TableFunction
  2849. // get global table with a metatable
  2850. values[3].m_name = "GlobalTableDerived";
  2851. getValueResult = debugContext->GetValue(values[3]);
  2852. AZ_TEST_ASSERT(getValueResult);
  2853. AZ_TEST_ASSERT(values[3].m_type == LUA_TTABLE);
  2854. AZ_TEST_ASSERT(values[3].m_elements.size() == 1); // valueA,valueB,valueC,SubTable and TableFunction
  2855. AZ_TEST_ASSERT(values[3].m_elements[0].m_elements.size() == 5); // valueA,valueB,valueC,SubTable and TableFunction
  2856. // get global function
  2857. values[4].m_name = "GlobalFunction";
  2858. getValueResult = debugContext->GetValue(values[4]);
  2859. AZ_TEST_ASSERT(getValueResult);
  2860. AZ_TEST_ASSERT(values[4].m_type == LUA_TFUNCTION);
  2861. // get global user class
  2862. script.Execute("sc = ScriptClass()"); // create a C++ class
  2863. values[5].m_name = "sc";
  2864. getValueResult = debugContext->GetValue(values[5]);
  2865. AZ_TEST_ASSERT(getValueResult);
  2866. AZ_TEST_ASSERT(values[5].m_type == LUA_TUSERDATA);
  2867. // check nested user classes
  2868. script.Execute("sv = ScriptValueHolder()");
  2869. values[6].m_name = "sv";
  2870. getValueResult = debugContext->GetValue(values[6]);
  2871. AZ_TEST_ASSERT(getValueResult);
  2872. // get global property/field
  2873. s_globalField = 23;
  2874. values[7].m_name = "globalField";
  2875. getValueResult = debugContext->GetValue(values[7]);
  2876. AZ_TEST_ASSERT(getValueResult);
  2877. AZ_TEST_ASSERT(values[7].m_value.find("23") != OSString::npos);
  2878. // make sure we can get the global table safely (if we want to support cyclic tables)
  2879. values[8].m_name = "_G";
  2880. getValueResult = debugContext->GetValue(values[8]);
  2881. AZ_TEST_ASSERT(getValueResult == true);
  2882. ScriptContextDebug::DebugValue valueCheck;
  2883. // set a global number and change it's type to a string
  2884. values[0].m_value = "BlaBla";
  2885. values[0].m_type = LUA_TSTRING;
  2886. debugContext->SetValue(values[0]);
  2887. // check the SetValue
  2888. valueCheck.m_name = values[0].m_name;
  2889. debugContext->GetValue(valueCheck);
  2890. AZ_TEST_ASSERT(valueCheck.m_type == LUA_TSTRING);
  2891. AZ_TEST_ASSERT(valueCheck.m_value == "BlaBla");
  2892. // set a global string
  2893. values[1].m_value = "BlaBla1";
  2894. debugContext->SetValue(values[1]);
  2895. // check the set value
  2896. valueCheck.m_name = values[1].m_name;
  2897. debugContext->GetValue(valueCheck);
  2898. AZ_TEST_ASSERT(valueCheck.m_value == "BlaBla1");
  2899. // set a table value
  2900. values[2].m_elements[0].m_value = "Aha";
  2901. values[2].m_elements[0].m_type = LUA_TSTRING;
  2902. debugContext->SetValue(values[2]);
  2903. // check
  2904. valueCheck.m_name = values[2].m_name;
  2905. debugContext->GetValue(valueCheck);
  2906. AZ_TEST_ASSERT(values[2].m_elements.size() == valueCheck.m_elements.size());
  2907. // set a table value with metatable
  2908. ScriptContextDebug::DebugValue& subValue = values[3].m_elements.emplace_back();
  2909. subValue.m_name = "valueA";
  2910. subValue.m_type = LUA_TNUMBER;
  2911. subValue.m_value = "16";
  2912. debugContext->SetValue(values[3]);
  2913. // check
  2914. valueCheck.m_name = values[3].m_name;
  2915. debugContext->GetValue(valueCheck);
  2916. AZ_TEST_ASSERT(values[3].m_elements.size() == valueCheck.m_elements.size());
  2917. int data1Element = -1;
  2918. for (size_t i = 0; i < values[5].m_elements.size(); ++i)
  2919. {
  2920. if (values[5].m_elements[i].m_name == "data1")
  2921. {
  2922. data1Element = static_cast<int>(i);
  2923. }
  2924. }
  2925. AZ_TEST_ASSERT(data1Element != -1); // make sure we have data 1 element
  2926. // user class
  2927. AZ_TEST_ASSERT(values[5].m_elements[data1Element].m_name == "data1"); // make sure we are modifying the correct element
  2928. values[5].m_elements[data1Element].m_value = "6.0";
  2929. debugContext->SetValue(values[5]);
  2930. // check
  2931. valueCheck.m_name = values[5].m_name;
  2932. debugContext->GetValue(valueCheck);
  2933. AZ_TEST_ASSERT(values[5].m_elements.size() == valueCheck.m_elements.size());
  2934. AZ_TEST_ASSERT(valueCheck.m_elements[data1Element].m_value.find("6.0") != OSString::npos);
  2935. // user nested class
  2936. values[6].m_elements[0].m_elements[0].m_value = "3.0";
  2937. debugContext->SetValue(values[6]);
  2938. // check
  2939. valueCheck.m_name = values[6].m_name;
  2940. debugContext->GetValue(valueCheck);
  2941. AZ_TEST_ASSERT(valueCheck.m_elements[0].m_elements[0].m_value.find("3.0") != OSString::npos);
  2942. // global table
  2943. // modify todo
  2944. debugContext->SetValue(values[8]);
  2945. // check (TODO)
  2946. // disable debug support (this will delete all breakpoints and everything debug related!)
  2947. script.DisableDebug();
  2948. }
  2949. };
  2950. ScriptContext* ScriptDebugTest::s_currentSC = nullptr;
  2951. // TEST_F(ScriptDebugTest, LuaTest)
  2952. // {
  2953. // run();
  2954. // }
  2955. //-----------------------------------------------------------------------------
  2956. // Ebus script test
  2957. //-----------------------------------------------------------------------------
  2958. void TestAssert(bool check)
  2959. {
  2960. (void)check;
  2961. AZ_Assert(!check, "Script Test assert");
  2962. }
  2963. class TestBusMessages
  2964. : public AZ::EBusTraits
  2965. {
  2966. public:
  2967. virtual ~TestBusMessages() {}
  2968. virtual void Set() = 0;
  2969. virtual void SetNotImplemented() = 0;
  2970. virtual void SetSum1(int) = 0;
  2971. virtual void SetSum2(int, int) = 0;
  2972. virtual void SetSum3(int, int, int) = 0;
  2973. virtual void SetSum4(int, int, int, int) = 0;
  2974. virtual void SetSum5(int, int, int, int, int) = 0;
  2975. virtual int Get() = 0;
  2976. virtual int GetNotImplemented() = 0;
  2977. virtual int GetSum1(int) = 0;
  2978. virtual int GetSum2(int, int) = 0;
  2979. virtual int GetSum3(int, int, int) = 0;
  2980. virtual int GetSum4(int, int, int, int) = 0;
  2981. virtual int GetSum5(int, int, int, int, int) = 0;
  2982. };
  2983. typedef AZ::EBus<TestBusMessages> TestBus;
  2984. class TestBusHandler
  2985. : public TestBus::Handler
  2986. , public AZ::BehaviorEBusHandler
  2987. {
  2988. public:
  2989. AZ_EBUS_BEHAVIOR_BINDER(TestBusHandler, "{CD26E702-6F40-4FF9-816D-4DCB652D97DF}", AZ::SystemAllocator,
  2990. Set, SetNotImplemented, SetSum1, SetSum2, SetSum3, SetSum4, SetSum5, Get, GetNotImplemented, GetSum1, GetSum2, GetSum3, GetSum4, GetSum5);
  2991. void Set() override
  2992. {
  2993. Call(FN_Set);
  2994. }
  2995. void SetNotImplemented() override
  2996. {
  2997. Call(FN_SetNotImplemented);
  2998. }
  2999. void SetSum1(int d1) override
  3000. {
  3001. Call(FN_SetSum1, d1);
  3002. }
  3003. void SetSum2(int d1, int d2) override
  3004. {
  3005. Call(FN_SetSum2, d1, d2);
  3006. }
  3007. void SetSum3(int d1, int d2, int d3) override
  3008. {
  3009. Call(FN_SetSum3, d1, d2, d3);
  3010. }
  3011. void SetSum4(int d1, int d2, int d3, int d4) override
  3012. {
  3013. Call(FN_SetSum4, d1, d2, d3, d4);
  3014. }
  3015. void SetSum5(int d1, int d2, int d3, int d4, int d5) override
  3016. {
  3017. Call(FN_SetSum5, d1, d2, d3, d4, d5);
  3018. }
  3019. int Get() override
  3020. {
  3021. int result = 0;
  3022. CallResult(result, FN_Get);
  3023. return result;
  3024. }
  3025. int GetNotImplemented() override
  3026. {
  3027. int result = -1;
  3028. CallResult(result, FN_GetNotImplemented);
  3029. return result;
  3030. }
  3031. int GetSum1(int d1) override
  3032. {
  3033. int result = 0;
  3034. CallResult(result, FN_GetSum1, d1);
  3035. return result;
  3036. }
  3037. int GetSum2(int d1, int d2) override
  3038. {
  3039. int result = 0;
  3040. CallResult(result, FN_GetSum2, d1, d2);
  3041. return result;
  3042. }
  3043. int GetSum3(int d1, int d2, int d3) override
  3044. {
  3045. int result = 0;
  3046. CallResult(result, FN_GetSum3, d1, d2, d3);
  3047. return result;
  3048. }
  3049. int GetSum4(int d1, int d2, int d3, int d4) override
  3050. {
  3051. int result = 0;
  3052. CallResult(result, FN_GetSum4, d1, d2, d3, d4);
  3053. return result;
  3054. }
  3055. int GetSum5(int d1, int d2, int d3, int d4, int d5) override
  3056. {
  3057. int result = 0;
  3058. CallResult(result, FN_GetSum5, d1, d2, d3, d4, d5);
  3059. return result;
  3060. }
  3061. };
  3062. //class TestBusSenderCheck : public TestBus::Handler
  3063. //{
  3064. //public:
  3065. // virtual void Set() { TestAssert(true); }
  3066. // virtual void SetNotImplemented() { /*Not used*/ }
  3067. // virtual void SetSum1(int _1) { TestAssert(_1 == 1); }
  3068. // virtual void SetSum2(int _1, int _2) { TestAssert(_1 + _2 == 3); }
  3069. // virtual void SetSum3(int _1, int _2, int _3) { TestAssert(_1 + _2 + _3 == 6); }
  3070. // virtual void SetSum4(int _1, int _2, int _3, int _4) { TestAssert(_1 + _2 + _3 + _4 == 10); }
  3071. // virtual void SetSum5(int _1, int _2, int _3, int _4, int _5) { TestAssert(_1 + _2 + _3 + _4 + _5 == 15); }
  3072. // virtual int Get() { return -1; }
  3073. // virtual int GetNotImplemented() { return -2; /*Not used*/ }
  3074. // virtual int GetSum1(int _1) { return _1; }
  3075. // virtual int GetSum2(int _1, int _2) { return _1 + _2; }
  3076. // virtual int GetSum3(int _1, int _2, int _3) { return _1 + _2 + _3; }
  3077. // virtual int GetSum4(int _1, int _2, int _3, int _4) { return _1 + _2 + _3 + _4; }
  3078. // virtual int GetSum5(int _1, int _2, int _3, int _4, int _5) { return _1 + _2 + _3 + _4 + _5; }
  3079. //};
  3080. //class MyInterface
  3081. //{
  3082. //public:
  3083. // // AZ_TYPE_INFO(MyInterface,"{96a83332-8cd1-4299-9972-e670be92ab99}");
  3084. // virtual int GetInt() const = 0;
  3085. //};
  3086. /* class MyImpl : public MyInterface
  3087. {
  3088. public:
  3089. int GetInt() const override { return 5; }
  3090. };*/
  3091. //class MyRequests : public AZ::EBusTraits
  3092. //{
  3093. //public:
  3094. // virtual const MyInterface* GetIFace() = 0;
  3095. //};
  3096. //using MyRequestBus = AZ::EBus<MyRequests>;
  3097. //AZ_SCRIPTABLE_EBUS(
  3098. // MyRequestBus,
  3099. // MyRequestBus,
  3100. // "{DD4261AD-416E-4824-97A8-EFEF0F54AD91}",
  3101. // "{9312EB0C-0717-4F91-97F8-30A946096E9B}",
  3102. // AZ_SCRIPTABLE_EBUS_EVENT_RESULT(const MyInterface*, nullptr, GetIFace)
  3103. // );
  3104. class ScriptedBusTest
  3105. : public LeakDetectionFixture {
  3106. public:
  3107. void run()
  3108. {
  3109. const char luaCode[] = "\
  3110. MyBusHandlerMetaTable1 = {\
  3111. Set = function(self)\
  3112. TestAssert(true)\
  3113. end,\
  3114. SetSum1 = function(self, _1)\
  3115. TestAssert(_1 == 1)\
  3116. end,\
  3117. SetSum2 = function(self, _1, _2)\
  3118. TestAssert(_1 + _2 == 3)\
  3119. end,\
  3120. SetSum3 = function(self, _1, _2, _3)\
  3121. TestAssert(_1 + _2 + _3 == 6)\
  3122. end,\
  3123. SetSum4 = function(self, _1, _2, _3, _4)\
  3124. TestAssert(_1 + _2 + _3 + _4 == 10)\
  3125. end,\
  3126. SetSum5 = function(self, _1, _2, _3, _4, _5)\
  3127. TestAssert(_1 + _2 + _3 + _4 + _5 == 15)\
  3128. end,\
  3129. Get = function(self)\
  3130. return -1\
  3131. end,\
  3132. GetSum1 = function(self, _1)\
  3133. return _1\
  3134. end,\
  3135. GetSum2 = function(self, _1, _2)\
  3136. return _1 + _2\
  3137. end,\
  3138. GetSum3 = function(self, _1, _2, _3)\
  3139. return _1 + _2 + _3\
  3140. end,\
  3141. GetSum4 = function(self, _1, _2, _3, _4)\
  3142. return _1 + _2 + _3 + _4\
  3143. end,\
  3144. GetSum5 = function(self, _1, _2, _3, _4, _5)\
  3145. return _1 + _2 + _3 + _4 + _5\
  3146. end\
  3147. }\
  3148. MyBusHandlerMetaTable2 = {\
  3149. Get = function(self)\
  3150. return -2\
  3151. end\
  3152. }\
  3153. setmetatable(MyBusHandlerMetaTable2, MyBusHandlerMetaTable1)\
  3154. ";
  3155. BehaviorContext behaviorContext;
  3156. behaviorContext.Method("TestAssert", &TestAssert);
  3157. behaviorContext.EBus<TestBus>("TestBus")->
  3158. Handler<TestBusHandler>()->
  3159. Event("Set", &TestBus::Events::Set)->
  3160. Event("SetNotImplemented", &TestBus::Events::SetNotImplemented)->
  3161. Event("SetSum1", &TestBus::Events::SetSum1)->
  3162. Event("SetSum2", &TestBus::Events::SetSum2)->
  3163. Event("SetSum3", &TestBus::Events::SetSum3)->
  3164. Event("SetSum4", &TestBus::Events::SetSum4)->
  3165. Event("SetSum5", &TestBus::Events::SetSum5)->
  3166. Event("Get", &TestBus::Events::Get)->
  3167. Event("GetNotImplemented", &TestBus::Events::GetNotImplemented)->
  3168. Event("GetSum1", &TestBus::Events::GetSum1)->
  3169. Event("GetSum2", &TestBus::Events::GetSum2)->
  3170. Event("GetSum3", &TestBus::Events::GetSum3)->
  3171. Event("GetSum4", &TestBus::Events::GetSum4)->
  3172. Event("GetSum5", &TestBus::Events::GetSum5)
  3173. ;
  3174. ScriptContext script;
  3175. script.BindTo(&behaviorContext);
  3176. script.Execute(luaCode);
  3177. // Test sending messages from C++ to LUA handler
  3178. script.Execute("handler = TestBus.Connect(MyBusHandlerMetaTable1)");
  3179. AZ_TEST_START_TRACE_SUPPRESSION;
  3180. TestBus::Broadcast(&TestBus::Events::Set);
  3181. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3182. TestBus::Broadcast(&TestBus::Events::SetNotImplemented); // nothing should happen here
  3183. AZ_TEST_START_TRACE_SUPPRESSION;
  3184. TestBus::Broadcast(&TestBus::Events::SetSum1, 1);
  3185. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3186. AZ_TEST_START_TRACE_SUPPRESSION;
  3187. TestBus::Broadcast(&TestBus::Events::SetSum2, 1, 2);
  3188. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3189. AZ_TEST_START_TRACE_SUPPRESSION;
  3190. TestBus::Broadcast(&TestBus::Events::SetSum3, 1, 2, 3);
  3191. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3192. AZ_TEST_START_TRACE_SUPPRESSION;
  3193. TestBus::Broadcast(&TestBus::Events::SetSum4, 1, 2, 3, 4);
  3194. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3195. AZ_TEST_START_TRACE_SUPPRESSION;
  3196. TestBus::Broadcast(&TestBus::Events::SetSum5, 1, 2, 3, 4, 5);
  3197. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3198. script.Execute("handler:Disconnect()");
  3199. script.Execute("handler = TestBus.Connect(MyBusHandlerMetaTable2)");
  3200. AZ_TEST_START_TRACE_SUPPRESSION;
  3201. script.Execute("TestBus.Broadcast.Set()");
  3202. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3203. AZ_TEST_START_TRACE_SUPPRESSION;
  3204. script.Execute("TestBus.Broadcast.SetNotImplemented()");
  3205. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  3206. AZ_TEST_START_TRACE_SUPPRESSION;
  3207. script.Execute("TestBus.Broadcast.SetSum1(1)");
  3208. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3209. AZ_TEST_START_TRACE_SUPPRESSION;
  3210. script.Execute("TestBus.Broadcast.SetSum2(1, 2)");
  3211. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3212. AZ_TEST_START_TRACE_SUPPRESSION;
  3213. script.Execute("TestBus.Broadcast.SetSum3(1, 2, 3)");
  3214. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3215. AZ_TEST_START_TRACE_SUPPRESSION;
  3216. script.Execute("TestBus.Broadcast.SetSum4(1, 2, 3, 4)");
  3217. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3218. AZ_TEST_START_TRACE_SUPPRESSION;
  3219. script.Execute("TestBus.Broadcast.SetSum5(1, 2, 3, 4, 5)");
  3220. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3221. AZ_TEST_START_TRACE_SUPPRESSION;
  3222. script.Execute("TestAssert(TestBus.Broadcast.Get() == -2)");
  3223. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3224. AZ_TEST_START_TRACE_SUPPRESSION;
  3225. script.Execute("TestAssert(TestBus.Broadcast.GetNotImplemented() == -1)");
  3226. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3227. AZ_TEST_START_TRACE_SUPPRESSION;
  3228. script.Execute("TestAssert(TestBus.Broadcast.GetSum1(1) == 1)");
  3229. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3230. AZ_TEST_START_TRACE_SUPPRESSION;
  3231. script.Execute("TestAssert(TestBus.Broadcast.GetSum2(1, 2) == 3)");
  3232. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3233. AZ_TEST_START_TRACE_SUPPRESSION;
  3234. script.Execute("TestAssert(TestBus.Broadcast.GetSum3(1, 2, 3) == 6)");
  3235. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3236. AZ_TEST_START_TRACE_SUPPRESSION;
  3237. script.Execute("TestAssert(TestBus.Broadcast.GetSum4(1, 2, 3, 4) == 10)");
  3238. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3239. AZ_TEST_START_TRACE_SUPPRESSION;
  3240. script.Execute("TestAssert(TestBus.Broadcast.GetSum5(1, 2, 3, 4, 5) == 15)");
  3241. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3242. script.Execute("handler:Disconnect()\
  3243. handler = nil");
  3244. }
  3245. };
  3246. TEST_F(ScriptedBusTest, LuaTest)
  3247. {
  3248. run();
  3249. }
  3250. // RamenRequests
  3251. class RamenRequests
  3252. : public AZ::EBusTraits
  3253. {
  3254. public:
  3255. typedef unsigned int BusIdType;
  3256. static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
  3257. static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
  3258. virtual void AddPepper() = 0;
  3259. };
  3260. using RamenRequestBus = AZ::EBus<RamenRequests>;
  3261. class RamenRequestHandler
  3262. : public RamenRequestBus::Handler
  3263. {
  3264. public:
  3265. void AddPepper() override { };
  3266. };
  3267. class RamenRequestBehaviorHandler
  3268. : public RamenRequestBus::Handler
  3269. , public BehaviorEBusHandler
  3270. {
  3271. public:
  3272. AZ_EBUS_BEHAVIOR_BINDER(RamenRequestBehaviorHandler, "{EB4E043B-AD1A-4745-A725-91100E191517}", AZ::SystemAllocator, AddPepper);
  3273. void AddPepper() override
  3274. {
  3275. Call(FN_AddPepper);
  3276. }
  3277. };
  3278. // RamenRequests
  3279. // RamenShopNotifications
  3280. class RamenShopNotifications
  3281. : public AZ::EBusTraits
  3282. {
  3283. public:
  3284. typedef unsigned int BusIdType;
  3285. static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
  3286. static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
  3287. virtual void OnOrderCancelled(int id) = 0;
  3288. };
  3289. using RamenShopNotificationBus = AZ::EBus<RamenShopNotifications>;
  3290. class RamenShopNotificationHandler
  3291. : public RamenShopNotificationBus::MultiHandler
  3292. {
  3293. public:
  3294. void OnOrderCancelled(int /*id*/) override {};
  3295. };
  3296. class RamenShopNotificationBehaviorHandler
  3297. : public RamenShopNotificationBus::MultiHandler
  3298. , public BehaviorEBusHandler
  3299. {
  3300. public:
  3301. AZ_EBUS_BEHAVIOR_BINDER(RamenShopNotificationBehaviorHandler, "{98A0C1B1-0B81-4563-886A-03204DDBE146}", AZ::SystemAllocator, OnOrderCancelled);
  3302. void OnOrderCancelled(int id) override
  3303. {
  3304. Call(FN_OnOrderCancelled, id);
  3305. }
  3306. };
  3307. // RamenShopNotifications
  3308. class ScriptBehaviorHandlerIsConnectedTest
  3309. : public LeakDetectionFixture
  3310. {
  3311. public:
  3312. static void TestAssert([[maybe_unused]] bool check)
  3313. {
  3314. AZ_Assert(check, "Script Test assert");
  3315. }
  3316. void SetUp() override
  3317. {
  3318. LeakDetectionFixture::SetUp();
  3319. m_behaviorContext = aznew BehaviorContext();
  3320. m_behaviorContext->Method("TestAssert", &ScriptBehaviorHandlerIsConnectedTest::TestAssert);
  3321. m_behaviorContext->EBus<RamenRequestBus>("RamenRequestBus")->
  3322. Handler<RamenRequestBehaviorHandler>()->
  3323. Event("AddPepper", &RamenRequestBus::Events::AddPepper);
  3324. m_behaviorContext->EBus<RamenShopNotificationBus>("RamenShopNotificationBus")->
  3325. Handler<RamenShopNotificationBehaviorHandler>()->
  3326. Event("OnOrderCancelled", &RamenShopNotificationBus::Events::OnOrderCancelled);
  3327. m_scriptContext = aznew ScriptContext();
  3328. m_scriptContext->BindTo(m_behaviorContext);
  3329. }
  3330. void TearDown() override
  3331. {
  3332. delete m_scriptContext;
  3333. delete m_behaviorContext;
  3334. LeakDetectionFixture::TearDown();
  3335. }
  3336. ScriptContext* m_scriptContext;
  3337. BehaviorContext* m_behaviorContext;
  3338. };
  3339. TEST_F(ScriptBehaviorHandlerIsConnectedTest, LuaIsConnected_UberTest)
  3340. {
  3341. const char luaCode[] = R"(
  3342. ramen = {
  3343. handler1 = nil,
  3344. handler2 = nil
  3345. }
  3346. ramen.handler1 = RamenRequestBus.Connect(ramen, 1)
  3347. ramen.handler2 = RamenRequestBus.Connect(ramen, 2)
  3348. ramenShop = {
  3349. handler = nil
  3350. }
  3351. ramenShop.handler = RamenShopNotificationBus.CreateHandler(ramenShop)
  3352. ramenShop.handler:Connect(3);
  3353. ramenShop.handler:Connect(4);
  3354. )";
  3355. m_scriptContext->Execute(luaCode);
  3356. m_scriptContext->Execute("TestAssert(ramen.handler1:IsConnected())");
  3357. m_scriptContext->Execute("TestAssert(ramen.handler1:IsConnectedId(1))");
  3358. m_scriptContext->Execute("TestAssert(ramen.handler2:IsConnectedId(2))");
  3359. m_scriptContext->Execute("TestAssert(ramenShop.handler:IsConnected())");
  3360. m_scriptContext->Execute("TestAssert(ramenShop.handler:IsConnectedId(3))");
  3361. m_scriptContext->Execute("TestAssert(ramenShop.handler:IsConnectedId(4))");
  3362. }
  3363. //-----------------------------------------------------------------------------
  3364. // Ebus script with bus id test
  3365. //-----------------------------------------------------------------------------
  3366. class TestIdBusMessages
  3367. : public AZ::EBusTraits
  3368. {
  3369. public:
  3370. typedef unsigned int BusIdType;
  3371. static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
  3372. static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
  3373. virtual ~TestIdBusMessages() {}
  3374. virtual void VoidFunc0() = 0;
  3375. virtual float Pick(float, float, float) = 0;
  3376. };
  3377. typedef AZ::EBus<TestIdBusMessages> TestIdBus;
  3378. class TestIdBusCPPHandler
  3379. : public TestIdBus::Handler
  3380. {
  3381. public:
  3382. void VoidFunc0() override { TestAssert(true); }
  3383. float Pick(float /*_1*/, float /*_2*/, float _3) override { return _3; }
  3384. };
  3385. //AZ_SCRIPTABLE_EBUS(
  3386. // TestIdBus,
  3387. // TestIdBus,
  3388. // "{2DACEBCC-CB6B-403A-9E91-4E7390F567C9}", // Handler type UUID
  3389. // "{EB13A5D0-D642-49E2-9D3C-DC15F96FD97A}", // Sender type UUID
  3390. // AZ_SCRIPTABLE_EBUS_EVENT(VoidFunc0)
  3391. // AZ_SCRIPTABLE_EBUS_EVENT_RESULT(float, 0.f, Pick, float, float, float)
  3392. // )
  3393. class TestIdBusHandler
  3394. : public TestIdBus::Handler
  3395. , public AZ::BehaviorEBusHandler
  3396. {
  3397. public:
  3398. AZ_EBUS_BEHAVIOR_BINDER(TestIdBusHandler, "{2DACEBCC-CB6B-403A-9E91-4E7390F567C9}", AZ::SystemAllocator,
  3399. VoidFunc0, Pick);
  3400. void VoidFunc0() override
  3401. {
  3402. Call(FN_VoidFunc0);
  3403. }
  3404. float Pick(float a, float b, float c) override
  3405. {
  3406. float result = 0.0f;
  3407. CallResult(result, FN_Pick, a, b, c);
  3408. return result;
  3409. }
  3410. };
  3411. class ScriptedIdBusTest
  3412. : public LeakDetectionFixture
  3413. {
  3414. public:
  3415. void run()
  3416. {
  3417. const char luaCode[] = "\
  3418. MyBusHandlerMetaTable1 = {\
  3419. VoidFunc0 = function(self)\
  3420. TestAssert(true)\
  3421. end,\
  3422. Pick = function(self, _1, _2, _3)\
  3423. return _1\
  3424. end\
  3425. }\
  3426. MyBusHandlerMetaTable2 = {\
  3427. Pick = function(self, _1, _2, _3)\
  3428. return _2\
  3429. end\
  3430. }\
  3431. setmetatable(MyBusHandlerMetaTable2, MyBusHandlerMetaTable1)\
  3432. handler1 = TestIdBus.Connect(MyBusHandlerMetaTable1, 1)\
  3433. handler2 = TestIdBus.CreateHandler(MyBusHandlerMetaTable2)\
  3434. handler2:Connect(2)\
  3435. ";
  3436. BehaviorContext behaviorContext;
  3437. behaviorContext.Method("TestAssert", &TestAssert);
  3438. behaviorContext.EBus<TestIdBus>("TestIdBus")->
  3439. Handler<TestIdBusHandler>()->
  3440. Event("VoidFunc0", &TestIdBus::Events::VoidFunc0)->
  3441. Event("Pick", &TestIdBus::Events::Pick);
  3442. ScriptContext script;
  3443. script.BindTo(&behaviorContext);
  3444. script.Execute(luaCode);
  3445. // Test sending messages from C++ to two LUA handlers on different bus ids
  3446. AZ_TEST_START_TRACE_SUPPRESSION;
  3447. TestIdBus::Event(1, &TestIdBus::Events::VoidFunc0);
  3448. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3449. AZ_TEST_START_TRACE_SUPPRESSION;
  3450. TestIdBus::Event(2, &TestIdBus::Events::VoidFunc0);
  3451. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3452. float ret = 0.f;
  3453. TestIdBus::EventResult(ret, 1, &TestIdBus::Events::Pick, 1.f, 2.f, 3.f);
  3454. AZ_TEST_ASSERT(ret == 1.f);
  3455. ret = 0;
  3456. TestIdBus::EventResult(ret, 2, &TestIdBus::Events::Pick, 1.f, 2.f, 3.f);
  3457. AZ_TEST_ASSERT(ret == 2.f);
  3458. script.Execute("handler1:Disconnect()");
  3459. script.Execute("handler2:Disconnect()");
  3460. // Test sending messages from LUA to a LUA handler on id 1 and a C++ handler on id 3.
  3461. script.Execute("handler = TestIdBus.Connect(MyBusHandlerMetaTable1, 1)");
  3462. TestIdBusCPPHandler cppHandler;
  3463. cppHandler.BusConnect(3);
  3464. AZ_TEST_START_TRACE_SUPPRESSION;
  3465. script.Execute("TestIdBus.Event.VoidFunc0(1)"); // send even on id=1
  3466. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3467. AZ_TEST_START_TRACE_SUPPRESSION;
  3468. script.Execute("TestAssert(TestIdBus.Event.Pick(1, 1.0, 2.0, 3.0) == 1.0)");
  3469. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3470. AZ_TEST_START_TRACE_SUPPRESSION;
  3471. script.Execute("TestIdBus.Event.VoidFunc0(3)");
  3472. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3473. AZ_TEST_START_TRACE_SUPPRESSION;
  3474. script.Execute("TestAssert(TestIdBus.Event.Pick(3, 1.0, 2.0, 3.0) == 3.0)");
  3475. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3476. script.Execute("handler:Disconnect()");
  3477. AZ_TEST_START_TRACE_SUPPRESSION;
  3478. script.Execute("handler:Connect('my fake bus id')");
  3479. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3480. AZ_TEST_START_TRACE_SUPPRESSION;
  3481. script.Execute("handler = TestIdBus.Connect({ }, 'my fake bus id')");
  3482. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  3483. script.Execute("TestAssert(handler == nil)");
  3484. }
  3485. };
  3486. TEST_F(ScriptedIdBusTest, LuaTest)
  3487. {
  3488. run();
  3489. }
  3490. void AZTestAssert(bool check)
  3491. {
  3492. (void)check;
  3493. AZ_Assert(check, "Script Test assert");
  3494. }
  3495. class AnyScriptBindTest
  3496. : public LeakDetectionFixture
  3497. {
  3498. public:
  3499. struct DataContainer
  3500. {
  3501. public:
  3502. AZ_TYPE_INFO(DataContainer, "{FC0B12F1-165F-4D0C-ABAE-E9F657370352}");
  3503. DataContainer(int initData)
  3504. : m_data(initData)
  3505. { }
  3506. int m_data;
  3507. };
  3508. static bool s_wasCalled;
  3509. static void TestThatDataIs10(AZStd::any container)
  3510. {
  3511. ASSERT_TRUE(container.is<DataContainer>());
  3512. ASSERT_EQ(10, AZStd::any_cast<DataContainer&>(container).m_data);
  3513. s_wasCalled = true;
  3514. }
  3515. void SetUp() override
  3516. {
  3517. LeakDetectionFixture::SetUp();
  3518. s_wasCalled = false;
  3519. m_behavior = aznew BehaviorContext();
  3520. m_behavior->Class<DataContainer>("DataContainer")
  3521. ->Constructor<int>()
  3522. ->Property("data", BehaviorValueProperty(&DataContainer::m_data))
  3523. ;
  3524. m_behavior->Method("TestThatDataIs10", &TestThatDataIs10);
  3525. m_behavior->Property("wasCalled", BehaviorValueGetter(&s_wasCalled), nullptr);
  3526. m_script = aznew ScriptContext();
  3527. m_script->BindTo(m_behavior);
  3528. }
  3529. void TearDown() override
  3530. {
  3531. delete m_script;
  3532. delete m_behavior;
  3533. LeakDetectionFixture::TearDown();
  3534. }
  3535. BehaviorContext* m_behavior;
  3536. ScriptContext* m_script;
  3537. };
  3538. bool AnyScriptBindTest::s_wasCalled = false;
  3539. TEST_F(AnyScriptBindTest, LuaScriptContextAny_AnyFromLua)
  3540. {
  3541. m_script->Execute("TestThatDataIs10(DataContainer(10))");
  3542. EXPECT_TRUE(s_wasCalled);
  3543. }
  3544. class BaseScriptTest
  3545. : public LeakDetectionFixture
  3546. {
  3547. public:
  3548. void SetUp() override
  3549. {
  3550. LeakDetectionFixture::SetUp();
  3551. m_behavior = aznew BehaviorContext();
  3552. m_behavior->Method("AZTestAssert", &AZTestAssert);
  3553. SetupBehaviorContext(*m_behavior);
  3554. m_script = aznew ScriptContext();
  3555. m_script->BindTo(m_behavior);
  3556. }
  3557. void TearDown() override
  3558. {
  3559. delete m_script;
  3560. delete m_behavior;
  3561. LeakDetectionFixture::TearDown();
  3562. }
  3563. BehaviorContext* m_behavior;
  3564. ScriptContext* m_script;
  3565. virtual void SetupBehaviorContext(BehaviorContext& bc) { (void)bc; }
  3566. };
  3567. TEST_F(BaseScriptTest, LuaUnreflect)
  3568. {
  3569. m_behavior->Class<ScriptClass>();
  3570. m_script->Execute("AZTestAssert(ScriptClass ~= nil)");
  3571. m_behavior->EnableRemoveReflection();
  3572. m_behavior->Class<ScriptClass>();
  3573. m_behavior->DisableRemoveReflection();
  3574. m_script->Execute("AZTestAssert(ScriptClass == nil)");
  3575. }
  3576. class MathScriptTest
  3577. : public BaseScriptTest
  3578. {
  3579. static void ScriptAssertEqual(double lhs, double rhs)
  3580. {
  3581. EXPECT_TRUE(AZ::IsClose(lhs, rhs, static_cast<double>(AZ::Constants::FloatEpsilon)));
  3582. }
  3583. void SetupBehaviorContext(BehaviorContext& bc) override
  3584. {
  3585. MathReflect(&bc);
  3586. bc.Method("ScriptAssertEqual", &ScriptAssertEqual);
  3587. }
  3588. };
  3589. TEST_F(MathScriptTest, LuaScriptMath_BasicRandomTests)
  3590. {
  3591. // tests pseudo random number generator
  3592. m_script->Execute(R"LUA(
  3593. local r = Random();
  3594. r = Random(4321);
  3595. r:SetSeed(1212);
  3596. ScriptAssertEqual(r:GetRandom(), 2783974736);
  3597. ScriptAssertEqual(r:GetRandomFloat(), 0.61152875423431396);
  3598. )LUA");
  3599. }
  3600. class ScriptTypeidTest
  3601. : public LeakDetectionFixture
  3602. {
  3603. public:
  3604. void SetUp() override
  3605. {
  3606. LeakDetectionFixture::SetUp();
  3607. m_behavior = aznew BehaviorContext();
  3608. AZ::MathReflect(m_behavior);
  3609. m_behavior->Class<ScriptClass>();
  3610. m_behavior->Method("AZTestAssert", &AZTestAssert);
  3611. m_behavior->Method("CheckScriptClassTypeid", &CheckScriptTypeid<ScriptClass>);
  3612. m_behavior->Method("CheckScriptBoolTypeid", &CheckScriptTypeid<bool>);
  3613. m_behavior->Method("CheckScriptStringTypeid", &CheckScriptTypeid<AZStd::string>);
  3614. m_behavior->Method("CheckScriptNumberTypeid", &CheckScriptTypeid<double>);
  3615. m_behavior->Method("CheckScriptTypeidNullptr", &CheckScriptTypeidNullptr);
  3616. m_script = aznew ScriptContext();
  3617. m_script->BindTo(m_behavior);
  3618. }
  3619. void TearDown() override
  3620. {
  3621. delete m_script;
  3622. delete m_behavior;
  3623. LeakDetectionFixture::TearDown();
  3624. }
  3625. template <typename T>
  3626. static void CheckScriptTypeid(const AZ::Uuid& typeId)
  3627. {
  3628. EXPECT_EQ(azrtti_typeid<T>(), typeId);
  3629. }
  3630. static void CheckScriptTypeidNullptr(const AZ::Uuid& typeId)
  3631. {
  3632. EXPECT_TRUE(typeId.IsNull());
  3633. }
  3634. BehaviorContext* m_behavior = nullptr;
  3635. ScriptContext* m_script = nullptr;
  3636. };
  3637. TEST_F(ScriptTypeidTest, LuaTypeId_Class)
  3638. {
  3639. m_script->Execute("CheckScriptClassTypeid(typeid(ScriptClass))");
  3640. m_script->Execute("local v = ScriptClass(); CheckScriptClassTypeid(typeid(v))");
  3641. }
  3642. TEST_F(ScriptTypeidTest, LuaTypeId_Bool)
  3643. {
  3644. m_script->Execute("CheckScriptBoolTypeid(typeid(true))");
  3645. }
  3646. TEST_F(ScriptTypeidTest, LuaTypeId_String)
  3647. {
  3648. m_script->Execute("CheckScriptStringTypeid(typeid(''))");
  3649. }
  3650. TEST_F(ScriptTypeidTest, LuaTypeId_Number)
  3651. {
  3652. m_script->Execute("CheckScriptNumberTypeid(typeid(1))");
  3653. }
  3654. TEST_F(ScriptTypeidTest, LuaTypeId_ArgMiscount)
  3655. {
  3656. m_script->Execute("CheckScriptTypeidNullptr(typeid())");
  3657. m_script->Execute("CheckScriptTypeidNullptr(typeid(1, 2, 3))");
  3658. }
  3659. TEST_F(ScriptTypeidTest, LuaTypeId_UnhandledType)
  3660. {
  3661. m_script->Execute("CheckScriptTypeidNullptr(typeid(function() end))");
  3662. m_script->Execute("CheckScriptTypeidNullptr(typeid({ }))");
  3663. }
  3664. class ScriptCacheTableTest
  3665. : public LeakDetectionFixture
  3666. {
  3667. public:
  3668. void SetUp() override
  3669. {
  3670. LeakDetectionFixture::SetUp();
  3671. m_script = aznew ScriptContext();
  3672. m_lua = m_script->NativeContext();
  3673. }
  3674. void TearDown() override
  3675. {
  3676. m_lua = nullptr;
  3677. delete m_script;
  3678. LeakDetectionFixture::TearDown();
  3679. }
  3680. ScriptContext* m_script = nullptr;
  3681. lua_State* m_lua = nullptr;
  3682. };
  3683. TEST_F(ScriptCacheTableTest, LuaNilRef)
  3684. {
  3685. lua_pushnil(m_lua);
  3686. EXPECT_EQ(LUA_REFNIL, Internal::LuaCacheValue(m_lua, -1));
  3687. lua_pop(m_lua, 1);
  3688. Internal::LuaLoadCached(m_lua, LUA_REFNIL);
  3689. EXPECT_TRUE(lua_isnil(m_lua, -1));
  3690. lua_pop(m_lua, 1);
  3691. }
  3692. TEST_F(ScriptCacheTableTest, LuaInsertElement_RetreiveElement_IsSame)
  3693. {
  3694. lua_pushliteral(m_lua, "TEST_STRING");
  3695. int ref = Internal::LuaCacheValue(m_lua, -1);
  3696. lua_pop(m_lua, 1);
  3697. ASSERT_GT(ref, 0);
  3698. Internal::LuaLoadCached(m_lua, ref);
  3699. ASSERT_EQ(LUA_TSTRING, lua_type(m_lua, -1));
  3700. EXPECT_STREQ("TEST_STRING", lua_tostring(m_lua, -1));
  3701. lua_pop(m_lua, 1);
  3702. Internal::LuaReleaseCached(m_lua, ref);
  3703. }
  3704. TEST_F(ScriptCacheTableTest, LuaInsertElements_RemoveFromMiddle_RemoveFromEnd)
  3705. {
  3706. int refs[6] = { };
  3707. int removedRefs[] = { 2, 4, 5 };
  3708. // Create a bunch of references
  3709. lua_pushinteger(m_lua, 42);
  3710. for (int& ref : refs)
  3711. {
  3712. ref = Internal::LuaCacheValue(m_lua, -1);
  3713. ASSERT_GT(ref, 0);
  3714. }
  3715. // All refs should be valid at the beginning
  3716. for (const int& ref : refs)
  3717. {
  3718. Internal::LuaLoadCached(m_lua, ref);
  3719. ASSERT_FALSE(lua_isnil(m_lua, -1));
  3720. EXPECT_EQ(42, lua_tointeger(m_lua, -1));
  3721. lua_pop(m_lua, 1);
  3722. }
  3723. // Remove some refs
  3724. for (const int& refIdx : removedRefs)
  3725. {
  3726. Internal::LuaReleaseCached(m_lua, refs[refIdx]);
  3727. refs[refIdx] = LUA_NOREF;
  3728. }
  3729. // All non-removed refs here should be valid
  3730. for (const int& ref : refs)
  3731. {
  3732. // Skip removed refs
  3733. if (ref == LUA_NOREF)
  3734. {
  3735. continue;
  3736. }
  3737. Internal::LuaLoadCached(m_lua, ref);
  3738. ASSERT_FALSE(lua_isnil(m_lua, -1));
  3739. EXPECT_EQ(42, lua_tointeger(m_lua, -1));
  3740. lua_pop(m_lua, 1);
  3741. }
  3742. // Reinsert the refs
  3743. for (const int& refIdx : removedRefs)
  3744. {
  3745. refs[refIdx] = Internal::LuaCacheValue(m_lua, -1);
  3746. }
  3747. // All refs should be valid again
  3748. for (const int& ref : refs)
  3749. {
  3750. Internal::LuaLoadCached(m_lua, ref);
  3751. ASSERT_FALSE(lua_isnil(m_lua, -1));
  3752. EXPECT_EQ(42, lua_tointeger(m_lua, -1));
  3753. lua_pop(m_lua, 1);
  3754. }
  3755. for (int& ref : refs)
  3756. {
  3757. Internal::LuaReleaseCached(m_lua, ref);
  3758. ref = LUA_NOREF;
  3759. }
  3760. // Get cache table to ensure it's reset
  3761. lua_rawgeti(m_lua, LUA_REGISTRYINDEX, AZ_LUA_WEAK_CACHE_TABLE_REF);
  3762. lua_rawgeti(m_lua, -1, 2); // Get first free list index
  3763. EXPECT_EQ(3, (int)lua_tointeger(m_lua, -1)) << "Free list index does not point to first assignable element";
  3764. lua_pop(m_lua, 1);
  3765. lua_rawgeti(m_lua, -1, 3); // Get the first free element
  3766. EXPECT_TRUE(lua_isnil(m_lua, -1)) << "First assignable element is not empty";
  3767. lua_pop(m_lua, 1);
  3768. EXPECT_EQ(2u, lua_rawlen(m_lua, -1)) << "Cache table contains more than just header";
  3769. lua_pop(m_lua, 1);
  3770. }
  3771. class UnregisteredSharedPointerTest
  3772. : public BehaviorContextFixture
  3773. {
  3774. public:
  3775. struct UnregisteredType
  3776. {
  3777. AZ_CLASS_ALLOCATOR(UnregisteredType, SystemAllocator);
  3778. AZ_TYPE_INFO(UnregisteredType, "{6C5C91A6-A9F6-470D-8841-179201A0D9E6}");
  3779. };
  3780. static AZStd::shared_ptr<UnregisteredType> GetPtr()
  3781. {
  3782. return AZStd::make_shared<UnregisteredType>();
  3783. }
  3784. static void TestIsPtrNullptr(AZStd::shared_ptr<UnregisteredType> ptr)
  3785. {
  3786. ASSERT_NE(nullptr, ptr);
  3787. }
  3788. void SetUp() override
  3789. {
  3790. BehaviorContextFixture::SetUp();
  3791. m_behaviorContext->Method("AZTestAssert", &AZTestAssert);
  3792. m_behaviorContext->Method("GetPtr", &GetPtr);
  3793. m_behaviorContext->Method("TestIsPtrNullptr", &TestIsPtrNullptr);
  3794. m_script = aznew ScriptContext();
  3795. m_script->BindTo(m_behaviorContext);
  3796. }
  3797. void TearDown() override
  3798. {
  3799. delete m_script;
  3800. BehaviorContextFixture::TearDown();
  3801. }
  3802. ScriptContext* m_script = nullptr;
  3803. };
  3804. TEST_F(UnregisteredSharedPointerTest, LuaTest)
  3805. {
  3806. // Test that the pointer remains valid
  3807. m_script->Execute(R"LUA(
  3808. instance = GetPtr();
  3809. TestIsPtrNullptr(instance);
  3810. AZTestAssert(instance:get() ~= nil);
  3811. )LUA");
  3812. ScriptContext::ErrorHook errorHook = [](ScriptContext*, ScriptContext::ErrorType error, const char*) {
  3813. ASSERT_GT(error, ScriptContext::ErrorType::Log);
  3814. };
  3815. // Test that actually doing stuff with it alerts the user
  3816. auto oldHook = m_script->GetErrorHook();
  3817. m_script->SetErrorHook(errorHook);
  3818. m_script->Execute(R"LUA(
  3819. instance:DoThing();
  3820. )LUA");
  3821. m_script->SetErrorHook(oldHook);
  3822. }
  3823. }
  3824. #endif // #if !defined(AZCORE_EXCLUDE_LUA)