You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

doctest.cpp 158KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838
  1. #if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER)
  2. #ifndef DOCTEST_SINGLE_HEADER
  3. #include "doctest_fwd.h"
  4. #endif // DOCTEST_SINGLE_HEADER
  5. DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros")
  6. #ifndef DOCTEST_LIBRARY_IMPLEMENTATION
  7. #define DOCTEST_LIBRARY_IMPLEMENTATION
  8. DOCTEST_CLANG_SUPPRESS_WARNING_POP
  9. DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
  10. DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas")
  11. DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded")
  12. DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables")
  13. DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors")
  14. DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
  15. DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes")
  16. DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion")
  17. DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32")
  18. DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations")
  19. DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch")
  20. DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum")
  21. DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default")
  22. DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn")
  23. DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef")
  24. DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion")
  25. DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces")
  26. DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers")
  27. DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
  28. DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
  29. DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function")
  30. DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path")
  31. DOCTEST_GCC_SUPPRESS_WARNING_PUSH
  32. DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas")
  33. DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas")
  34. DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion")
  35. DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++")
  36. DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion")
  37. DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow")
  38. DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing")
  39. DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers")
  40. DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces")
  41. DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations")
  42. DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch")
  43. DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum")
  44. DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default")
  45. DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations")
  46. DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast")
  47. DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs")
  48. DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast")
  49. DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function")
  50. DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance")
  51. DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept")
  52. DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute")
  53. DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
  54. DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning
  55. DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning
  56. DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration
  57. DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data
  58. DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression
  59. DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated
  60. DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant
  61. DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled
  62. DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified
  63. DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal
  64. DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch
  65. DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding in structs
  66. DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe
  67. DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C
  68. DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation stuff
  69. DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted
  70. DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted
  71. DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted
  72. DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted
  73. DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning)
  74. // static analysis
  75. DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept'
  76. DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable
  77. DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ...
  78. DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtor...
  79. DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum'
  80. DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
  81. // required includes - will go only in one translation unit!
  82. #include <ctime>
  83. #include <cmath>
  84. #include <climits>
  85. // borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37
  86. #ifdef __BORLANDC__
  87. #include <math.h>
  88. #endif // __BORLANDC__
  89. #include <new>
  90. #include <cstdio>
  91. #include <cstdlib>
  92. #include <cstring>
  93. #include <limits>
  94. #include <utility>
  95. #include <fstream>
  96. #include <sstream>
  97. #include <iostream>
  98. #include <algorithm>
  99. #include <iomanip>
  100. #include <vector>
  101. #include <atomic>
  102. #include <mutex>
  103. #include <set>
  104. #include <map>
  105. #include <exception>
  106. #include <stdexcept>
  107. #include <csignal>
  108. #include <cfloat>
  109. #include <cctype>
  110. #include <cstdint>
  111. #ifdef DOCTEST_PLATFORM_MAC
  112. #include <sys/types.h>
  113. #include <unistd.h>
  114. #include <sys/sysctl.h>
  115. #endif // DOCTEST_PLATFORM_MAC
  116. #ifdef DOCTEST_PLATFORM_WINDOWS
  117. // defines for a leaner windows.h
  118. #ifndef WIN32_LEAN_AND_MEAN
  119. #define WIN32_LEAN_AND_MEAN
  120. #endif // WIN32_LEAN_AND_MEAN
  121. #ifndef NOMINMAX
  122. #define NOMINMAX
  123. #endif // NOMINMAX
  124. // not sure what AfxWin.h is for - here I do what Catch does
  125. #ifdef __AFXDLL
  126. #include <AfxWin.h>
  127. #else
  128. #include <windows.h>
  129. #endif
  130. #include <io.h>
  131. #else // DOCTEST_PLATFORM_WINDOWS
  132. #include <sys/time.h>
  133. #include <unistd.h>
  134. #endif // DOCTEST_PLATFORM_WINDOWS
  135. // this is a fix for https://github.com/onqtam/doctest/issues/348
  136. // https://mail.gnome.org/archives/xml/2012-January/msg00000.html
  137. #if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO)
  138. #define STDOUT_FILENO fileno(stdout)
  139. #endif // HAVE_UNISTD_H
  140. DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
  141. // counts the number of elements in a C array
  142. #define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0]))
  143. #ifdef DOCTEST_CONFIG_DISABLE
  144. #define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_disabled
  145. #else // DOCTEST_CONFIG_DISABLE
  146. #define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_not_disabled
  147. #endif // DOCTEST_CONFIG_DISABLE
  148. #ifndef DOCTEST_CONFIG_OPTIONS_PREFIX
  149. #define DOCTEST_CONFIG_OPTIONS_PREFIX "dt-"
  150. #endif
  151. #ifndef DOCTEST_THREAD_LOCAL
  152. #define DOCTEST_THREAD_LOCAL thread_local
  153. #endif
  154. #ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES
  155. #define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32
  156. #endif
  157. #ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE
  158. #define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64
  159. #endif
  160. #ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
  161. #define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX
  162. #else
  163. #define DOCTEST_OPTIONS_PREFIX_DISPLAY ""
  164. #endif
  165. namespace doctest {
  166. bool is_running_in_test = false;
  167. namespace {
  168. using namespace detail;
  169. // case insensitive strcmp
  170. int stricmp(const char* a, const char* b) {
  171. for(;; a++, b++) {
  172. const int d = tolower(*a) - tolower(*b);
  173. if(d != 0 || !*a)
  174. return d;
  175. }
  176. }
  177. template <typename T>
  178. String fpToString(T value, int precision) {
  179. std::ostringstream oss;
  180. oss << std::setprecision(precision) << std::fixed << value;
  181. std::string d = oss.str();
  182. size_t i = d.find_last_not_of('0');
  183. if(i != std::string::npos && i != d.size() - 1) {
  184. if(d[i] == '.')
  185. i++;
  186. d = d.substr(0, i + 1);
  187. }
  188. return d.c_str();
  189. }
  190. struct Endianness
  191. {
  192. enum Arch
  193. {
  194. Big,
  195. Little
  196. };
  197. static Arch which() {
  198. int x = 1;
  199. // casting any data pointer to char* is allowed
  200. auto ptr = reinterpret_cast<char*>(&x);
  201. if(*ptr)
  202. return Little;
  203. return Big;
  204. }
  205. };
  206. } // namespace
  207. namespace detail {
  208. void my_memcpy(void* dest, const void* src, unsigned num) { memcpy(dest, src, num); }
  209. String rawMemoryToString(const void* object, unsigned size) {
  210. // Reverse order for little endian architectures
  211. int i = 0, end = static_cast<int>(size), inc = 1;
  212. if(Endianness::which() == Endianness::Little) {
  213. i = end - 1;
  214. end = inc = -1;
  215. }
  216. unsigned const char* bytes = static_cast<unsigned const char*>(object);
  217. std::ostringstream oss;
  218. oss << "0x" << std::setfill('0') << std::hex;
  219. for(; i != end; i += inc)
  220. oss << std::setw(2) << static_cast<unsigned>(bytes[i]);
  221. return oss.str().c_str();
  222. }
  223. DOCTEST_THREAD_LOCAL std::ostringstream g_oss; // NOLINT(cert-err58-cpp)
  224. std::ostream* getTlsOss() {
  225. g_oss.clear(); // there shouldn't be anything worth clearing in the flags
  226. g_oss.str(""); // the slow way of resetting a string stream
  227. //g_oss.seekp(0); // optimal reset - as seen here: https://stackoverflow.com/a/624291/3162383
  228. return &g_oss;
  229. }
  230. String getTlsOssResult() {
  231. //g_oss << std::ends; // needed - as shown here: https://stackoverflow.com/a/624291/3162383
  232. return g_oss.str().c_str();
  233. }
  234. #ifndef DOCTEST_CONFIG_DISABLE
  235. namespace timer_large_integer
  236. {
  237. #if defined(DOCTEST_PLATFORM_WINDOWS)
  238. typedef ULONGLONG type;
  239. #else // DOCTEST_PLATFORM_WINDOWS
  240. using namespace std;
  241. typedef uint64_t type;
  242. #endif // DOCTEST_PLATFORM_WINDOWS
  243. }
  244. typedef timer_large_integer::type ticks_t;
  245. #ifdef DOCTEST_CONFIG_GETCURRENTTICKS
  246. ticks_t getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); }
  247. #elif defined(DOCTEST_PLATFORM_WINDOWS)
  248. ticks_t getCurrentTicks() {
  249. static LARGE_INTEGER hz = {0}, hzo = {0};
  250. if(!hz.QuadPart) {
  251. QueryPerformanceFrequency(&hz);
  252. QueryPerformanceCounter(&hzo);
  253. }
  254. LARGE_INTEGER t;
  255. QueryPerformanceCounter(&t);
  256. return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart;
  257. }
  258. #else // DOCTEST_PLATFORM_WINDOWS
  259. ticks_t getCurrentTicks() {
  260. timeval t;
  261. gettimeofday(&t, nullptr);
  262. return static_cast<ticks_t>(t.tv_sec) * 1000000 + static_cast<ticks_t>(t.tv_usec);
  263. }
  264. #endif // DOCTEST_PLATFORM_WINDOWS
  265. struct Timer
  266. {
  267. void start() { m_ticks = getCurrentTicks(); }
  268. unsigned int getElapsedMicroseconds() const {
  269. return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
  270. }
  271. //unsigned int getElapsedMilliseconds() const {
  272. // return static_cast<unsigned int>(getElapsedMicroseconds() / 1000);
  273. //}
  274. double getElapsedSeconds() const { return static_cast<double>(getCurrentTicks() - m_ticks) / 1000000.0; }
  275. private:
  276. ticks_t m_ticks = 0;
  277. };
  278. #ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
  279. template <typename T>
  280. using AtomicOrMultiLaneAtomic = std::atomic<T>;
  281. #else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
  282. // Provides a multilane implementation of an atomic variable that supports add, sub, load,
  283. // store. Instead of using a single atomic variable, this splits up into multiple ones,
  284. // each sitting on a separate cache line. The goal is to provide a speedup when most
  285. // operations are modifying. It achieves this with two properties:
  286. //
  287. // * Multiple atomics are used, so chance of congestion from the same atomic is reduced.
  288. // * Each atomic sits on a separate cache line, so false sharing is reduced.
  289. //
  290. // The disadvantage is that there is a small overhead due to the use of TLS, and load/store
  291. // is slower because all atomics have to be accessed.
  292. template <typename T>
  293. class MultiLaneAtomic
  294. {
  295. struct CacheLineAlignedAtomic
  296. {
  297. std::atomic<T> atomic{};
  298. char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic<T>)];
  299. };
  300. CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES];
  301. static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE,
  302. "guarantee one atomic takes exactly one cache line");
  303. public:
  304. T operator++() noexcept { return fetch_add(1) + 1; }
  305. T operator++(int) noexcept { return fetch_add(1); }
  306. T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
  307. return myAtomic().fetch_add(arg, order);
  308. }
  309. T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
  310. return myAtomic().fetch_sub(arg, order);
  311. }
  312. operator T() const noexcept { return load(); }
  313. T load(std::memory_order order = std::memory_order_seq_cst) const noexcept {
  314. auto result = T();
  315. for(auto const& c : m_atomics) {
  316. result += c.atomic.load(order);
  317. }
  318. return result;
  319. }
  320. T operator=(T desired) noexcept {
  321. store(desired);
  322. return desired;
  323. }
  324. void store(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept {
  325. // first value becomes desired", all others become 0.
  326. for(auto& c : m_atomics) {
  327. c.atomic.store(desired, order);
  328. desired = {};
  329. }
  330. }
  331. private:
  332. // Each thread has a different atomic that it operates on. If more than NumLanes threads
  333. // use this, some will use the same atomic. So performance will degrate a bit, but still
  334. // everything will work.
  335. //
  336. // The logic here is a bit tricky. The call should be as fast as possible, so that there
  337. // is minimal to no overhead in determining the correct atomic for the current thread.
  338. //
  339. // 1. A global static counter laneCounter counts continuously up.
  340. // 2. Each successive thread will use modulo operation of that counter so it gets an atomic
  341. // assigned in a round-robin fashion.
  342. // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with
  343. // little overhead.
  344. std::atomic<T>& myAtomic() noexcept {
  345. static std::atomic<size_t> laneCounter;
  346. DOCTEST_THREAD_LOCAL size_t tlsLaneIdx =
  347. laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES;
  348. return m_atomics[tlsLaneIdx].atomic;
  349. }
  350. };
  351. template <typename T>
  352. using AtomicOrMultiLaneAtomic = MultiLaneAtomic<T>;
  353. #endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
  354. // this holds both parameters from the command line and runtime data for tests
  355. struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats
  356. {
  357. AtomicOrMultiLaneAtomic<int> numAssertsCurrentTest_atomic;
  358. AtomicOrMultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;
  359. std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters
  360. std::vector<IReporter*> reporters_currently_used;
  361. assert_handler ah = nullptr;
  362. Timer timer;
  363. std::vector<String> stringifiedContexts; // logging from INFO() due to an exception
  364. // stuff for subcases
  365. std::vector<SubcaseSignature> subcasesStack;
  366. std::set<decltype(subcasesStack)> subcasesPassed;
  367. int subcasesCurrentMaxLevel;
  368. bool should_reenter;
  369. std::atomic<bool> shouldLogCurrentException;
  370. void resetRunData() {
  371. numTestCases = 0;
  372. numTestCasesPassingFilters = 0;
  373. numTestSuitesPassingFilters = 0;
  374. numTestCasesFailed = 0;
  375. numAsserts = 0;
  376. numAssertsFailed = 0;
  377. numAssertsCurrentTest = 0;
  378. numAssertsFailedCurrentTest = 0;
  379. }
  380. void finalizeTestCaseData() {
  381. seconds = timer.getElapsedSeconds();
  382. // update the non-atomic counters
  383. numAsserts += numAssertsCurrentTest_atomic;
  384. numAssertsFailed += numAssertsFailedCurrentTest_atomic;
  385. numAssertsCurrentTest = numAssertsCurrentTest_atomic;
  386. numAssertsFailedCurrentTest = numAssertsFailedCurrentTest_atomic;
  387. if(numAssertsFailedCurrentTest)
  388. failure_flags |= TestCaseFailureReason::AssertFailure;
  389. if(Approx(currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 &&
  390. Approx(seconds).epsilon(DBL_EPSILON) > currentTest->m_timeout)
  391. failure_flags |= TestCaseFailureReason::Timeout;
  392. if(currentTest->m_should_fail) {
  393. if(failure_flags) {
  394. failure_flags |= TestCaseFailureReason::ShouldHaveFailedAndDid;
  395. } else {
  396. failure_flags |= TestCaseFailureReason::ShouldHaveFailedButDidnt;
  397. }
  398. } else if(failure_flags && currentTest->m_may_fail) {
  399. failure_flags |= TestCaseFailureReason::CouldHaveFailedAndDid;
  400. } else if(currentTest->m_expected_failures > 0) {
  401. if(numAssertsFailedCurrentTest == currentTest->m_expected_failures) {
  402. failure_flags |= TestCaseFailureReason::FailedExactlyNumTimes;
  403. } else {
  404. failure_flags |= TestCaseFailureReason::DidntFailExactlyNumTimes;
  405. }
  406. }
  407. bool ok_to_fail = (TestCaseFailureReason::ShouldHaveFailedAndDid & failure_flags) ||
  408. (TestCaseFailureReason::CouldHaveFailedAndDid & failure_flags) ||
  409. (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags);
  410. // if any subcase has failed - the whole test case has failed
  411. if(failure_flags && !ok_to_fail)
  412. numTestCasesFailed++;
  413. }
  414. };
  415. ContextState* g_cs = nullptr;
  416. // used to avoid locks for the debug output
  417. // TODO: figure out if this is indeed necessary/correct - seems like either there still
  418. // could be a race or that there wouldn't be a race even if using the context directly
  419. DOCTEST_THREAD_LOCAL bool g_no_colors;
  420. #endif // DOCTEST_CONFIG_DISABLE
  421. } // namespace detail
  422. void String::setOnHeap() { *reinterpret_cast<unsigned char*>(&buf[last]) = 128; }
  423. void String::setLast(unsigned in) { buf[last] = char(in); }
  424. void String::copy(const String& other) {
  425. using namespace std;
  426. if(other.isOnStack()) {
  427. memcpy(buf, other.buf, len);
  428. } else {
  429. setOnHeap();
  430. data.size = other.data.size;
  431. data.capacity = data.size + 1;
  432. data.ptr = new char[data.capacity];
  433. memcpy(data.ptr, other.data.ptr, data.size + 1);
  434. }
  435. }
  436. String::String() {
  437. buf[0] = '\0';
  438. setLast();
  439. }
  440. String::~String() {
  441. if(!isOnStack())
  442. delete[] data.ptr;
  443. // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
  444. }
  445. String::String(const char* in)
  446. : String(in, strlen(in)) {}
  447. String::String(const char* in, unsigned in_size) {
  448. using namespace std;
  449. if(in_size <= last) {
  450. memcpy(buf, in, in_size);
  451. buf[in_size] = '\0';
  452. setLast(last - in_size);
  453. } else {
  454. setOnHeap();
  455. data.size = in_size;
  456. data.capacity = data.size + 1;
  457. data.ptr = new char[data.capacity];
  458. memcpy(data.ptr, in, in_size);
  459. data.ptr[in_size] = '\0';
  460. }
  461. }
  462. String::String(const String& other) { copy(other); }
  463. String& String::operator=(const String& other) {
  464. if(this != &other) {
  465. if(!isOnStack())
  466. delete[] data.ptr;
  467. copy(other);
  468. }
  469. return *this;
  470. }
  471. String& String::operator+=(const String& other) {
  472. const unsigned my_old_size = size();
  473. const unsigned other_size = other.size();
  474. const unsigned total_size = my_old_size + other_size;
  475. using namespace std;
  476. if(isOnStack()) {
  477. if(total_size < len) {
  478. // append to the current stack space
  479. memcpy(buf + my_old_size, other.c_str(), other_size + 1);
  480. // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
  481. setLast(last - total_size);
  482. } else {
  483. // alloc new chunk
  484. char* temp = new char[total_size + 1];
  485. // copy current data to new location before writing in the union
  486. memcpy(temp, buf, my_old_size); // skip the +1 ('\0') for speed
  487. // update data in union
  488. setOnHeap();
  489. data.size = total_size;
  490. data.capacity = data.size + 1;
  491. data.ptr = temp;
  492. // transfer the rest of the data
  493. memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1);
  494. }
  495. } else {
  496. if(data.capacity > total_size) {
  497. // append to the current heap block
  498. data.size = total_size;
  499. memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1);
  500. } else {
  501. // resize
  502. data.capacity *= 2;
  503. if(data.capacity <= total_size)
  504. data.capacity = total_size + 1;
  505. // alloc new chunk
  506. char* temp = new char[data.capacity];
  507. // copy current data to new location before releasing it
  508. memcpy(temp, data.ptr, my_old_size); // skip the +1 ('\0') for speed
  509. // release old chunk
  510. delete[] data.ptr;
  511. // update the rest of the union members
  512. data.size = total_size;
  513. data.ptr = temp;
  514. // transfer the rest of the data
  515. memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1);
  516. }
  517. }
  518. return *this;
  519. }
  520. // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
  521. String String::operator+(const String& other) const { return String(*this) += other; }
  522. String::String(String&& other) {
  523. using namespace std;
  524. memcpy(buf, other.buf, len);
  525. other.buf[0] = '\0';
  526. other.setLast();
  527. }
  528. String& String::operator=(String&& other) {
  529. using namespace std;
  530. if(this != &other) {
  531. if(!isOnStack())
  532. delete[] data.ptr;
  533. memcpy(buf, other.buf, len);
  534. other.buf[0] = '\0';
  535. other.setLast();
  536. }
  537. return *this;
  538. }
  539. char String::operator[](unsigned i) const {
  540. return const_cast<String*>(this)->operator[](i); // NOLINT
  541. }
  542. char& String::operator[](unsigned i) {
  543. if(isOnStack())
  544. return reinterpret_cast<char*>(buf)[i];
  545. return data.ptr[i];
  546. }
  547. DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized")
  548. unsigned String::size() const {
  549. if(isOnStack())
  550. return last - (unsigned(buf[last]) & 31); // using "last" would work only if "len" is 32
  551. return data.size;
  552. }
  553. DOCTEST_GCC_SUPPRESS_WARNING_POP
  554. unsigned String::capacity() const {
  555. if(isOnStack())
  556. return len;
  557. return data.capacity;
  558. }
  559. int String::compare(const char* other, bool no_case) const {
  560. if(no_case)
  561. return doctest::stricmp(c_str(), other);
  562. return std::strcmp(c_str(), other);
  563. }
  564. int String::compare(const String& other, bool no_case) const {
  565. return compare(other.c_str(), no_case);
  566. }
  567. // clang-format off
  568. bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; }
  569. bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; }
  570. bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; }
  571. bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; }
  572. bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; }
  573. bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; }
  574. // clang-format on
  575. std::ostream& operator<<(std::ostream& s, const String& in) { return s << in.c_str(); }
  576. namespace {
  577. void color_to_stream(std::ostream&, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;)
  578. } // namespace
  579. namespace Color {
  580. std::ostream& operator<<(std::ostream& s, Color::Enum code) {
  581. color_to_stream(s, code);
  582. return s;
  583. }
  584. } // namespace Color
  585. // clang-format off
  586. const char* assertString(assertType::Enum at) {
  587. DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4062) // enum 'x' in switch of enum 'y' is not handled
  588. switch(at) { //!OCLINT missing default in switch statements
  589. case assertType::DT_WARN : return "WARN";
  590. case assertType::DT_CHECK : return "CHECK";
  591. case assertType::DT_REQUIRE : return "REQUIRE";
  592. case assertType::DT_WARN_FALSE : return "WARN_FALSE";
  593. case assertType::DT_CHECK_FALSE : return "CHECK_FALSE";
  594. case assertType::DT_REQUIRE_FALSE : return "REQUIRE_FALSE";
  595. case assertType::DT_WARN_THROWS : return "WARN_THROWS";
  596. case assertType::DT_CHECK_THROWS : return "CHECK_THROWS";
  597. case assertType::DT_REQUIRE_THROWS : return "REQUIRE_THROWS";
  598. case assertType::DT_WARN_THROWS_AS : return "WARN_THROWS_AS";
  599. case assertType::DT_CHECK_THROWS_AS : return "CHECK_THROWS_AS";
  600. case assertType::DT_REQUIRE_THROWS_AS : return "REQUIRE_THROWS_AS";
  601. case assertType::DT_WARN_THROWS_WITH : return "WARN_THROWS_WITH";
  602. case assertType::DT_CHECK_THROWS_WITH : return "CHECK_THROWS_WITH";
  603. case assertType::DT_REQUIRE_THROWS_WITH : return "REQUIRE_THROWS_WITH";
  604. case assertType::DT_WARN_THROWS_WITH_AS : return "WARN_THROWS_WITH_AS";
  605. case assertType::DT_CHECK_THROWS_WITH_AS : return "CHECK_THROWS_WITH_AS";
  606. case assertType::DT_REQUIRE_THROWS_WITH_AS : return "REQUIRE_THROWS_WITH_AS";
  607. case assertType::DT_WARN_NOTHROW : return "WARN_NOTHROW";
  608. case assertType::DT_CHECK_NOTHROW : return "CHECK_NOTHROW";
  609. case assertType::DT_REQUIRE_NOTHROW : return "REQUIRE_NOTHROW";
  610. case assertType::DT_WARN_EQ : return "WARN_EQ";
  611. case assertType::DT_CHECK_EQ : return "CHECK_EQ";
  612. case assertType::DT_REQUIRE_EQ : return "REQUIRE_EQ";
  613. case assertType::DT_WARN_NE : return "WARN_NE";
  614. case assertType::DT_CHECK_NE : return "CHECK_NE";
  615. case assertType::DT_REQUIRE_NE : return "REQUIRE_NE";
  616. case assertType::DT_WARN_GT : return "WARN_GT";
  617. case assertType::DT_CHECK_GT : return "CHECK_GT";
  618. case assertType::DT_REQUIRE_GT : return "REQUIRE_GT";
  619. case assertType::DT_WARN_LT : return "WARN_LT";
  620. case assertType::DT_CHECK_LT : return "CHECK_LT";
  621. case assertType::DT_REQUIRE_LT : return "REQUIRE_LT";
  622. case assertType::DT_WARN_GE : return "WARN_GE";
  623. case assertType::DT_CHECK_GE : return "CHECK_GE";
  624. case assertType::DT_REQUIRE_GE : return "REQUIRE_GE";
  625. case assertType::DT_WARN_LE : return "WARN_LE";
  626. case assertType::DT_CHECK_LE : return "CHECK_LE";
  627. case assertType::DT_REQUIRE_LE : return "REQUIRE_LE";
  628. case assertType::DT_WARN_UNARY : return "WARN_UNARY";
  629. case assertType::DT_CHECK_UNARY : return "CHECK_UNARY";
  630. case assertType::DT_REQUIRE_UNARY : return "REQUIRE_UNARY";
  631. case assertType::DT_WARN_UNARY_FALSE : return "WARN_UNARY_FALSE";
  632. case assertType::DT_CHECK_UNARY_FALSE : return "CHECK_UNARY_FALSE";
  633. case assertType::DT_REQUIRE_UNARY_FALSE : return "REQUIRE_UNARY_FALSE";
  634. }
  635. DOCTEST_MSVC_SUPPRESS_WARNING_POP
  636. return "";
  637. }
  638. // clang-format on
  639. const char* failureString(assertType::Enum at) {
  640. if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional
  641. return "WARNING";
  642. if(at & assertType::is_check) //!OCLINT bitwise operator in conditional
  643. return "ERROR";
  644. if(at & assertType::is_require) //!OCLINT bitwise operator in conditional
  645. return "FATAL ERROR";
  646. return "";
  647. }
  648. DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference")
  649. DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference")
  650. // depending on the current options this will remove the path of filenames
  651. const char* skipPathFromFilename(const char* file) {
  652. #ifndef DOCTEST_CONFIG_DISABLE
  653. if(getContextOptions()->no_path_in_filenames) {
  654. auto back = std::strrchr(file, '\\');
  655. auto forward = std::strrchr(file, '/');
  656. if(back || forward) {
  657. if(back > forward)
  658. forward = back;
  659. return forward + 1;
  660. }
  661. }
  662. #endif // DOCTEST_CONFIG_DISABLE
  663. return file;
  664. }
  665. DOCTEST_CLANG_SUPPRESS_WARNING_POP
  666. DOCTEST_GCC_SUPPRESS_WARNING_POP
  667. bool SubcaseSignature::operator<(const SubcaseSignature& other) const {
  668. if(m_line != other.m_line)
  669. return m_line < other.m_line;
  670. if(std::strcmp(m_file, other.m_file) != 0)
  671. return std::strcmp(m_file, other.m_file) < 0;
  672. return m_name.compare(other.m_name) < 0;
  673. }
  674. IContextScope::IContextScope() = default;
  675. IContextScope::~IContextScope() = default;
  676. #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
  677. String toString(char* in) { return toString(static_cast<const char*>(in)); }
  678. // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
  679. String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; }
  680. #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
  681. String toString(bool in) { return in ? "true" : "false"; }
  682. String toString(float in) { return fpToString(in, 5) + "f"; }
  683. String toString(double in) { return fpToString(in, 10); }
  684. String toString(double long in) { return fpToString(in, 15); }
  685. #define DOCTEST_TO_STRING_OVERLOAD(type, fmt) \
  686. String toString(type in) { \
  687. char buf[64]; \
  688. std::sprintf(buf, fmt, in); \
  689. return buf; \
  690. }
  691. DOCTEST_TO_STRING_OVERLOAD(char, "%d")
  692. DOCTEST_TO_STRING_OVERLOAD(char signed, "%d")
  693. DOCTEST_TO_STRING_OVERLOAD(char unsigned, "%u")
  694. DOCTEST_TO_STRING_OVERLOAD(int short, "%d")
  695. DOCTEST_TO_STRING_OVERLOAD(int short unsigned, "%u")
  696. DOCTEST_TO_STRING_OVERLOAD(int, "%d")
  697. DOCTEST_TO_STRING_OVERLOAD(unsigned, "%u")
  698. DOCTEST_TO_STRING_OVERLOAD(int long, "%ld")
  699. DOCTEST_TO_STRING_OVERLOAD(int long unsigned, "%lu")
  700. DOCTEST_TO_STRING_OVERLOAD(int long long, "%lld")
  701. DOCTEST_TO_STRING_OVERLOAD(int long long unsigned, "%llu")
  702. String toString(std::nullptr_t) { return "NULL"; }
  703. #if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
  704. // see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183
  705. String toString(const std::string& in) { return in.c_str(); }
  706. #endif // VS 2019
  707. Approx::Approx(double value)
  708. : m_epsilon(static_cast<double>(std::numeric_limits<float>::epsilon()) * 100)
  709. , m_scale(1.0)
  710. , m_value(value) {}
  711. Approx Approx::operator()(double value) const {
  712. Approx approx(value);
  713. approx.epsilon(m_epsilon);
  714. approx.scale(m_scale);
  715. return approx;
  716. }
  717. Approx& Approx::epsilon(double newEpsilon) {
  718. m_epsilon = newEpsilon;
  719. return *this;
  720. }
  721. Approx& Approx::scale(double newScale) {
  722. m_scale = newScale;
  723. return *this;
  724. }
  725. bool operator==(double lhs, const Approx& rhs) {
  726. // Thanks to Richard Harris for his help refining this formula
  727. return std::fabs(lhs - rhs.m_value) <
  728. rhs.m_epsilon * (rhs.m_scale + std::max<double>(std::fabs(lhs), std::fabs(rhs.m_value)));
  729. }
  730. bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); }
  731. bool operator!=(double lhs, const Approx& rhs) { return !operator==(lhs, rhs); }
  732. bool operator!=(const Approx& lhs, double rhs) { return !operator==(rhs, lhs); }
  733. bool operator<=(double lhs, const Approx& rhs) { return lhs < rhs.m_value || lhs == rhs; }
  734. bool operator<=(const Approx& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; }
  735. bool operator>=(double lhs, const Approx& rhs) { return lhs > rhs.m_value || lhs == rhs; }
  736. bool operator>=(const Approx& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; }
  737. bool operator<(double lhs, const Approx& rhs) { return lhs < rhs.m_value && lhs != rhs; }
  738. bool operator<(const Approx& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; }
  739. bool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs != rhs; }
  740. bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; }
  741. String toString(const Approx& in) {
  742. // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
  743. return String("Approx( ") + doctest::toString(in.m_value) + " )";
  744. }
  745. const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); }
  746. } // namespace doctest
  747. #ifdef DOCTEST_CONFIG_DISABLE
  748. namespace doctest {
  749. Context::Context(int, const char* const*) {}
  750. Context::~Context() = default;
  751. void Context::applyCommandLine(int, const char* const*) {}
  752. void Context::addFilter(const char*, const char*) {}
  753. void Context::clearFilters() {}
  754. void Context::setOption(const char*, int) {}
  755. void Context::setOption(const char*, const char*) {}
  756. bool Context::shouldExit() { return false; }
  757. void Context::setAsDefaultForAssertsOutOfTestCases() {}
  758. void Context::setAssertHandler(detail::assert_handler) {}
  759. int Context::run() { return 0; }
  760. IReporter::~IReporter() = default;
  761. int IReporter::get_num_active_contexts() { return 0; }
  762. const IContextScope* const* IReporter::get_active_contexts() { return nullptr; }
  763. int IReporter::get_num_stringified_contexts() { return 0; }
  764. const String* IReporter::get_stringified_contexts() { return nullptr; }
  765. int registerReporter(const char*, int, IReporter*) { return 0; }
  766. } // namespace doctest
  767. #else // DOCTEST_CONFIG_DISABLE
  768. #if !defined(DOCTEST_CONFIG_COLORS_NONE)
  769. #if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI)
  770. #ifdef DOCTEST_PLATFORM_WINDOWS
  771. #define DOCTEST_CONFIG_COLORS_WINDOWS
  772. #else // linux
  773. #define DOCTEST_CONFIG_COLORS_ANSI
  774. #endif // platform
  775. #endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI
  776. #endif // DOCTEST_CONFIG_COLORS_NONE
  777. namespace doctest_detail_test_suite_ns {
  778. // holds the current test suite
  779. doctest::detail::TestSuite& getCurrentTestSuite() {
  780. static doctest::detail::TestSuite data;
  781. return data;
  782. }
  783. } // namespace doctest_detail_test_suite_ns
  784. namespace doctest {
  785. namespace {
  786. // the int (priority) is part of the key for automatic sorting - sadly one can register a
  787. // reporter with a duplicate name and a different priority but hopefully that won't happen often :|
  788. typedef std::map<std::pair<int, String>, reporterCreatorFunc> reporterMap;
  789. reporterMap& getReporters() {
  790. static reporterMap data;
  791. return data;
  792. }
  793. reporterMap& getListeners() {
  794. static reporterMap data;
  795. return data;
  796. }
  797. } // namespace
  798. namespace detail {
  799. #define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...) \
  800. for(auto& curr_rep : g_cs->reporters_currently_used) \
  801. curr_rep->function(__VA_ARGS__)
  802. bool checkIfShouldThrow(assertType::Enum at) {
  803. if(at & assertType::is_require) //!OCLINT bitwise operator in conditional
  804. return true;
  805. if((at & assertType::is_check) //!OCLINT bitwise operator in conditional
  806. && getContextOptions()->abort_after > 0 &&
  807. (g_cs->numAssertsFailed + g_cs->numAssertsFailedCurrentTest_atomic) >=
  808. getContextOptions()->abort_after)
  809. return true;
  810. return false;
  811. }
  812. #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
  813. DOCTEST_NORETURN void throwException() {
  814. g_cs->shouldLogCurrentException = false;
  815. throw TestFailureException();
  816. } // NOLINT(cert-err60-cpp)
  817. #else // DOCTEST_CONFIG_NO_EXCEPTIONS
  818. void throwException() {}
  819. #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
  820. } // namespace detail
  821. namespace {
  822. using namespace detail;
  823. // matching of a string against a wildcard mask (case sensitivity configurable) taken from
  824. // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing
  825. int wildcmp(const char* str, const char* wild, bool caseSensitive) {
  826. const char* cp = str;
  827. const char* mp = wild;
  828. while((*str) && (*wild != '*')) {
  829. if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) &&
  830. (*wild != '?')) {
  831. return 0;
  832. }
  833. wild++;
  834. str++;
  835. }
  836. while(*str) {
  837. if(*wild == '*') {
  838. if(!*++wild) {
  839. return 1;
  840. }
  841. mp = wild;
  842. cp = str + 1;
  843. } else if((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) ||
  844. (*wild == '?')) {
  845. wild++;
  846. str++;
  847. } else {
  848. wild = mp; //!OCLINT parameter reassignment
  849. str = cp++; //!OCLINT parameter reassignment
  850. }
  851. }
  852. while(*wild == '*') {
  853. wild++;
  854. }
  855. return !*wild;
  856. }
  857. //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html
  858. //unsigned hashStr(unsigned const char* str) {
  859. // unsigned long hash = 5381;
  860. // char c;
  861. // while((c = *str++))
  862. // hash = ((hash << 5) + hash) + c; // hash * 33 + c
  863. // return hash;
  864. //}
  865. // checks if the name matches any of the filters (and can be configured what to do when empty)
  866. bool matchesAny(const char* name, const std::vector<String>& filters, bool matchEmpty,
  867. bool caseSensitive) {
  868. if(filters.empty() && matchEmpty)
  869. return true;
  870. for(auto& curr : filters)
  871. if(wildcmp(name, curr.c_str(), caseSensitive))
  872. return true;
  873. return false;
  874. }
  875. } // namespace
  876. namespace detail {
  877. Subcase::Subcase(const String& name, const char* file, int line)
  878. : m_signature({name, file, line}) {
  879. auto* s = g_cs;
  880. // check subcase filters
  881. if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) {
  882. if(!matchesAny(m_signature.m_name.c_str(), s->filters[6], true, s->case_sensitive))
  883. return;
  884. if(matchesAny(m_signature.m_name.c_str(), s->filters[7], false, s->case_sensitive))
  885. return;
  886. }
  887. // if a Subcase on the same level has already been entered
  888. if(s->subcasesStack.size() < size_t(s->subcasesCurrentMaxLevel)) {
  889. s->should_reenter = true;
  890. return;
  891. }
  892. // push the current signature to the stack so we can check if the
  893. // current stack + the current new subcase have been traversed
  894. s->subcasesStack.push_back(m_signature);
  895. if(s->subcasesPassed.count(s->subcasesStack) != 0) {
  896. // pop - revert to previous stack since we've already passed this
  897. s->subcasesStack.pop_back();
  898. return;
  899. }
  900. s->subcasesCurrentMaxLevel = s->subcasesStack.size();
  901. m_entered = true;
  902. DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature);
  903. }
  904. DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17
  905. DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
  906. DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
  907. Subcase::~Subcase() {
  908. if(m_entered) {
  909. // only mark the subcase stack as passed if no subcases have been skipped
  910. if(g_cs->should_reenter == false)
  911. g_cs->subcasesPassed.insert(g_cs->subcasesStack);
  912. g_cs->subcasesStack.pop_back();
  913. #if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L
  914. if(std::uncaught_exceptions() > 0
  915. #else
  916. if(std::uncaught_exception()
  917. #endif
  918. && g_cs->shouldLogCurrentException) {
  919. DOCTEST_ITERATE_THROUGH_REPORTERS(
  920. test_case_exception, {"exception thrown in subcase - will translate later "
  921. "when the whole test case has been exited (cannot "
  922. "translate while there is an active exception)",
  923. false});
  924. g_cs->shouldLogCurrentException = false;
  925. }
  926. DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY);
  927. }
  928. }
  929. DOCTEST_CLANG_SUPPRESS_WARNING_POP
  930. DOCTEST_GCC_SUPPRESS_WARNING_POP
  931. DOCTEST_MSVC_SUPPRESS_WARNING_POP
  932. Subcase::operator bool() const { return m_entered; }
  933. Result::Result(bool passed, const String& decomposition)
  934. : m_passed(passed)
  935. , m_decomp(decomposition) {}
  936. ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at)
  937. : m_at(at) {}
  938. TestSuite& TestSuite::operator*(const char* in) {
  939. m_test_suite = in;
  940. // clear state
  941. m_description = nullptr;
  942. m_skip = false;
  943. m_no_breaks = false;
  944. m_no_output = false;
  945. m_may_fail = false;
  946. m_should_fail = false;
  947. m_expected_failures = 0;
  948. m_timeout = 0;
  949. return *this;
  950. }
  951. TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite,
  952. const char* type, int template_id) {
  953. m_file = file;
  954. m_line = line;
  955. m_name = nullptr; // will be later overridden in operator*
  956. m_test_suite = test_suite.m_test_suite;
  957. m_description = test_suite.m_description;
  958. m_skip = test_suite.m_skip;
  959. m_no_breaks = test_suite.m_no_breaks;
  960. m_no_output = test_suite.m_no_output;
  961. m_may_fail = test_suite.m_may_fail;
  962. m_should_fail = test_suite.m_should_fail;
  963. m_expected_failures = test_suite.m_expected_failures;
  964. m_timeout = test_suite.m_timeout;
  965. m_test = test;
  966. m_type = type;
  967. m_template_id = template_id;
  968. }
  969. TestCase::TestCase(const TestCase& other)
  970. : TestCaseData() {
  971. *this = other;
  972. }
  973. DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function
  974. DOCTEST_MSVC_SUPPRESS_WARNING(26437) // Do not slice
  975. TestCase& TestCase::operator=(const TestCase& other) {
  976. static_cast<TestCaseData&>(*this) = static_cast<const TestCaseData&>(other);
  977. m_test = other.m_test;
  978. m_type = other.m_type;
  979. m_template_id = other.m_template_id;
  980. m_full_name = other.m_full_name;
  981. if(m_template_id != -1)
  982. m_name = m_full_name.c_str();
  983. return *this;
  984. }
  985. DOCTEST_MSVC_SUPPRESS_WARNING_POP
  986. TestCase& TestCase::operator*(const char* in) {
  987. m_name = in;
  988. // make a new name with an appended type for templated test case
  989. if(m_template_id != -1) {
  990. m_full_name = String(m_name) + m_type;
  991. // redirect the name to point to the newly constructed full name
  992. m_name = m_full_name.c_str();
  993. }
  994. return *this;
  995. }
  996. bool TestCase::operator<(const TestCase& other) const {
  997. // this will be used only to differentiate between test cases - not relevant for sorting
  998. if(m_line != other.m_line)
  999. return m_line < other.m_line;
  1000. const int name_cmp = strcmp(m_name, other.m_name);
  1001. if(name_cmp != 0)
  1002. return name_cmp < 0;
  1003. const int file_cmp = m_file.compare(other.m_file);
  1004. if(file_cmp != 0)
  1005. return file_cmp < 0;
  1006. return m_template_id < other.m_template_id;
  1007. }
  1008. } // namespace detail
  1009. namespace {
  1010. using namespace detail;
  1011. // for sorting tests by file/line
  1012. bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) {
  1013. // this is needed because MSVC gives different case for drive letters
  1014. // for __FILE__ when evaluated in a header and a source file
  1015. const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC));
  1016. if(res != 0)
  1017. return res < 0;
  1018. if(lhs->m_line != rhs->m_line)
  1019. return lhs->m_line < rhs->m_line;
  1020. return lhs->m_template_id < rhs->m_template_id;
  1021. }
  1022. // for sorting tests by suite/file/line
  1023. bool suiteOrderComparator(const TestCase* lhs, const TestCase* rhs) {
  1024. const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite);
  1025. if(res != 0)
  1026. return res < 0;
  1027. return fileOrderComparator(lhs, rhs);
  1028. }
  1029. // for sorting tests by name/suite/file/line
  1030. bool nameOrderComparator(const TestCase* lhs, const TestCase* rhs) {
  1031. const int res = std::strcmp(lhs->m_name, rhs->m_name);
  1032. if(res != 0)
  1033. return res < 0;
  1034. return suiteOrderComparator(lhs, rhs);
  1035. }
  1036. // all the registered tests
  1037. std::set<TestCase>& getRegisteredTests() {
  1038. static std::set<TestCase> data;
  1039. return data;
  1040. }
  1041. #ifdef DOCTEST_CONFIG_COLORS_WINDOWS
  1042. HANDLE g_stdoutHandle;
  1043. WORD g_origFgAttrs;
  1044. WORD g_origBgAttrs;
  1045. bool g_attrsInitted = false;
  1046. int colors_init() {
  1047. if(!g_attrsInitted) {
  1048. g_stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  1049. g_attrsInitted = true;
  1050. CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
  1051. GetConsoleScreenBufferInfo(g_stdoutHandle, &csbiInfo);
  1052. g_origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED |
  1053. BACKGROUND_BLUE | BACKGROUND_INTENSITY);
  1054. g_origBgAttrs = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED |
  1055. FOREGROUND_BLUE | FOREGROUND_INTENSITY);
  1056. }
  1057. return 0;
  1058. }
  1059. int dumy_init_console_colors = colors_init();
  1060. #endif // DOCTEST_CONFIG_COLORS_WINDOWS
  1061. DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
  1062. void color_to_stream(std::ostream& s, Color::Enum code) {
  1063. static_cast<void>(s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS
  1064. static_cast<void>(code); // for DOCTEST_CONFIG_COLORS_NONE
  1065. #ifdef DOCTEST_CONFIG_COLORS_ANSI
  1066. if(g_no_colors ||
  1067. (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false))
  1068. return;
  1069. auto col = "";
  1070. // clang-format off
  1071. switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement
  1072. case Color::Red: col = "[0;31m"; break;
  1073. case Color::Green: col = "[0;32m"; break;
  1074. case Color::Blue: col = "[0;34m"; break;
  1075. case Color::Cyan: col = "[0;36m"; break;
  1076. case Color::Yellow: col = "[0;33m"; break;
  1077. case Color::Grey: col = "[1;30m"; break;
  1078. case Color::LightGrey: col = "[0;37m"; break;
  1079. case Color::BrightRed: col = "[1;31m"; break;
  1080. case Color::BrightGreen: col = "[1;32m"; break;
  1081. case Color::BrightWhite: col = "[1;37m"; break;
  1082. case Color::Bright: // invalid
  1083. case Color::None:
  1084. case Color::White:
  1085. default: col = "[0m";
  1086. }
  1087. // clang-format on
  1088. s << "\033" << col;
  1089. #endif // DOCTEST_CONFIG_COLORS_ANSI
  1090. #ifdef DOCTEST_CONFIG_COLORS_WINDOWS
  1091. if(g_no_colors ||
  1092. (isatty(fileno(stdout)) == false && getContextOptions()->force_colors == false))
  1093. return;
  1094. #define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(g_stdoutHandle, x | g_origBgAttrs)
  1095. // clang-format off
  1096. switch (code) {
  1097. case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break;
  1098. case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break;
  1099. case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break;
  1100. case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break;
  1101. case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break;
  1102. case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break;
  1103. case Color::Grey: DOCTEST_SET_ATTR(0); break;
  1104. case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break;
  1105. case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break;
  1106. case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break;
  1107. case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break;
  1108. case Color::None:
  1109. case Color::Bright: // invalid
  1110. default: DOCTEST_SET_ATTR(g_origFgAttrs);
  1111. }
  1112. // clang-format on
  1113. #endif // DOCTEST_CONFIG_COLORS_WINDOWS
  1114. }
  1115. DOCTEST_CLANG_SUPPRESS_WARNING_POP
  1116. std::vector<const IExceptionTranslator*>& getExceptionTranslators() {
  1117. static std::vector<const IExceptionTranslator*> data;
  1118. return data;
  1119. }
  1120. String translateActiveException() {
  1121. #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
  1122. String res;
  1123. auto& translators = getExceptionTranslators();
  1124. for(auto& curr : translators)
  1125. if(curr->translate(res))
  1126. return res;
  1127. // clang-format off
  1128. DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcatch-value")
  1129. try {
  1130. throw;
  1131. } catch(std::exception& ex) {
  1132. return ex.what();
  1133. } catch(std::string& msg) {
  1134. return msg.c_str();
  1135. } catch(const char* msg) {
  1136. return msg;
  1137. } catch(...) {
  1138. return "unknown exception";
  1139. }
  1140. DOCTEST_GCC_SUPPRESS_WARNING_POP
  1141. // clang-format on
  1142. #else // DOCTEST_CONFIG_NO_EXCEPTIONS
  1143. return "";
  1144. #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
  1145. }
  1146. } // namespace
  1147. namespace detail {
  1148. // used by the macros for registering tests
  1149. int regTest(const TestCase& tc) {
  1150. getRegisteredTests().insert(tc);
  1151. return 0;
  1152. }
  1153. // sets the current test suite
  1154. int setTestSuite(const TestSuite& ts) {
  1155. doctest_detail_test_suite_ns::getCurrentTestSuite() = ts;
  1156. return 0;
  1157. }
  1158. #ifdef DOCTEST_IS_DEBUGGER_ACTIVE
  1159. bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); }
  1160. #else // DOCTEST_IS_DEBUGGER_ACTIVE
  1161. #ifdef DOCTEST_PLATFORM_LINUX
  1162. class ErrnoGuard {
  1163. public:
  1164. ErrnoGuard() : m_oldErrno(errno) {}
  1165. ~ErrnoGuard() { errno = m_oldErrno; }
  1166. private:
  1167. int m_oldErrno;
  1168. };
  1169. // See the comments in Catch2 for the reasoning behind this implementation:
  1170. // https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102
  1171. bool isDebuggerActive() {
  1172. ErrnoGuard guard;
  1173. std::ifstream in("/proc/self/status");
  1174. for(std::string line; std::getline(in, line);) {
  1175. static const int PREFIX_LEN = 11;
  1176. if(line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) {
  1177. return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
  1178. }
  1179. }
  1180. return false;
  1181. }
  1182. #elif defined(DOCTEST_PLATFORM_MAC)
  1183. // The following function is taken directly from the following technical note:
  1184. // https://developer.apple.com/library/archive/qa/qa1361/_index.html
  1185. // Returns true if the current process is being debugged (either
  1186. // running under the debugger or has a debugger attached post facto).
  1187. bool isDebuggerActive() {
  1188. int mib[4];
  1189. kinfo_proc info;
  1190. size_t size;
  1191. // Initialize the flags so that, if sysctl fails for some bizarre
  1192. // reason, we get a predictable result.
  1193. info.kp_proc.p_flag = 0;
  1194. // Initialize mib, which tells sysctl the info we want, in this case
  1195. // we're looking for information about a specific process ID.
  1196. mib[0] = CTL_KERN;
  1197. mib[1] = KERN_PROC;
  1198. mib[2] = KERN_PROC_PID;
  1199. mib[3] = getpid();
  1200. // Call sysctl.
  1201. size = sizeof(info);
  1202. if(sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) {
  1203. std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n";
  1204. return false;
  1205. }
  1206. // We're being debugged if the P_TRACED flag is set.
  1207. return ((info.kp_proc.p_flag & P_TRACED) != 0);
  1208. }
  1209. #elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__)
  1210. bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; }
  1211. #else
  1212. bool isDebuggerActive() { return false; }
  1213. #endif // Platform
  1214. #endif // DOCTEST_IS_DEBUGGER_ACTIVE
  1215. void registerExceptionTranslatorImpl(const IExceptionTranslator* et) {
  1216. if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) ==
  1217. getExceptionTranslators().end())
  1218. getExceptionTranslators().push_back(et);
  1219. }
  1220. #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
  1221. void toStream(std::ostream* s, char* in) { *s << in; }
  1222. void toStream(std::ostream* s, const char* in) { *s << in; }
  1223. #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
  1224. void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; }
  1225. void toStream(std::ostream* s, float in) { *s << in; }
  1226. void toStream(std::ostream* s, double in) { *s << in; }
  1227. void toStream(std::ostream* s, double long in) { *s << in; }
  1228. void toStream(std::ostream* s, char in) { *s << in; }
  1229. void toStream(std::ostream* s, char signed in) { *s << in; }
  1230. void toStream(std::ostream* s, char unsigned in) { *s << in; }
  1231. void toStream(std::ostream* s, int short in) { *s << in; }
  1232. void toStream(std::ostream* s, int short unsigned in) { *s << in; }
  1233. void toStream(std::ostream* s, int in) { *s << in; }
  1234. void toStream(std::ostream* s, int unsigned in) { *s << in; }
  1235. void toStream(std::ostream* s, int long in) { *s << in; }
  1236. void toStream(std::ostream* s, int long unsigned in) { *s << in; }
  1237. void toStream(std::ostream* s, int long long in) { *s << in; }
  1238. void toStream(std::ostream* s, int long long unsigned in) { *s << in; }
  1239. DOCTEST_THREAD_LOCAL std::vector<IContextScope*> g_infoContexts; // for logging with INFO()
  1240. ContextScopeBase::ContextScopeBase() {
  1241. g_infoContexts.push_back(this);
  1242. }
  1243. DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17
  1244. DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
  1245. DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
  1246. // destroy cannot be inlined into the destructor because that would mean calling stringify after
  1247. // ContextScope has been destroyed (base class destructors run after derived class destructors).
  1248. // Instead, ContextScope calls this method directly from its destructor.
  1249. void ContextScopeBase::destroy() {
  1250. #if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L
  1251. if(std::uncaught_exceptions() > 0) {
  1252. #else
  1253. if(std::uncaught_exception()) {
  1254. #endif
  1255. std::ostringstream s;
  1256. this->stringify(&s);
  1257. g_cs->stringifiedContexts.push_back(s.str().c_str());
  1258. }
  1259. g_infoContexts.pop_back();
  1260. }
  1261. DOCTEST_CLANG_SUPPRESS_WARNING_POP
  1262. DOCTEST_GCC_SUPPRESS_WARNING_POP
  1263. DOCTEST_MSVC_SUPPRESS_WARNING_POP
  1264. } // namespace detail
  1265. namespace {
  1266. using namespace detail;
  1267. #if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH)
  1268. struct FatalConditionHandler
  1269. {
  1270. void reset() {}
  1271. };
  1272. #else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
  1273. void reportFatal(const std::string&);
  1274. #ifdef DOCTEST_PLATFORM_WINDOWS
  1275. struct SignalDefs
  1276. {
  1277. DWORD id;
  1278. const char* name;
  1279. };
  1280. // There is no 1-1 mapping between signals and windows exceptions.
  1281. // Windows can easily distinguish between SO and SigSegV,
  1282. // but SigInt, SigTerm, etc are handled differently.
  1283. SignalDefs signalDefs[] = {
  1284. {static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION),
  1285. "SIGILL - Illegal instruction signal"},
  1286. {static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow"},
  1287. {static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION),
  1288. "SIGSEGV - Segmentation violation signal"},
  1289. {static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error"},
  1290. };
  1291. struct FatalConditionHandler
  1292. {
  1293. static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) {
  1294. // Multiple threads may enter this filter/handler at once. We want the error message to be printed on the
  1295. // console just once no matter how many threads have crashed.
  1296. static std::mutex mutex;
  1297. static bool execute = true;
  1298. {
  1299. std::lock_guard<std::mutex> lock(mutex);
  1300. if(execute) {
  1301. bool reported = false;
  1302. for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
  1303. if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
  1304. reportFatal(signalDefs[i].name);
  1305. reported = true;
  1306. break;
  1307. }
  1308. }
  1309. if(reported == false)
  1310. reportFatal("Unhandled SEH exception caught");
  1311. if(isDebuggerActive() && !g_cs->no_breaks)
  1312. DOCTEST_BREAK_INTO_DEBUGGER();
  1313. }
  1314. execute = false;
  1315. }
  1316. std::exit(EXIT_FAILURE);
  1317. }
  1318. FatalConditionHandler() {
  1319. isSet = true;
  1320. // 32k seems enough for doctest to handle stack overflow,
  1321. // but the value was found experimentally, so there is no strong guarantee
  1322. guaranteeSize = 32 * 1024;
  1323. // Register an unhandled exception filter
  1324. previousTop = SetUnhandledExceptionFilter(handleException);
  1325. // Pass in guarantee size to be filled
  1326. SetThreadStackGuarantee(&guaranteeSize);
  1327. // On Windows uncaught exceptions from another thread, exceptions from
  1328. // destructors, or calls to std::terminate are not a SEH exception
  1329. // The terminal handler gets called when:
  1330. // - std::terminate is called FROM THE TEST RUNNER THREAD
  1331. // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD
  1332. original_terminate_handler = std::get_terminate();
  1333. std::set_terminate([]() noexcept {
  1334. reportFatal("Terminate handler called");
  1335. if(isDebuggerActive() && !g_cs->no_breaks)
  1336. DOCTEST_BREAK_INTO_DEBUGGER();
  1337. std::exit(EXIT_FAILURE); // explicitly exit - otherwise the SIGABRT handler may be called as well
  1338. });
  1339. // SIGABRT is raised when:
  1340. // - std::terminate is called FROM A DIFFERENT THREAD
  1341. // - an exception is thrown from a destructor FROM A DIFFERENT THREAD
  1342. // - an uncaught exception is thrown FROM A DIFFERENT THREAD
  1343. prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) noexcept {
  1344. if(signal == SIGABRT) {
  1345. reportFatal("SIGABRT - Abort (abnormal termination) signal");
  1346. if(isDebuggerActive() && !g_cs->no_breaks)
  1347. DOCTEST_BREAK_INTO_DEBUGGER();
  1348. std::exit(EXIT_FAILURE);
  1349. }
  1350. });
  1351. // The following settings are taken from google test, and more
  1352. // specifically from UnitTest::Run() inside of gtest.cc
  1353. // the user does not want to see pop-up dialogs about crashes
  1354. prev_error_mode_1 = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
  1355. SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
  1356. // This forces the abort message to go to stderr in all circumstances.
  1357. prev_error_mode_2 = _set_error_mode(_OUT_TO_STDERR);
  1358. // In the debug version, Visual Studio pops up a separate dialog
  1359. // offering a choice to debug the aborted program - we want to disable that.
  1360. prev_abort_behavior = _set_abort_behavior(0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
  1361. // In debug mode, the Windows CRT can crash with an assertion over invalid
  1362. // input (e.g. passing an invalid file descriptor). The default handling
  1363. // for these assertions is to pop up a dialog and wait for user input.
  1364. // Instead ask the CRT to dump such assertions to stderr non-interactively.
  1365. prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
  1366. prev_report_file = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
  1367. }
  1368. static void reset() {
  1369. if(isSet) {
  1370. // Unregister handler and restore the old guarantee
  1371. SetUnhandledExceptionFilter(previousTop);
  1372. SetThreadStackGuarantee(&guaranteeSize);
  1373. std::set_terminate(original_terminate_handler);
  1374. std::signal(SIGABRT, prev_sigabrt_handler);
  1375. SetErrorMode(prev_error_mode_1);
  1376. _set_error_mode(prev_error_mode_2);
  1377. _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
  1378. static_cast<void>(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode));
  1379. static_cast<void>(_CrtSetReportFile(_CRT_ASSERT, prev_report_file));
  1380. isSet = false;
  1381. }
  1382. }
  1383. ~FatalConditionHandler() { reset(); }
  1384. private:
  1385. static UINT prev_error_mode_1;
  1386. static int prev_error_mode_2;
  1387. static unsigned int prev_abort_behavior;
  1388. static int prev_report_mode;
  1389. static _HFILE prev_report_file;
  1390. static void (*prev_sigabrt_handler)(int);
  1391. static std::terminate_handler original_terminate_handler;
  1392. static bool isSet;
  1393. static ULONG guaranteeSize;
  1394. static LPTOP_LEVEL_EXCEPTION_FILTER previousTop;
  1395. };
  1396. UINT FatalConditionHandler::prev_error_mode_1;
  1397. int FatalConditionHandler::prev_error_mode_2;
  1398. unsigned int FatalConditionHandler::prev_abort_behavior;
  1399. int FatalConditionHandler::prev_report_mode;
  1400. _HFILE FatalConditionHandler::prev_report_file;
  1401. void (*FatalConditionHandler::prev_sigabrt_handler)(int);
  1402. std::terminate_handler FatalConditionHandler::original_terminate_handler;
  1403. bool FatalConditionHandler::isSet = false;
  1404. ULONG FatalConditionHandler::guaranteeSize = 0;
  1405. LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr;
  1406. #else // DOCTEST_PLATFORM_WINDOWS
  1407. struct SignalDefs
  1408. {
  1409. int id;
  1410. const char* name;
  1411. };
  1412. SignalDefs signalDefs[] = {{SIGINT, "SIGINT - Terminal interrupt signal"},
  1413. {SIGILL, "SIGILL - Illegal instruction signal"},
  1414. {SIGFPE, "SIGFPE - Floating point error signal"},
  1415. {SIGSEGV, "SIGSEGV - Segmentation violation signal"},
  1416. {SIGTERM, "SIGTERM - Termination request signal"},
  1417. {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}};
  1418. struct FatalConditionHandler
  1419. {
  1420. static bool isSet;
  1421. static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)];
  1422. static stack_t oldSigStack;
  1423. static char altStackMem[4 * SIGSTKSZ];
  1424. static void handleSignal(int sig) {
  1425. const char* name = "<unknown signal>";
  1426. for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
  1427. SignalDefs& def = signalDefs[i];
  1428. if(sig == def.id) {
  1429. name = def.name;
  1430. break;
  1431. }
  1432. }
  1433. reset();
  1434. reportFatal(name);
  1435. raise(sig);
  1436. }
  1437. FatalConditionHandler() {
  1438. isSet = true;
  1439. stack_t sigStack;
  1440. sigStack.ss_sp = altStackMem;
  1441. sigStack.ss_size = sizeof(altStackMem);
  1442. sigStack.ss_flags = 0;
  1443. sigaltstack(&sigStack, &oldSigStack);
  1444. struct sigaction sa = {};
  1445. sa.sa_handler = handleSignal; // NOLINT
  1446. sa.sa_flags = SA_ONSTACK;
  1447. for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
  1448. sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
  1449. }
  1450. }
  1451. ~FatalConditionHandler() { reset(); }
  1452. static void reset() {
  1453. if(isSet) {
  1454. // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
  1455. for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
  1456. sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
  1457. }
  1458. // Return the old stack
  1459. sigaltstack(&oldSigStack, nullptr);
  1460. isSet = false;
  1461. }
  1462. }
  1463. };
  1464. bool FatalConditionHandler::isSet = false;
  1465. struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {};
  1466. stack_t FatalConditionHandler::oldSigStack = {};
  1467. char FatalConditionHandler::altStackMem[] = {};
  1468. #endif // DOCTEST_PLATFORM_WINDOWS
  1469. #endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
  1470. } // namespace
  1471. namespace {
  1472. using namespace detail;
  1473. #ifdef DOCTEST_PLATFORM_WINDOWS
  1474. #define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text)
  1475. #else
  1476. // TODO: integration with XCode and other IDEs
  1477. #define DOCTEST_OUTPUT_DEBUG_STRING(text) // NOLINT(clang-diagnostic-unused-macros)
  1478. #endif // Platform
  1479. void addAssert(assertType::Enum at) {
  1480. if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional
  1481. g_cs->numAssertsCurrentTest_atomic++;
  1482. }
  1483. void addFailedAssert(assertType::Enum at) {
  1484. if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional
  1485. g_cs->numAssertsFailedCurrentTest_atomic++;
  1486. }
  1487. #if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH)
  1488. void reportFatal(const std::string& message) {
  1489. g_cs->failure_flags |= TestCaseFailureReason::Crash;
  1490. DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true});
  1491. while(g_cs->subcasesStack.size()) {
  1492. g_cs->subcasesStack.pop_back();
  1493. DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY);
  1494. }
  1495. g_cs->finalizeTestCaseData();
  1496. DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs);
  1497. DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs);
  1498. }
  1499. #endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
  1500. } // namespace
  1501. namespace detail {
  1502. ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr,
  1503. const char* exception_type, const char* exception_string) {
  1504. m_test_case = g_cs->currentTest;
  1505. m_at = at;
  1506. m_file = file;
  1507. m_line = line;
  1508. m_expr = expr;
  1509. m_failed = true;
  1510. m_threw = false;
  1511. m_threw_as = false;
  1512. m_exception_type = exception_type;
  1513. m_exception_string = exception_string;
  1514. #if DOCTEST_MSVC
  1515. if(m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC
  1516. ++m_expr;
  1517. #endif // MSVC
  1518. }
  1519. void ResultBuilder::setResult(const Result& res) {
  1520. m_decomp = res.m_decomp;
  1521. m_failed = !res.m_passed;
  1522. }
  1523. void ResultBuilder::translateException() {
  1524. m_threw = true;
  1525. m_exception = translateActiveException();
  1526. }
  1527. bool ResultBuilder::log() {
  1528. if(m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional
  1529. m_failed = !m_threw;
  1530. } else if((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //!OCLINT
  1531. m_failed = !m_threw_as || (m_exception != m_exception_string);
  1532. } else if(m_at & assertType::is_throws_as) { //!OCLINT bitwise operator in conditional
  1533. m_failed = !m_threw_as;
  1534. } else if(m_at & assertType::is_throws_with) { //!OCLINT bitwise operator in conditional
  1535. m_failed = m_exception != m_exception_string;
  1536. } else if(m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional
  1537. m_failed = m_threw;
  1538. }
  1539. if(m_exception.size())
  1540. m_exception = String("\"") + m_exception + "\"";
  1541. if(is_running_in_test) {
  1542. addAssert(m_at);
  1543. DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this);
  1544. if(m_failed)
  1545. addFailedAssert(m_at);
  1546. } else if(m_failed) {
  1547. failed_out_of_a_testing_context(*this);
  1548. }
  1549. return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks &&
  1550. (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
  1551. }
  1552. void ResultBuilder::react() const {
  1553. if(m_failed && checkIfShouldThrow(m_at))
  1554. throwException();
  1555. }
  1556. void failed_out_of_a_testing_context(const AssertData& ad) {
  1557. if(g_cs->ah)
  1558. g_cs->ah(ad);
  1559. else
  1560. std::abort();
  1561. }
  1562. void decomp_assert(assertType::Enum at, const char* file, int line, const char* expr,
  1563. Result result) {
  1564. bool failed = !result.m_passed;
  1565. // ###################################################################################
  1566. // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT
  1567. // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED
  1568. // ###################################################################################
  1569. DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp);
  1570. DOCTEST_ASSERT_IN_TESTS(result.m_decomp);
  1571. // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
  1572. }
  1573. MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) {
  1574. m_stream = getTlsOss();
  1575. m_file = file;
  1576. m_line = line;
  1577. m_severity = severity;
  1578. }
  1579. IExceptionTranslator::IExceptionTranslator() = default;
  1580. IExceptionTranslator::~IExceptionTranslator() = default;
  1581. bool MessageBuilder::log() {
  1582. m_string = getTlsOssResult();
  1583. DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this);
  1584. const bool isWarn = m_severity & assertType::is_warn;
  1585. // warn is just a message in this context so we don't treat it as an assert
  1586. if(!isWarn) {
  1587. addAssert(m_severity);
  1588. addFailedAssert(m_severity);
  1589. }
  1590. return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn &&
  1591. (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
  1592. }
  1593. void MessageBuilder::react() {
  1594. if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional
  1595. throwException();
  1596. }
  1597. MessageBuilder::~MessageBuilder() = default;
  1598. } // namespace detail
  1599. namespace {
  1600. using namespace detail;
  1601. template <typename Ex>
  1602. DOCTEST_NORETURN void throw_exception(Ex const& e) {
  1603. #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
  1604. throw e;
  1605. #else // DOCTEST_CONFIG_NO_EXCEPTIONS
  1606. std::cerr << "doctest will terminate because it needed to throw an exception.\n"
  1607. << "The message was: " << e.what() << '\n';
  1608. std::terminate();
  1609. #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
  1610. }
  1611. #ifndef DOCTEST_INTERNAL_ERROR
  1612. #define DOCTEST_INTERNAL_ERROR(msg) \
  1613. throw_exception(std::logic_error( \
  1614. __FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg))
  1615. #endif // DOCTEST_INTERNAL_ERROR
  1616. // clang-format off
  1617. // =================================================================================================
  1618. // The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp
  1619. // This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched.
  1620. // =================================================================================================
  1621. class XmlEncode {
  1622. public:
  1623. enum ForWhat { ForTextNodes, ForAttributes };
  1624. XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );
  1625. void encodeTo( std::ostream& os ) const;
  1626. friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
  1627. private:
  1628. std::string m_str;
  1629. ForWhat m_forWhat;
  1630. };
  1631. class XmlWriter {
  1632. public:
  1633. class ScopedElement {
  1634. public:
  1635. ScopedElement( XmlWriter* writer );
  1636. ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT;
  1637. ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT;
  1638. ~ScopedElement();
  1639. ScopedElement& writeText( std::string const& text, bool indent = true );
  1640. template<typename T>
  1641. ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
  1642. m_writer->writeAttribute( name, attribute );
  1643. return *this;
  1644. }
  1645. private:
  1646. mutable XmlWriter* m_writer = nullptr;
  1647. };
  1648. XmlWriter( std::ostream& os = std::cout );
  1649. ~XmlWriter();
  1650. XmlWriter( XmlWriter const& ) = delete;
  1651. XmlWriter& operator=( XmlWriter const& ) = delete;
  1652. XmlWriter& startElement( std::string const& name );
  1653. ScopedElement scopedElement( std::string const& name );
  1654. XmlWriter& endElement();
  1655. XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
  1656. XmlWriter& writeAttribute( std::string const& name, const char* attribute );
  1657. XmlWriter& writeAttribute( std::string const& name, bool attribute );
  1658. template<typename T>
  1659. XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
  1660. std::stringstream rss;
  1661. rss << attribute;
  1662. return writeAttribute( name, rss.str() );
  1663. }
  1664. XmlWriter& writeText( std::string const& text, bool indent = true );
  1665. //XmlWriter& writeComment( std::string const& text );
  1666. //void writeStylesheetRef( std::string const& url );
  1667. //XmlWriter& writeBlankLine();
  1668. void ensureTagClosed();
  1669. private:
  1670. void writeDeclaration();
  1671. void newlineIfNecessary();
  1672. bool m_tagIsOpen = false;
  1673. bool m_needsNewline = false;
  1674. std::vector<std::string> m_tags;
  1675. std::string m_indent;
  1676. std::ostream& m_os;
  1677. };
  1678. // =================================================================================================
  1679. // The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp
  1680. // This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched.
  1681. // =================================================================================================
  1682. using uchar = unsigned char;
  1683. namespace {
  1684. size_t trailingBytes(unsigned char c) {
  1685. if ((c & 0xE0) == 0xC0) {
  1686. return 2;
  1687. }
  1688. if ((c & 0xF0) == 0xE0) {
  1689. return 3;
  1690. }
  1691. if ((c & 0xF8) == 0xF0) {
  1692. return 4;
  1693. }
  1694. DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
  1695. }
  1696. uint32_t headerValue(unsigned char c) {
  1697. if ((c & 0xE0) == 0xC0) {
  1698. return c & 0x1F;
  1699. }
  1700. if ((c & 0xF0) == 0xE0) {
  1701. return c & 0x0F;
  1702. }
  1703. if ((c & 0xF8) == 0xF0) {
  1704. return c & 0x07;
  1705. }
  1706. DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
  1707. }
  1708. void hexEscapeChar(std::ostream& os, unsigned char c) {
  1709. std::ios_base::fmtflags f(os.flags());
  1710. os << "\\x"
  1711. << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
  1712. << static_cast<int>(c);
  1713. os.flags(f);
  1714. }
  1715. } // anonymous namespace
  1716. XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
  1717. : m_str( str ),
  1718. m_forWhat( forWhat )
  1719. {}
  1720. void XmlEncode::encodeTo( std::ostream& os ) const {
  1721. // Apostrophe escaping not necessary if we always use " to write attributes
  1722. // (see: https://www.w3.org/TR/xml/#syntax)
  1723. for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
  1724. uchar c = m_str[idx];
  1725. switch (c) {
  1726. case '<': os << "&lt;"; break;
  1727. case '&': os << "&amp;"; break;
  1728. case '>':
  1729. // See: https://www.w3.org/TR/xml/#syntax
  1730. if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
  1731. os << "&gt;";
  1732. else
  1733. os << c;
  1734. break;
  1735. case '\"':
  1736. if (m_forWhat == ForAttributes)
  1737. os << "&quot;";
  1738. else
  1739. os << c;
  1740. break;
  1741. default:
  1742. // Check for control characters and invalid utf-8
  1743. // Escape control characters in standard ascii
  1744. // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
  1745. if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
  1746. hexEscapeChar(os, c);
  1747. break;
  1748. }
  1749. // Plain ASCII: Write it to stream
  1750. if (c < 0x7F) {
  1751. os << c;
  1752. break;
  1753. }
  1754. // UTF-8 territory
  1755. // Check if the encoding is valid and if it is not, hex escape bytes.
  1756. // Important: We do not check the exact decoded values for validity, only the encoding format
  1757. // First check that this bytes is a valid lead byte:
  1758. // This means that it is not encoded as 1111 1XXX
  1759. // Or as 10XX XXXX
  1760. if (c < 0xC0 ||
  1761. c >= 0xF8) {
  1762. hexEscapeChar(os, c);
  1763. break;
  1764. }
  1765. auto encBytes = trailingBytes(c);
  1766. // Are there enough bytes left to avoid accessing out-of-bounds memory?
  1767. if (idx + encBytes - 1 >= m_str.size()) {
  1768. hexEscapeChar(os, c);
  1769. break;
  1770. }
  1771. // The header is valid, check data
  1772. // The next encBytes bytes must together be a valid utf-8
  1773. // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
  1774. bool valid = true;
  1775. uint32_t value = headerValue(c);
  1776. for (std::size_t n = 1; n < encBytes; ++n) {
  1777. uchar nc = m_str[idx + n];
  1778. valid &= ((nc & 0xC0) == 0x80);
  1779. value = (value << 6) | (nc & 0x3F);
  1780. }
  1781. if (
  1782. // Wrong bit pattern of following bytes
  1783. (!valid) ||
  1784. // Overlong encodings
  1785. (value < 0x80) ||
  1786. ( value < 0x800 && encBytes > 2) || // removed "0x80 <= value &&" because redundant
  1787. (0x800 < value && value < 0x10000 && encBytes > 3) ||
  1788. // Encoded value out of range
  1789. (value >= 0x110000)
  1790. ) {
  1791. hexEscapeChar(os, c);
  1792. break;
  1793. }
  1794. // If we got here, this is in fact a valid(ish) utf-8 sequence
  1795. for (std::size_t n = 0; n < encBytes; ++n) {
  1796. os << m_str[idx + n];
  1797. }
  1798. idx += encBytes - 1;
  1799. break;
  1800. }
  1801. }
  1802. }
  1803. std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
  1804. xmlEncode.encodeTo( os );
  1805. return os;
  1806. }
  1807. XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
  1808. : m_writer( writer )
  1809. {}
  1810. XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT
  1811. : m_writer( other.m_writer ){
  1812. other.m_writer = nullptr;
  1813. }
  1814. XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT {
  1815. if ( m_writer ) {
  1816. m_writer->endElement();
  1817. }
  1818. m_writer = other.m_writer;
  1819. other.m_writer = nullptr;
  1820. return *this;
  1821. }
  1822. XmlWriter::ScopedElement::~ScopedElement() {
  1823. if( m_writer )
  1824. m_writer->endElement();
  1825. }
  1826. XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
  1827. m_writer->writeText( text, indent );
  1828. return *this;
  1829. }
  1830. XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
  1831. {
  1832. writeDeclaration();
  1833. }
  1834. XmlWriter::~XmlWriter() {
  1835. while( !m_tags.empty() )
  1836. endElement();
  1837. }
  1838. XmlWriter& XmlWriter::startElement( std::string const& name ) {
  1839. ensureTagClosed();
  1840. newlineIfNecessary();
  1841. m_os << m_indent << '<' << name;
  1842. m_tags.push_back( name );
  1843. m_indent += " ";
  1844. m_tagIsOpen = true;
  1845. return *this;
  1846. }
  1847. XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
  1848. ScopedElement scoped( this );
  1849. startElement( name );
  1850. return scoped;
  1851. }
  1852. XmlWriter& XmlWriter::endElement() {
  1853. newlineIfNecessary();
  1854. m_indent = m_indent.substr( 0, m_indent.size()-2 );
  1855. if( m_tagIsOpen ) {
  1856. m_os << "/>";
  1857. m_tagIsOpen = false;
  1858. }
  1859. else {
  1860. m_os << m_indent << "</" << m_tags.back() << ">";
  1861. }
  1862. m_os << std::endl;
  1863. m_tags.pop_back();
  1864. return *this;
  1865. }
  1866. XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {
  1867. if( !name.empty() && !attribute.empty() )
  1868. m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
  1869. return *this;
  1870. }
  1871. XmlWriter& XmlWriter::writeAttribute( std::string const& name, const char* attribute ) {
  1872. if( !name.empty() && attribute && attribute[0] != '\0' )
  1873. m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
  1874. return *this;
  1875. }
  1876. XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {
  1877. m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
  1878. return *this;
  1879. }
  1880. XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
  1881. if( !text.empty() ){
  1882. bool tagWasOpen = m_tagIsOpen;
  1883. ensureTagClosed();
  1884. if( tagWasOpen && indent )
  1885. m_os << m_indent;
  1886. m_os << XmlEncode( text );
  1887. m_needsNewline = true;
  1888. }
  1889. return *this;
  1890. }
  1891. //XmlWriter& XmlWriter::writeComment( std::string const& text ) {
  1892. // ensureTagClosed();
  1893. // m_os << m_indent << "<!--" << text << "-->";
  1894. // m_needsNewline = true;
  1895. // return *this;
  1896. //}
  1897. //void XmlWriter::writeStylesheetRef( std::string const& url ) {
  1898. // m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
  1899. //}
  1900. //XmlWriter& XmlWriter::writeBlankLine() {
  1901. // ensureTagClosed();
  1902. // m_os << '\n';
  1903. // return *this;
  1904. //}
  1905. void XmlWriter::ensureTagClosed() {
  1906. if( m_tagIsOpen ) {
  1907. m_os << ">" << std::endl;
  1908. m_tagIsOpen = false;
  1909. }
  1910. }
  1911. void XmlWriter::writeDeclaration() {
  1912. m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
  1913. }
  1914. void XmlWriter::newlineIfNecessary() {
  1915. if( m_needsNewline ) {
  1916. m_os << std::endl;
  1917. m_needsNewline = false;
  1918. }
  1919. }
  1920. // =================================================================================================
  1921. // End of copy-pasted code from Catch
  1922. // =================================================================================================
  1923. // clang-format on
  1924. struct XmlReporter : public IReporter
  1925. {
  1926. XmlWriter xml;
  1927. std::mutex mutex;
  1928. // caching pointers/references to objects of these types - safe to do
  1929. const ContextOptions& opt;
  1930. const TestCaseData* tc = nullptr;
  1931. XmlReporter(const ContextOptions& co)
  1932. : xml(*co.cout)
  1933. , opt(co) {}
  1934. void log_contexts() {
  1935. int num_contexts = get_num_active_contexts();
  1936. if(num_contexts) {
  1937. auto contexts = get_active_contexts();
  1938. std::stringstream ss;
  1939. for(int i = 0; i < num_contexts; ++i) {
  1940. contexts[i]->stringify(&ss);
  1941. xml.scopedElement("Info").writeText(ss.str());
  1942. ss.str("");
  1943. }
  1944. }
  1945. }
  1946. unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; }
  1947. void test_case_start_impl(const TestCaseData& in) {
  1948. bool open_ts_tag = false;
  1949. if(tc != nullptr) { // we have already opened a test suite
  1950. if(std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) {
  1951. xml.endElement();
  1952. open_ts_tag = true;
  1953. }
  1954. }
  1955. else {
  1956. open_ts_tag = true; // first test case ==> first test suite
  1957. }
  1958. if(open_ts_tag) {
  1959. xml.startElement("TestSuite");
  1960. xml.writeAttribute("name", in.m_test_suite);
  1961. }
  1962. tc = &in;
  1963. xml.startElement("TestCase")
  1964. .writeAttribute("name", in.m_name)
  1965. .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str()))
  1966. .writeAttribute("line", line(in.m_line))
  1967. .writeAttribute("description", in.m_description);
  1968. if(Approx(in.m_timeout) != 0)
  1969. xml.writeAttribute("timeout", in.m_timeout);
  1970. if(in.m_may_fail)
  1971. xml.writeAttribute("may_fail", true);
  1972. if(in.m_should_fail)
  1973. xml.writeAttribute("should_fail", true);
  1974. }
  1975. // =========================================================================================
  1976. // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE
  1977. // =========================================================================================
  1978. void report_query(const QueryData& in) override {
  1979. test_run_start();
  1980. if(opt.list_reporters) {
  1981. for(auto& curr : getListeners())
  1982. xml.scopedElement("Listener")
  1983. .writeAttribute("priority", curr.first.first)
  1984. .writeAttribute("name", curr.first.second);
  1985. for(auto& curr : getReporters())
  1986. xml.scopedElement("Reporter")
  1987. .writeAttribute("priority", curr.first.first)
  1988. .writeAttribute("name", curr.first.second);
  1989. } else if(opt.count || opt.list_test_cases) {
  1990. for(unsigned i = 0; i < in.num_data; ++i) {
  1991. xml.scopedElement("TestCase").writeAttribute("name", in.data[i]->m_name)
  1992. .writeAttribute("testsuite", in.data[i]->m_test_suite)
  1993. .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str()))
  1994. .writeAttribute("line", line(in.data[i]->m_line));
  1995. }
  1996. xml.scopedElement("OverallResultsTestCases")
  1997. .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters);
  1998. } else if(opt.list_test_suites) {
  1999. for(unsigned i = 0; i < in.num_data; ++i)
  2000. xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]->m_test_suite);
  2001. xml.scopedElement("OverallResultsTestCases")
  2002. .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters);
  2003. xml.scopedElement("OverallResultsTestSuites")
  2004. .writeAttribute("unskipped", in.run_stats->numTestSuitesPassingFilters);
  2005. }
  2006. xml.endElement();
  2007. }
  2008. void test_run_start() override {
  2009. // remove .exe extension - mainly to have the same output on UNIX and Windows
  2010. std::string binary_name = skipPathFromFilename(opt.binary_name.c_str());
  2011. #ifdef DOCTEST_PLATFORM_WINDOWS
  2012. if(binary_name.rfind(".exe") != std::string::npos)
  2013. binary_name = binary_name.substr(0, binary_name.length() - 4);
  2014. #endif // DOCTEST_PLATFORM_WINDOWS
  2015. xml.startElement("doctest").writeAttribute("binary", binary_name);
  2016. if(opt.no_version == false)
  2017. xml.writeAttribute("version", DOCTEST_VERSION_STR);
  2018. // only the consequential ones (TODO: filters)
  2019. xml.scopedElement("Options")
  2020. .writeAttribute("order_by", opt.order_by.c_str())
  2021. .writeAttribute("rand_seed", opt.rand_seed)
  2022. .writeAttribute("first", opt.first)
  2023. .writeAttribute("last", opt.last)
  2024. .writeAttribute("abort_after", opt.abort_after)
  2025. .writeAttribute("subcase_filter_levels", opt.subcase_filter_levels)
  2026. .writeAttribute("case_sensitive", opt.case_sensitive)
  2027. .writeAttribute("no_throw", opt.no_throw)
  2028. .writeAttribute("no_skip", opt.no_skip);
  2029. }
  2030. void test_run_end(const TestRunStats& p) override {
  2031. if(tc) // the TestSuite tag - only if there has been at least 1 test case
  2032. xml.endElement();
  2033. xml.scopedElement("OverallResultsAsserts")
  2034. .writeAttribute("successes", p.numAsserts - p.numAssertsFailed)
  2035. .writeAttribute("failures", p.numAssertsFailed);
  2036. xml.startElement("OverallResultsTestCases")
  2037. .writeAttribute("successes",
  2038. p.numTestCasesPassingFilters - p.numTestCasesFailed)
  2039. .writeAttribute("failures", p.numTestCasesFailed);
  2040. if(opt.no_skipped_summary == false)
  2041. xml.writeAttribute("skipped", p.numTestCases - p.numTestCasesPassingFilters);
  2042. xml.endElement();
  2043. xml.endElement();
  2044. }
  2045. void test_case_start(const TestCaseData& in) override {
  2046. test_case_start_impl(in);
  2047. xml.ensureTagClosed();
  2048. }
  2049. void test_case_reenter(const TestCaseData&) override {}
  2050. void test_case_end(const CurrentTestCaseStats& st) override {
  2051. xml.startElement("OverallResultsAsserts")
  2052. .writeAttribute("successes",
  2053. st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest)
  2054. .writeAttribute("failures", st.numAssertsFailedCurrentTest);
  2055. if(opt.duration)
  2056. xml.writeAttribute("duration", st.seconds);
  2057. if(tc->m_expected_failures)
  2058. xml.writeAttribute("expected_failures", tc->m_expected_failures);
  2059. xml.endElement();
  2060. xml.endElement();
  2061. }
  2062. void test_case_exception(const TestCaseException& e) override {
  2063. std::lock_guard<std::mutex> lock(mutex);
  2064. xml.scopedElement("Exception")
  2065. .writeAttribute("crash", e.is_crash)
  2066. .writeText(e.error_string.c_str());
  2067. }
  2068. void subcase_start(const SubcaseSignature& in) override {
  2069. std::lock_guard<std::mutex> lock(mutex);
  2070. xml.startElement("SubCase")
  2071. .writeAttribute("name", in.m_name)
  2072. .writeAttribute("filename", skipPathFromFilename(in.m_file))
  2073. .writeAttribute("line", line(in.m_line));
  2074. xml.ensureTagClosed();
  2075. }
  2076. void subcase_end() override { xml.endElement(); }
  2077. void log_assert(const AssertData& rb) override {
  2078. if(!rb.m_failed && !opt.success)
  2079. return;
  2080. std::lock_guard<std::mutex> lock(mutex);
  2081. xml.startElement("Expression")
  2082. .writeAttribute("success", !rb.m_failed)
  2083. .writeAttribute("type", assertString(rb.m_at))
  2084. .writeAttribute("filename", skipPathFromFilename(rb.m_file))
  2085. .writeAttribute("line", line(rb.m_line));
  2086. xml.scopedElement("Original").writeText(rb.m_expr);
  2087. if(rb.m_threw)
  2088. xml.scopedElement("Exception").writeText(rb.m_exception.c_str());
  2089. if(rb.m_at & assertType::is_throws_as)
  2090. xml.scopedElement("ExpectedException").writeText(rb.m_exception_type);
  2091. if(rb.m_at & assertType::is_throws_with)
  2092. xml.scopedElement("ExpectedExceptionString").writeText(rb.m_exception_string);
  2093. if((rb.m_at & assertType::is_normal) && !rb.m_threw)
  2094. xml.scopedElement("Expanded").writeText(rb.m_decomp.c_str());
  2095. log_contexts();
  2096. xml.endElement();
  2097. }
  2098. void log_message(const MessageData& mb) override {
  2099. std::lock_guard<std::mutex> lock(mutex);
  2100. xml.startElement("Message")
  2101. .writeAttribute("type", failureString(mb.m_severity))
  2102. .writeAttribute("filename", skipPathFromFilename(mb.m_file))
  2103. .writeAttribute("line", line(mb.m_line));
  2104. xml.scopedElement("Text").writeText(mb.m_string.c_str());
  2105. log_contexts();
  2106. xml.endElement();
  2107. }
  2108. void test_case_skipped(const TestCaseData& in) override {
  2109. if(opt.no_skipped_summary == false) {
  2110. test_case_start_impl(in);
  2111. xml.writeAttribute("skipped", "true");
  2112. xml.endElement();
  2113. }
  2114. }
  2115. };
  2116. DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter);
  2117. void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) {
  2118. if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) ==
  2119. 0) //!OCLINT bitwise operator in conditional
  2120. s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) "
  2121. << Color::None;
  2122. if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional
  2123. s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n";
  2124. } else if((rb.m_at & assertType::is_throws_as) &&
  2125. (rb.m_at & assertType::is_throws_with)) { //!OCLINT
  2126. s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \""
  2127. << rb.m_exception_string << "\", " << rb.m_exception_type << " ) " << Color::None;
  2128. if(rb.m_threw) {
  2129. if(!rb.m_failed) {
  2130. s << "threw as expected!\n";
  2131. } else {
  2132. s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n";
  2133. }
  2134. } else {
  2135. s << "did NOT throw at all!\n";
  2136. }
  2137. } else if(rb.m_at &
  2138. assertType::is_throws_as) { //!OCLINT bitwise operator in conditional
  2139. s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", "
  2140. << rb.m_exception_type << " ) " << Color::None
  2141. << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" :
  2142. "threw a DIFFERENT exception: ") :
  2143. "did NOT throw at all!")
  2144. << Color::Cyan << rb.m_exception << "\n";
  2145. } else if(rb.m_at &
  2146. assertType::is_throws_with) { //!OCLINT bitwise operator in conditional
  2147. s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \""
  2148. << rb.m_exception_string << "\" ) " << Color::None
  2149. << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" :
  2150. "threw a DIFFERENT exception: ") :
  2151. "did NOT throw at all!")
  2152. << Color::Cyan << rb.m_exception << "\n";
  2153. } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional
  2154. s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan
  2155. << rb.m_exception << "\n";
  2156. } else {
  2157. s << (rb.m_threw ? "THREW exception: " :
  2158. (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n"));
  2159. if(rb.m_threw)
  2160. s << rb.m_exception << "\n";
  2161. else
  2162. s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n";
  2163. }
  2164. }
  2165. // TODO:
  2166. // - log_message()
  2167. // - respond to queries
  2168. // - honor remaining options
  2169. // - more attributes in tags
  2170. struct JUnitReporter : public IReporter
  2171. {
  2172. XmlWriter xml;
  2173. std::mutex mutex;
  2174. Timer timer;
  2175. std::vector<String> deepestSubcaseStackNames;
  2176. struct JUnitTestCaseData
  2177. {
  2178. static std::string getCurrentTimestamp() {
  2179. // Beware, this is not reentrant because of backward compatibility issues
  2180. // Also, UTC only, again because of backward compatibility (%z is C++11)
  2181. time_t rawtime;
  2182. std::time(&rawtime);
  2183. auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
  2184. std::tm timeInfo;
  2185. #ifdef DOCTEST_PLATFORM_WINDOWS
  2186. gmtime_s(&timeInfo, &rawtime);
  2187. #else // DOCTEST_PLATFORM_WINDOWS
  2188. gmtime_r(&rawtime, &timeInfo);
  2189. #endif // DOCTEST_PLATFORM_WINDOWS
  2190. char timeStamp[timeStampSize];
  2191. const char* const fmt = "%Y-%m-%dT%H:%M:%SZ";
  2192. std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
  2193. return std::string(timeStamp);
  2194. }
  2195. struct JUnitTestMessage
  2196. {
  2197. JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details)
  2198. : message(_message), type(_type), details(_details) {}
  2199. JUnitTestMessage(const std::string& _message, const std::string& _details)
  2200. : message(_message), type(), details(_details) {}
  2201. std::string message, type, details;
  2202. };
  2203. struct JUnitTestCase
  2204. {
  2205. JUnitTestCase(const std::string& _classname, const std::string& _name)
  2206. : classname(_classname), name(_name), time(0), failures() {}
  2207. std::string classname, name;
  2208. double time;
  2209. std::vector<JUnitTestMessage> failures, errors;
  2210. };
  2211. void add(const std::string& classname, const std::string& name) {
  2212. testcases.emplace_back(classname, name);
  2213. }
  2214. void appendSubcaseNamesToLastTestcase(std::vector<String> nameStack) {
  2215. for(auto& curr: nameStack)
  2216. if(curr.size())
  2217. testcases.back().name += std::string("/") + curr.c_str();
  2218. }
  2219. void addTime(double time) {
  2220. if(time < 1e-4)
  2221. time = 0;
  2222. testcases.back().time = time;
  2223. totalSeconds += time;
  2224. }
  2225. void addFailure(const std::string& message, const std::string& type, const std::string& details) {
  2226. testcases.back().failures.emplace_back(message, type, details);
  2227. ++totalFailures;
  2228. }
  2229. void addError(const std::string& message, const std::string& details) {
  2230. testcases.back().errors.emplace_back(message, details);
  2231. ++totalErrors;
  2232. }
  2233. std::vector<JUnitTestCase> testcases;
  2234. double totalSeconds = 0;
  2235. int totalErrors = 0, totalFailures = 0;
  2236. };
  2237. JUnitTestCaseData testCaseData;
  2238. // caching pointers/references to objects of these types - safe to do
  2239. const ContextOptions& opt;
  2240. const TestCaseData* tc = nullptr;
  2241. JUnitReporter(const ContextOptions& co)
  2242. : xml(*co.cout)
  2243. , opt(co) {}
  2244. unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; }
  2245. // =========================================================================================
  2246. // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE
  2247. // =========================================================================================
  2248. void report_query(const QueryData&) override {}
  2249. void test_run_start() override {}
  2250. void test_run_end(const TestRunStats& p) override {
  2251. // remove .exe extension - mainly to have the same output on UNIX and Windows
  2252. std::string binary_name = skipPathFromFilename(opt.binary_name.c_str());
  2253. #ifdef DOCTEST_PLATFORM_WINDOWS
  2254. if(binary_name.rfind(".exe") != std::string::npos)
  2255. binary_name = binary_name.substr(0, binary_name.length() - 4);
  2256. #endif // DOCTEST_PLATFORM_WINDOWS
  2257. xml.startElement("testsuites");
  2258. xml.startElement("testsuite").writeAttribute("name", binary_name)
  2259. .writeAttribute("errors", testCaseData.totalErrors)
  2260. .writeAttribute("failures", testCaseData.totalFailures)
  2261. .writeAttribute("tests", p.numAsserts);
  2262. if(opt.no_time_in_output == false) {
  2263. xml.writeAttribute("time", testCaseData.totalSeconds);
  2264. xml.writeAttribute("timestamp", JUnitTestCaseData::getCurrentTimestamp());
  2265. }
  2266. if(opt.no_version == false)
  2267. xml.writeAttribute("doctest_version", DOCTEST_VERSION_STR);
  2268. for(const auto& testCase : testCaseData.testcases) {
  2269. xml.startElement("testcase")
  2270. .writeAttribute("classname", testCase.classname)
  2271. .writeAttribute("name", testCase.name);
  2272. if(opt.no_time_in_output == false)
  2273. xml.writeAttribute("time", testCase.time);
  2274. // This is not ideal, but it should be enough to mimic gtest's junit output.
  2275. xml.writeAttribute("status", "run");
  2276. for(const auto& failure : testCase.failures) {
  2277. xml.scopedElement("failure")
  2278. .writeAttribute("message", failure.message)
  2279. .writeAttribute("type", failure.type)
  2280. .writeText(failure.details, false);
  2281. }
  2282. for(const auto& error : testCase.errors) {
  2283. xml.scopedElement("error")
  2284. .writeAttribute("message", error.message)
  2285. .writeText(error.details);
  2286. }
  2287. xml.endElement();
  2288. }
  2289. xml.endElement();
  2290. xml.endElement();
  2291. }
  2292. void test_case_start(const TestCaseData& in) override {
  2293. testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name);
  2294. timer.start();
  2295. }
  2296. void test_case_reenter(const TestCaseData& in) override {
  2297. testCaseData.addTime(timer.getElapsedSeconds());
  2298. testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames);
  2299. deepestSubcaseStackNames.clear();
  2300. timer.start();
  2301. testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name);
  2302. }
  2303. void test_case_end(const CurrentTestCaseStats&) override {
  2304. testCaseData.addTime(timer.getElapsedSeconds());
  2305. testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames);
  2306. deepestSubcaseStackNames.clear();
  2307. }
  2308. void test_case_exception(const TestCaseException& e) override {
  2309. std::lock_guard<std::mutex> lock(mutex);
  2310. testCaseData.addError("exception", e.error_string.c_str());
  2311. }
  2312. void subcase_start(const SubcaseSignature& in) override {
  2313. std::lock_guard<std::mutex> lock(mutex);
  2314. deepestSubcaseStackNames.push_back(in.m_name);
  2315. }
  2316. void subcase_end() override {}
  2317. void log_assert(const AssertData& rb) override {
  2318. if(!rb.m_failed) // report only failures & ignore the `success` option
  2319. return;
  2320. std::lock_guard<std::mutex> lock(mutex);
  2321. std::ostringstream os;
  2322. os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(")
  2323. << line(rb.m_line) << (opt.gnu_file_line ? ":" : "):") << std::endl;
  2324. fulltext_log_assert_to_stream(os, rb);
  2325. log_contexts(os);
  2326. testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str());
  2327. }
  2328. void log_message(const MessageData&) override {}
  2329. void test_case_skipped(const TestCaseData&) override {}
  2330. void log_contexts(std::ostringstream& s) {
  2331. int num_contexts = get_num_active_contexts();
  2332. if(num_contexts) {
  2333. auto contexts = get_active_contexts();
  2334. s << " logged: ";
  2335. for(int i = 0; i < num_contexts; ++i) {
  2336. s << (i == 0 ? "" : " ");
  2337. contexts[i]->stringify(&s);
  2338. s << std::endl;
  2339. }
  2340. }
  2341. }
  2342. };
  2343. DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter);
  2344. struct Whitespace
  2345. {
  2346. int nrSpaces;
  2347. explicit Whitespace(int nr)
  2348. : nrSpaces(nr) {}
  2349. };
  2350. std::ostream& operator<<(std::ostream& out, const Whitespace& ws) {
  2351. if(ws.nrSpaces != 0)
  2352. out << std::setw(ws.nrSpaces) << ' ';
  2353. return out;
  2354. }
  2355. struct ConsoleReporter : public IReporter
  2356. {
  2357. std::ostream& s;
  2358. bool hasLoggedCurrentTestStart;
  2359. std::vector<SubcaseSignature> subcasesStack;
  2360. size_t currentSubcaseLevel;
  2361. std::mutex mutex;
  2362. // caching pointers/references to objects of these types - safe to do
  2363. const ContextOptions& opt;
  2364. const TestCaseData* tc;
  2365. ConsoleReporter(const ContextOptions& co)
  2366. : s(*co.cout)
  2367. , opt(co) {}
  2368. ConsoleReporter(const ContextOptions& co, std::ostream& ostr)
  2369. : s(ostr)
  2370. , opt(co) {}
  2371. // =========================================================================================
  2372. // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE
  2373. // =========================================================================================
  2374. void separator_to_stream() {
  2375. s << Color::Yellow
  2376. << "==============================================================================="
  2377. "\n";
  2378. }
  2379. const char* getSuccessOrFailString(bool success, assertType::Enum at,
  2380. const char* success_str) {
  2381. if(success)
  2382. return success_str;
  2383. return failureString(at);
  2384. }
  2385. Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at) {
  2386. return success ? Color::BrightGreen :
  2387. (at & assertType::is_warn) ? Color::Yellow : Color::Red;
  2388. }
  2389. void successOrFailColoredStringToStream(bool success, assertType::Enum at,
  2390. const char* success_str = "SUCCESS") {
  2391. s << getSuccessOrFailColor(success, at)
  2392. << getSuccessOrFailString(success, at, success_str) << ": ";
  2393. }
  2394. void log_contexts() {
  2395. int num_contexts = get_num_active_contexts();
  2396. if(num_contexts) {
  2397. auto contexts = get_active_contexts();
  2398. s << Color::None << " logged: ";
  2399. for(int i = 0; i < num_contexts; ++i) {
  2400. s << (i == 0 ? "" : " ");
  2401. contexts[i]->stringify(&s);
  2402. s << "\n";
  2403. }
  2404. }
  2405. s << "\n";
  2406. }
  2407. // this was requested to be made virtual so users could override it
  2408. virtual void file_line_to_stream(const char* file, int line,
  2409. const char* tail = "") {
  2410. s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(")
  2411. << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option
  2412. << (opt.gnu_file_line ? ":" : "):") << tail;
  2413. }
  2414. void logTestStart() {
  2415. if(hasLoggedCurrentTestStart)
  2416. return;
  2417. separator_to_stream();
  2418. file_line_to_stream(tc->m_file.c_str(), tc->m_line, "\n");
  2419. if(tc->m_description)
  2420. s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n";
  2421. if(tc->m_test_suite && tc->m_test_suite[0] != '\0')
  2422. s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n";
  2423. if(strncmp(tc->m_name, " Scenario:", 11) != 0)
  2424. s << Color::Yellow << "TEST CASE: ";
  2425. s << Color::None << tc->m_name << "\n";
  2426. for(size_t i = 0; i < currentSubcaseLevel; ++i) {
  2427. if(subcasesStack[i].m_name[0] != '\0')
  2428. s << " " << subcasesStack[i].m_name << "\n";
  2429. }
  2430. if(currentSubcaseLevel != subcasesStack.size()) {
  2431. s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" << Color::None;
  2432. for(size_t i = 0; i < subcasesStack.size(); ++i) {
  2433. if(subcasesStack[i].m_name[0] != '\0')
  2434. s << " " << subcasesStack[i].m_name << "\n";
  2435. }
  2436. }
  2437. s << "\n";
  2438. hasLoggedCurrentTestStart = true;
  2439. }
  2440. void printVersion() {
  2441. if(opt.no_version == false)
  2442. s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \""
  2443. << DOCTEST_VERSION_STR << "\"\n";
  2444. }
  2445. void printIntro() {
  2446. printVersion();
  2447. s << Color::Cyan << "[doctest] " << Color::None
  2448. << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n";
  2449. }
  2450. void printHelp() {
  2451. int sizePrefixDisplay = static_cast<int>(strlen(DOCTEST_OPTIONS_PREFIX_DISPLAY));
  2452. printVersion();
  2453. // clang-format off
  2454. s << Color::Cyan << "[doctest]\n" << Color::None;
  2455. s << Color::Cyan << "[doctest] " << Color::None;
  2456. s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n";
  2457. s << Color::Cyan << "[doctest] " << Color::None;
  2458. s << "filter values: \"str1,str2,str3\" (comma separated strings)\n";
  2459. s << Color::Cyan << "[doctest]\n" << Color::None;
  2460. s << Color::Cyan << "[doctest] " << Color::None;
  2461. s << "filters use wildcards for matching strings\n";
  2462. s << Color::Cyan << "[doctest] " << Color::None;
  2463. s << "something passes a filter if any of the strings in a filter matches\n";
  2464. #ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
  2465. s << Color::Cyan << "[doctest]\n" << Color::None;
  2466. s << Color::Cyan << "[doctest] " << Color::None;
  2467. s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"" DOCTEST_CONFIG_OPTIONS_PREFIX "\" PREFIX!!!\n";
  2468. #endif
  2469. s << Color::Cyan << "[doctest]\n" << Color::None;
  2470. s << Color::Cyan << "[doctest] " << Color::None;
  2471. s << "Query flags - the program quits after them. Available:\n\n";
  2472. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "?, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "help, -" DOCTEST_OPTIONS_PREFIX_DISPLAY "h "
  2473. << Whitespace(sizePrefixDisplay*0) << "prints this message\n";
  2474. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "v, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "version "
  2475. << Whitespace(sizePrefixDisplay*1) << "prints the version\n";
  2476. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "c, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "count "
  2477. << Whitespace(sizePrefixDisplay*1) << "prints the number of matching tests\n";
  2478. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ltc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-cases "
  2479. << Whitespace(sizePrefixDisplay*1) << "lists all matching tests by name\n";
  2480. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-suites "
  2481. << Whitespace(sizePrefixDisplay*1) << "lists all matching test suites\n";
  2482. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-reporters "
  2483. << Whitespace(sizePrefixDisplay*1) << "lists all registered reporters\n\n";
  2484. // ================================================================================== << 79
  2485. s << Color::Cyan << "[doctest] " << Color::None;
  2486. s << "The available <int>/<string> options/filters are:\n\n";
  2487. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case=<filters> "
  2488. << Whitespace(sizePrefixDisplay*1) << "filters tests by their name\n";
  2489. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case-exclude=<filters> "
  2490. << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their name\n";
  2491. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file=<filters> "
  2492. << Whitespace(sizePrefixDisplay*1) << "filters tests by their file\n";
  2493. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sfe, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file-exclude=<filters> "
  2494. << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their file\n";
  2495. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite=<filters> "
  2496. << Whitespace(sizePrefixDisplay*1) << "filters tests by their test suite\n";
  2497. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tse, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite-exclude=<filters> "
  2498. << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their test suite\n";
  2499. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase=<filters> "
  2500. << Whitespace(sizePrefixDisplay*1) << "filters subcases by their name\n";
  2501. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-exclude=<filters> "
  2502. << Whitespace(sizePrefixDisplay*1) << "filters OUT subcases by their name\n";
  2503. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "r, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "reporters=<filters> "
  2504. << Whitespace(sizePrefixDisplay*1) << "reporters to use (console is default)\n";
  2505. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "o, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "out=<string> "
  2506. << Whitespace(sizePrefixDisplay*1) << "output filename\n";
  2507. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by=<string> "
  2508. << Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n";
  2509. s << Whitespace(sizePrefixDisplay*3) << " <string> - [file/suite/name/rand/none]\n";
  2510. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed=<int> "
  2511. << Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n";
  2512. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first=<int> "
  2513. << Whitespace(sizePrefixDisplay*1) << "the first test passing the filters to\n";
  2514. s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n";
  2515. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "l, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "last=<int> "
  2516. << Whitespace(sizePrefixDisplay*1) << "the last test passing the filters to\n";
  2517. s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n";
  2518. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "aa, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "abort-after=<int> "
  2519. << Whitespace(sizePrefixDisplay*1) << "stop after <int> failed assertions\n";
  2520. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "scfl,--" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-filter-levels=<int> "
  2521. << Whitespace(sizePrefixDisplay*1) << "apply filters for the first <int> levels\n";
  2522. s << Color::Cyan << "\n[doctest] " << Color::None;
  2523. s << "Bool options - can be used like flags and true is assumed. Available:\n\n";
  2524. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "s, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "success=<bool> "
  2525. << Whitespace(sizePrefixDisplay*1) << "include successful assertions in output\n";
  2526. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "cs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "case-sensitive=<bool> "
  2527. << Whitespace(sizePrefixDisplay*1) << "filters being treated as case sensitive\n";
  2528. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "e, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "exit=<bool> "
  2529. << Whitespace(sizePrefixDisplay*1) << "exits after the tests finish\n";
  2530. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "duration=<bool> "
  2531. << Whitespace(sizePrefixDisplay*1) << "prints the time duration of each test\n";
  2532. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw=<bool> "
  2533. << Whitespace(sizePrefixDisplay*1) << "skips exceptions-related assert checks\n";
  2534. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode=<bool> "
  2535. << Whitespace(sizePrefixDisplay*1) << "returns (or exits) always with success\n";
  2536. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run=<bool> "
  2537. << Whitespace(sizePrefixDisplay*1) << "skips all runtime doctest operations\n";
  2538. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version=<bool> "
  2539. << Whitespace(sizePrefixDisplay*1) << "omit the framework version in the output\n";
  2540. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors=<bool> "
  2541. << Whitespace(sizePrefixDisplay*1) << "disables colors in output\n";
  2542. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "fc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "force-colors=<bool> "
  2543. << Whitespace(sizePrefixDisplay*1) << "use colors even when not in a tty\n";
  2544. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nb, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-breaks=<bool> "
  2545. << Whitespace(sizePrefixDisplay*1) << "disables breakpoints in debuggers\n";
  2546. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ns, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-skip=<bool> "
  2547. << Whitespace(sizePrefixDisplay*1) << "don't skip test cases marked as skip\n";
  2548. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "gfl, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "gnu-file-line=<bool> "
  2549. << Whitespace(sizePrefixDisplay*1) << ":n: vs (n): for line numbers in output\n";
  2550. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "npf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-path-filenames=<bool> "
  2551. << Whitespace(sizePrefixDisplay*1) << "only filenames and no paths in output\n";
  2552. s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nln, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-line-numbers=<bool> "
  2553. << Whitespace(sizePrefixDisplay*1) << "0 instead of real line numbers in output\n";
  2554. // ================================================================================== << 79
  2555. // clang-format on
  2556. s << Color::Cyan << "\n[doctest] " << Color::None;
  2557. s << "for more information visit the project documentation\n\n";
  2558. }
  2559. void printRegisteredReporters() {
  2560. printVersion();
  2561. auto printReporters = [this] (const reporterMap& reporters, const char* type) {
  2562. if(reporters.size()) {
  2563. s << Color::Cyan << "[doctest] " << Color::None << "listing all registered " << type << "\n";
  2564. for(auto& curr : reporters)
  2565. s << "priority: " << std::setw(5) << curr.first.first
  2566. << " name: " << curr.first.second << "\n";
  2567. }
  2568. };
  2569. printReporters(getListeners(), "listeners");
  2570. printReporters(getReporters(), "reporters");
  2571. }
  2572. void list_query_results() {
  2573. separator_to_stream();
  2574. if(opt.count || opt.list_test_cases) {
  2575. s << Color::Cyan << "[doctest] " << Color::None
  2576. << "unskipped test cases passing the current filters: "
  2577. << g_cs->numTestCasesPassingFilters << "\n";
  2578. } else if(opt.list_test_suites) {
  2579. s << Color::Cyan << "[doctest] " << Color::None
  2580. << "unskipped test cases passing the current filters: "
  2581. << g_cs->numTestCasesPassingFilters << "\n";
  2582. s << Color::Cyan << "[doctest] " << Color::None
  2583. << "test suites with unskipped test cases passing the current filters: "
  2584. << g_cs->numTestSuitesPassingFilters << "\n";
  2585. }
  2586. }
  2587. // =========================================================================================
  2588. // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE
  2589. // =========================================================================================
  2590. void report_query(const QueryData& in) override {
  2591. if(opt.version) {
  2592. printVersion();
  2593. } else if(opt.help) {
  2594. printHelp();
  2595. } else if(opt.list_reporters) {
  2596. printRegisteredReporters();
  2597. } else if(opt.count || opt.list_test_cases) {
  2598. if(opt.list_test_cases) {
  2599. s << Color::Cyan << "[doctest] " << Color::None
  2600. << "listing all test case names\n";
  2601. separator_to_stream();
  2602. }
  2603. for(unsigned i = 0; i < in.num_data; ++i)
  2604. s << Color::None << in.data[i]->m_name << "\n";
  2605. separator_to_stream();
  2606. s << Color::Cyan << "[doctest] " << Color::None
  2607. << "unskipped test cases passing the current filters: "
  2608. << g_cs->numTestCasesPassingFilters << "\n";
  2609. } else if(opt.list_test_suites) {
  2610. s << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n";
  2611. separator_to_stream();
  2612. for(unsigned i = 0; i < in.num_data; ++i)
  2613. s << Color::None << in.data[i]->m_test_suite << "\n";
  2614. separator_to_stream();
  2615. s << Color::Cyan << "[doctest] " << Color::None
  2616. << "unskipped test cases passing the current filters: "
  2617. << g_cs->numTestCasesPassingFilters << "\n";
  2618. s << Color::Cyan << "[doctest] " << Color::None
  2619. << "test suites with unskipped test cases passing the current filters: "
  2620. << g_cs->numTestSuitesPassingFilters << "\n";
  2621. }
  2622. }
  2623. void test_run_start() override { printIntro(); }
  2624. void test_run_end(const TestRunStats& p) override {
  2625. separator_to_stream();
  2626. s << std::dec;
  2627. auto totwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters, static_cast<unsigned>(p.numAsserts))) + 1)));
  2628. auto passwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast<unsigned>(p.numAsserts - p.numAssertsFailed))) + 1)));
  2629. auto failwidth = int(std::ceil(log10((std::max(p.numTestCasesFailed, static_cast<unsigned>(p.numAssertsFailed))) + 1)));
  2630. const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0;
  2631. s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(totwidth)
  2632. << p.numTestCasesPassingFilters << " | "
  2633. << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None :
  2634. Color::Green)
  2635. << std::setw(passwidth) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed"
  2636. << Color::None << " | " << (p.numTestCasesFailed > 0 ? Color::Red : Color::None)
  2637. << std::setw(failwidth) << p.numTestCasesFailed << " failed" << Color::None << " |";
  2638. if(opt.no_skipped_summary == false) {
  2639. const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters;
  2640. s << " " << (numSkipped == 0 ? Color::None : Color::Yellow) << numSkipped
  2641. << " skipped" << Color::None;
  2642. }
  2643. s << "\n";
  2644. s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(totwidth)
  2645. << p.numAsserts << " | "
  2646. << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green)
  2647. << std::setw(passwidth) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None
  2648. << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth)
  2649. << p.numAssertsFailed << " failed" << Color::None << " |\n";
  2650. s << Color::Cyan << "[doctest] " << Color::None
  2651. << "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green)
  2652. << ((p.numTestCasesFailed > 0) ? "FAILURE!" : "SUCCESS!") << Color::None << std::endl;
  2653. }
  2654. void test_case_start(const TestCaseData& in) override {
  2655. hasLoggedCurrentTestStart = false;
  2656. tc = &in;
  2657. subcasesStack.clear();
  2658. currentSubcaseLevel = 0;
  2659. }
  2660. void test_case_reenter(const TestCaseData&) override {
  2661. subcasesStack.clear();
  2662. }
  2663. void test_case_end(const CurrentTestCaseStats& st) override {
  2664. if(tc->m_no_output)
  2665. return;
  2666. // log the preamble of the test case only if there is something
  2667. // else to print - something other than that an assert has failed
  2668. if(opt.duration ||
  2669. (st.failure_flags && st.failure_flags != TestCaseFailureReason::AssertFailure))
  2670. logTestStart();
  2671. if(opt.duration)
  2672. s << Color::None << std::setprecision(6) << std::fixed << st.seconds
  2673. << " s: " << tc->m_name << "\n";
  2674. if(st.failure_flags & TestCaseFailureReason::Timeout)
  2675. s << Color::Red << "Test case exceeded time limit of " << std::setprecision(6)
  2676. << std::fixed << tc->m_timeout << "!\n";
  2677. if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) {
  2678. s << Color::Red << "Should have failed but didn't! Marking it as failed!\n";
  2679. } else if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedAndDid) {
  2680. s << Color::Yellow << "Failed as expected so marking it as not failed\n";
  2681. } else if(st.failure_flags & TestCaseFailureReason::CouldHaveFailedAndDid) {
  2682. s << Color::Yellow << "Allowed to fail so marking it as not failed\n";
  2683. } else if(st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) {
  2684. s << Color::Red << "Didn't fail exactly " << tc->m_expected_failures
  2685. << " times so marking it as failed!\n";
  2686. } else if(st.failure_flags & TestCaseFailureReason::FailedExactlyNumTimes) {
  2687. s << Color::Yellow << "Failed exactly " << tc->m_expected_failures
  2688. << " times as expected so marking it as not failed!\n";
  2689. }
  2690. if(st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) {
  2691. s << Color::Red << "Aborting - too many failed asserts!\n";
  2692. }
  2693. s << Color::None; // lgtm [cpp/useless-expression]
  2694. }
  2695. void test_case_exception(const TestCaseException& e) override {
  2696. if(tc->m_no_output)
  2697. return;
  2698. logTestStart();
  2699. file_line_to_stream(tc->m_file.c_str(), tc->m_line, " ");
  2700. successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require :
  2701. assertType::is_check);
  2702. s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: ")
  2703. << Color::Cyan << e.error_string << "\n";
  2704. int num_stringified_contexts = get_num_stringified_contexts();
  2705. if(num_stringified_contexts) {
  2706. auto stringified_contexts = get_stringified_contexts();
  2707. s << Color::None << " logged: ";
  2708. for(int i = num_stringified_contexts; i > 0; --i) {
  2709. s << (i == num_stringified_contexts ? "" : " ")
  2710. << stringified_contexts[i - 1] << "\n";
  2711. }
  2712. }
  2713. s << "\n" << Color::None;
  2714. }
  2715. void subcase_start(const SubcaseSignature& subc) override {
  2716. std::lock_guard<std::mutex> lock(mutex);
  2717. subcasesStack.push_back(subc);
  2718. ++currentSubcaseLevel;
  2719. hasLoggedCurrentTestStart = false;
  2720. }
  2721. void subcase_end() override {
  2722. std::lock_guard<std::mutex> lock(mutex);
  2723. --currentSubcaseLevel;
  2724. hasLoggedCurrentTestStart = false;
  2725. }
  2726. void log_assert(const AssertData& rb) override {
  2727. if((!rb.m_failed && !opt.success) || tc->m_no_output)
  2728. return;
  2729. std::lock_guard<std::mutex> lock(mutex);
  2730. logTestStart();
  2731. file_line_to_stream(rb.m_file, rb.m_line, " ");
  2732. successOrFailColoredStringToStream(!rb.m_failed, rb.m_at);
  2733. fulltext_log_assert_to_stream(s, rb);
  2734. log_contexts();
  2735. }
  2736. void log_message(const MessageData& mb) override {
  2737. if(tc->m_no_output)
  2738. return;
  2739. std::lock_guard<std::mutex> lock(mutex);
  2740. logTestStart();
  2741. file_line_to_stream(mb.m_file, mb.m_line, " ");
  2742. s << getSuccessOrFailColor(false, mb.m_severity)
  2743. << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity,
  2744. "MESSAGE") << ": ";
  2745. s << Color::None << mb.m_string << "\n";
  2746. log_contexts();
  2747. }
  2748. void test_case_skipped(const TestCaseData&) override {}
  2749. };
  2750. DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter);
  2751. #ifdef DOCTEST_PLATFORM_WINDOWS
  2752. struct DebugOutputWindowReporter : public ConsoleReporter
  2753. {
  2754. DOCTEST_THREAD_LOCAL static std::ostringstream oss;
  2755. DebugOutputWindowReporter(const ContextOptions& co)
  2756. : ConsoleReporter(co, oss) {}
  2757. #define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg) \
  2758. void func(type arg) override { \
  2759. bool with_col = g_no_colors; \
  2760. g_no_colors = false; \
  2761. ConsoleReporter::func(arg); \
  2762. DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \
  2763. oss.str(""); \
  2764. g_no_colors = with_col; \
  2765. }
  2766. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY)
  2767. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats&, in)
  2768. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData&, in)
  2769. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData&, in)
  2770. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats&, in)
  2771. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException&, in)
  2772. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature&, in)
  2773. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY)
  2774. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_assert, const AssertData&, in)
  2775. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_message, const MessageData&, in)
  2776. DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_skipped, const TestCaseData&, in)
  2777. };
  2778. DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss;
  2779. #endif // DOCTEST_PLATFORM_WINDOWS
  2780. // the implementation of parseOption()
  2781. bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) {
  2782. // going from the end to the beginning and stopping on the first occurrence from the end
  2783. for(int i = argc; i > 0; --i) {
  2784. auto index = i - 1;
  2785. auto temp = std::strstr(argv[index], pattern);
  2786. if(temp && (value || strlen(temp) == strlen(pattern))) { //!OCLINT prefer early exits and continue
  2787. // eliminate matches in which the chars before the option are not '-'
  2788. bool noBadCharsFound = true;
  2789. auto curr = argv[index];
  2790. while(curr != temp) {
  2791. if(*curr++ != '-') {
  2792. noBadCharsFound = false;
  2793. break;
  2794. }
  2795. }
  2796. if(noBadCharsFound && argv[index][0] == '-') {
  2797. if(value) {
  2798. // parsing the value of an option
  2799. temp += strlen(pattern);
  2800. const unsigned len = strlen(temp);
  2801. if(len) {
  2802. *value = temp;
  2803. return true;
  2804. }
  2805. } else {
  2806. // just a flag - no value
  2807. return true;
  2808. }
  2809. }
  2810. }
  2811. }
  2812. return false;
  2813. }
  2814. // parses an option and returns the string after the '=' character
  2815. bool parseOption(int argc, const char* const* argv, const char* pattern, String* value = nullptr,
  2816. const String& defaultVal = String()) {
  2817. if(value)
  2818. *value = defaultVal;
  2819. #ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
  2820. // offset (normally 3 for "dt-") to skip prefix
  2821. if(parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value))
  2822. return true;
  2823. #endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
  2824. return parseOptionImpl(argc, argv, pattern, value);
  2825. }
  2826. // locates a flag on the command line
  2827. bool parseFlag(int argc, const char* const* argv, const char* pattern) {
  2828. return parseOption(argc, argv, pattern);
  2829. }
  2830. // parses a comma separated list of words after a pattern in one of the arguments in argv
  2831. bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern,
  2832. std::vector<String>& res) {
  2833. String filtersString;
  2834. if(parseOption(argc, argv, pattern, &filtersString)) {
  2835. // tokenize with "," as a separator
  2836. // cppcheck-suppress strtokCalled
  2837. DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
  2838. auto pch = std::strtok(filtersString.c_str(), ","); // modifies the string
  2839. while(pch != nullptr) {
  2840. if(strlen(pch))
  2841. res.push_back(pch);
  2842. // uses the strtok() internal state to go to the next token
  2843. // cppcheck-suppress strtokCalled
  2844. pch = std::strtok(nullptr, ",");
  2845. }
  2846. DOCTEST_CLANG_SUPPRESS_WARNING_POP
  2847. return true;
  2848. }
  2849. return false;
  2850. }
  2851. enum optionType
  2852. {
  2853. option_bool,
  2854. option_int
  2855. };
  2856. // parses an int/bool option from the command line
  2857. bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type,
  2858. int& res) {
  2859. String parsedValue;
  2860. if(!parseOption(argc, argv, pattern, &parsedValue))
  2861. return false;
  2862. if(type == 0) {
  2863. // boolean
  2864. const char positive[][5] = {"1", "true", "on", "yes"}; // 5 - strlen("true") + 1
  2865. const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1
  2866. // if the value matches any of the positive/negative possibilities
  2867. for(unsigned i = 0; i < 4; i++) {
  2868. if(parsedValue.compare(positive[i], true) == 0) {
  2869. res = 1; //!OCLINT parameter reassignment
  2870. return true;
  2871. }
  2872. if(parsedValue.compare(negative[i], true) == 0) {
  2873. res = 0; //!OCLINT parameter reassignment
  2874. return true;
  2875. }
  2876. }
  2877. } else {
  2878. // integer
  2879. // TODO: change this to use std::stoi or something else! currently it uses undefined behavior - assumes '0' on failed parse...
  2880. int theInt = std::atoi(parsedValue.c_str()); // NOLINT
  2881. if(theInt != 0) {
  2882. res = theInt; //!OCLINT parameter reassignment
  2883. return true;
  2884. }
  2885. }
  2886. return false;
  2887. }
  2888. } // namespace
  2889. Context::Context(int argc, const char* const* argv)
  2890. : p(new detail::ContextState) {
  2891. parseArgs(argc, argv, true);
  2892. if(argc)
  2893. p->binary_name = argv[0];
  2894. }
  2895. Context::~Context() {
  2896. if(g_cs == p)
  2897. g_cs = nullptr;
  2898. delete p;
  2899. }
  2900. void Context::applyCommandLine(int argc, const char* const* argv) {
  2901. parseArgs(argc, argv);
  2902. if(argc)
  2903. p->binary_name = argv[0];
  2904. }
  2905. // parses args
  2906. void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) {
  2907. using namespace detail;
  2908. // clang-format off
  2909. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file=", p->filters[0]);
  2910. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sf=", p->filters[0]);
  2911. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file-exclude=",p->filters[1]);
  2912. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sfe=", p->filters[1]);
  2913. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite=", p->filters[2]);
  2914. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ts=", p->filters[2]);
  2915. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite-exclude=", p->filters[3]);
  2916. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tse=", p->filters[3]);
  2917. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case=", p->filters[4]);
  2918. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tc=", p->filters[4]);
  2919. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case-exclude=", p->filters[5]);
  2920. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tce=", p->filters[5]);
  2921. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase=", p->filters[6]);
  2922. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sc=", p->filters[6]);
  2923. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase-exclude=", p->filters[7]);
  2924. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sce=", p->filters[7]);
  2925. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "reporters=", p->filters[8]);
  2926. parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "r=", p->filters[8]);
  2927. // clang-format on
  2928. int intRes = 0;
  2929. String strRes;
  2930. #define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \
  2931. if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \
  2932. parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \
  2933. p->var = !!intRes; \
  2934. else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \
  2935. parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \
  2936. p->var = true; \
  2937. else if(withDefaults) \
  2938. p->var = default
  2939. #define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \
  2940. if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_int, intRes) || \
  2941. parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_int, intRes)) \
  2942. p->var = intRes; \
  2943. else if(withDefaults) \
  2944. p->var = default
  2945. #define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \
  2946. if(parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", &strRes, default) || \
  2947. parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", &strRes, default) || \
  2948. withDefaults) \
  2949. p->var = strRes
  2950. // clang-format off
  2951. DOCTEST_PARSE_STR_OPTION("out", "o", out, "");
  2952. DOCTEST_PARSE_STR_OPTION("order-by", "ob", order_by, "file");
  2953. DOCTEST_PARSE_INT_OPTION("rand-seed", "rs", rand_seed, 0);
  2954. DOCTEST_PARSE_INT_OPTION("first", "f", first, 0);
  2955. DOCTEST_PARSE_INT_OPTION("last", "l", last, UINT_MAX);
  2956. DOCTEST_PARSE_INT_OPTION("abort-after", "aa", abort_after, 0);
  2957. DOCTEST_PARSE_INT_OPTION("subcase-filter-levels", "scfl", subcase_filter_levels, INT_MAX);
  2958. DOCTEST_PARSE_AS_BOOL_OR_FLAG("success", "s", success, false);
  2959. DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, false);
  2960. DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false);
  2961. DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false);
  2962. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false);
  2963. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false);
  2964. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false);
  2965. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false);
  2966. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false);
  2967. DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false);
  2968. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-breaks", "nb", no_breaks, false);
  2969. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skip", "ns", no_skip, false);
  2970. DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC));
  2971. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false);
  2972. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false);
  2973. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-debug-output", "ndo", no_debug_output, false);
  2974. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false);
  2975. DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-time-in-output", "ntio", no_time_in_output, false);
  2976. // clang-format on
  2977. if(withDefaults) {
  2978. p->help = false;
  2979. p->version = false;
  2980. p->count = false;
  2981. p->list_test_cases = false;
  2982. p->list_test_suites = false;
  2983. p->list_reporters = false;
  2984. }
  2985. if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "help") ||
  2986. parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "h") ||
  2987. parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "?")) {
  2988. p->help = true;
  2989. p->exit = true;
  2990. }
  2991. if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "version") ||
  2992. parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "v")) {
  2993. p->version = true;
  2994. p->exit = true;
  2995. }
  2996. if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "count") ||
  2997. parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "c")) {
  2998. p->count = true;
  2999. p->exit = true;
  3000. }
  3001. if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-cases") ||
  3002. parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ltc")) {
  3003. p->list_test_cases = true;
  3004. p->exit = true;
  3005. }
  3006. if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-suites") ||
  3007. parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lts")) {
  3008. p->list_test_suites = true;
  3009. p->exit = true;
  3010. }
  3011. if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-reporters") ||
  3012. parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lr")) {
  3013. p->list_reporters = true;
  3014. p->exit = true;
  3015. }
  3016. }
  3017. // allows the user to add procedurally to the filters from the command line
  3018. void Context::addFilter(const char* filter, const char* value) { setOption(filter, value); }
  3019. // allows the user to clear all filters from the command line
  3020. void Context::clearFilters() {
  3021. for(auto& curr : p->filters)
  3022. curr.clear();
  3023. }
  3024. // allows the user to override procedurally the int/bool options from the command line
  3025. void Context::setOption(const char* option, int value) {
  3026. setOption(option, toString(value).c_str());
  3027. // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
  3028. }
  3029. // allows the user to override procedurally the string options from the command line
  3030. void Context::setOption(const char* option, const char* value) {
  3031. auto argv = String("-") + option + "=" + value;
  3032. auto lvalue = argv.c_str();
  3033. parseArgs(1, &lvalue);
  3034. }
  3035. // users should query this in their main() and exit the program if true
  3036. bool Context::shouldExit() { return p->exit; }
  3037. void Context::setAsDefaultForAssertsOutOfTestCases() { g_cs = p; }
  3038. void Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; }
  3039. // the main function that does all the filtering and test running
  3040. int Context::run() {
  3041. using namespace detail;
  3042. // save the old context state in case such was setup - for using asserts out of a testing context
  3043. auto old_cs = g_cs;
  3044. // this is the current contest
  3045. g_cs = p;
  3046. is_running_in_test = true;
  3047. g_no_colors = p->no_colors;
  3048. p->resetRunData();
  3049. // stdout by default
  3050. p->cout = &std::cout;
  3051. p->cerr = &std::cerr;
  3052. // or to a file if specified
  3053. std::fstream fstr;
  3054. if(p->out.size()) {
  3055. fstr.open(p->out.c_str(), std::fstream::out);
  3056. p->cout = &fstr;
  3057. }
  3058. auto cleanup_and_return = [&]() {
  3059. if(fstr.is_open())
  3060. fstr.close();
  3061. // restore context
  3062. g_cs = old_cs;
  3063. is_running_in_test = false;
  3064. // we have to free the reporters which were allocated when the run started
  3065. for(auto& curr : p->reporters_currently_used)
  3066. delete curr;
  3067. p->reporters_currently_used.clear();
  3068. if(p->numTestCasesFailed && !p->no_exitcode)
  3069. return EXIT_FAILURE;
  3070. return EXIT_SUCCESS;
  3071. };
  3072. // setup default reporter if none is given through the command line
  3073. if(p->filters[8].empty())
  3074. p->filters[8].push_back("console");
  3075. // check to see if any of the registered reporters has been selected
  3076. for(auto& curr : getReporters()) {
  3077. if(matchesAny(curr.first.second.c_str(), p->filters[8], false, p->case_sensitive))
  3078. p->reporters_currently_used.push_back(curr.second(*g_cs));
  3079. }
  3080. // TODO: check if there is nothing in reporters_currently_used
  3081. // prepend all listeners
  3082. for(auto& curr : getListeners())
  3083. p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs));
  3084. #ifdef DOCTEST_PLATFORM_WINDOWS
  3085. if(isDebuggerActive() && p->no_debug_output == false)
  3086. p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs));
  3087. #endif // DOCTEST_PLATFORM_WINDOWS
  3088. // handle version, help and no_run
  3089. if(p->no_run || p->version || p->help || p->list_reporters) {
  3090. DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, QueryData());
  3091. return cleanup_and_return();
  3092. }
  3093. std::vector<const TestCase*> testArray;
  3094. for(auto& curr : getRegisteredTests())
  3095. testArray.push_back(&curr);
  3096. p->numTestCases = testArray.size();
  3097. // sort the collected records
  3098. if(!testArray.empty()) {
  3099. if(p->order_by.compare("file", true) == 0) {
  3100. std::sort(testArray.begin(), testArray.end(), fileOrderComparator);
  3101. } else if(p->order_by.compare("suite", true) == 0) {
  3102. std::sort(testArray.begin(), testArray.end(), suiteOrderComparator);
  3103. } else if(p->order_by.compare("name", true) == 0) {
  3104. std::sort(testArray.begin(), testArray.end(), nameOrderComparator);
  3105. } else if(p->order_by.compare("rand", true) == 0) {
  3106. std::srand(p->rand_seed);
  3107. // random_shuffle implementation
  3108. const auto first = &testArray[0];
  3109. for(size_t i = testArray.size() - 1; i > 0; --i) {
  3110. int idxToSwap = std::rand() % (i + 1); // NOLINT
  3111. const auto temp = first[i];
  3112. first[i] = first[idxToSwap];
  3113. first[idxToSwap] = temp;
  3114. }
  3115. } else if(p->order_by.compare("none", true) == 0) {
  3116. // means no sorting - beneficial for death tests which call into the executable
  3117. // with a specific test case in mind - we don't want to slow down the startup times
  3118. }
  3119. }
  3120. std::set<String> testSuitesPassingFilt;
  3121. bool query_mode = p->count || p->list_test_cases || p->list_test_suites;
  3122. std::vector<const TestCaseData*> queryResults;
  3123. if(!query_mode)
  3124. DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY);
  3125. // invoke the registered functions if they match the filter criteria (or just count them)
  3126. for(auto& curr : testArray) {
  3127. const auto& tc = *curr;
  3128. bool skip_me = false;
  3129. if(tc.m_skip && !p->no_skip)
  3130. skip_me = true;
  3131. if(!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive))
  3132. skip_me = true;
  3133. if(matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive))
  3134. skip_me = true;
  3135. if(!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive))
  3136. skip_me = true;
  3137. if(matchesAny(tc.m_test_suite, p->filters[3], false, p->case_sensitive))
  3138. skip_me = true;
  3139. if(!matchesAny(tc.m_name, p->filters[4], true, p->case_sensitive))
  3140. skip_me = true;
  3141. if(matchesAny(tc.m_name, p->filters[5], false, p->case_sensitive))
  3142. skip_me = true;
  3143. if(!skip_me)
  3144. p->numTestCasesPassingFilters++;
  3145. // skip the test if it is not in the execution range
  3146. if((p->last < p->numTestCasesPassingFilters && p->first <= p->last) ||
  3147. (p->first > p->numTestCasesPassingFilters))
  3148. skip_me = true;
  3149. if(skip_me) {
  3150. if(!query_mode)
  3151. DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_skipped, tc);
  3152. continue;
  3153. }
  3154. // do not execute the test if we are to only count the number of filter passing tests
  3155. if(p->count)
  3156. continue;
  3157. // print the name of the test and don't execute it
  3158. if(p->list_test_cases) {
  3159. queryResults.push_back(&tc);
  3160. continue;
  3161. }
  3162. // print the name of the test suite if not done already and don't execute it
  3163. if(p->list_test_suites) {
  3164. if((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\0') {
  3165. queryResults.push_back(&tc);
  3166. testSuitesPassingFilt.insert(tc.m_test_suite);
  3167. p->numTestSuitesPassingFilters++;
  3168. }
  3169. continue;
  3170. }
  3171. // execute the test if it passes all the filtering
  3172. {
  3173. p->currentTest = &tc;
  3174. p->failure_flags = TestCaseFailureReason::None;
  3175. p->seconds = 0;
  3176. // reset atomic counters
  3177. p->numAssertsFailedCurrentTest_atomic = 0;
  3178. p->numAssertsCurrentTest_atomic = 0;
  3179. p->subcasesPassed.clear();
  3180. DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc);
  3181. p->timer.start();
  3182. bool run_test = true;
  3183. do {
  3184. // reset some of the fields for subcases (except for the set of fully passed ones)
  3185. p->should_reenter = false;
  3186. p->subcasesCurrentMaxLevel = 0;
  3187. p->subcasesStack.clear();
  3188. p->shouldLogCurrentException = true;
  3189. // reset stuff for logging with INFO()
  3190. p->stringifiedContexts.clear();
  3191. #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
  3192. try {
  3193. #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
  3194. FatalConditionHandler fatalConditionHandler; // Handle signals
  3195. // execute the test
  3196. tc.m_test();
  3197. fatalConditionHandler.reset();
  3198. #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
  3199. } catch(const TestFailureException&) {
  3200. p->failure_flags |= TestCaseFailureReason::AssertFailure;
  3201. } catch(...) {
  3202. DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception,
  3203. {translateActiveException(), false});
  3204. p->failure_flags |= TestCaseFailureReason::Exception;
  3205. }
  3206. #endif // DOCTEST_CONFIG_NO_EXCEPTIONS
  3207. // exit this loop if enough assertions have failed - even if there are more subcases
  3208. if(p->abort_after > 0 &&
  3209. p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) {
  3210. run_test = false;
  3211. p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts;
  3212. }
  3213. if(p->should_reenter && run_test)
  3214. DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc);
  3215. if(!p->should_reenter)
  3216. run_test = false;
  3217. } while(run_test);
  3218. p->finalizeTestCaseData();
  3219. DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs);
  3220. p->currentTest = nullptr;
  3221. // stop executing tests if enough assertions have failed
  3222. if(p->abort_after > 0 && p->numAssertsFailed >= p->abort_after)
  3223. break;
  3224. }
  3225. }
  3226. if(!query_mode) {
  3227. DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs);
  3228. } else {
  3229. QueryData qdata;
  3230. qdata.run_stats = g_cs;
  3231. qdata.data = queryResults.data();
  3232. qdata.num_data = unsigned(queryResults.size());
  3233. DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata);
  3234. }
  3235. // see these issues on the reasoning for this:
  3236. // - https://github.com/onqtam/doctest/issues/143#issuecomment-414418903
  3237. // - https://github.com/onqtam/doctest/issues/126
  3238. auto DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS = []() DOCTEST_NOINLINE
  3239. { std::cout << std::string(); };
  3240. DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS();
  3241. return cleanup_and_return();
  3242. }
  3243. IReporter::~IReporter() = default;
  3244. int IReporter::get_num_active_contexts() { return detail::g_infoContexts.size(); }
  3245. const IContextScope* const* IReporter::get_active_contexts() {
  3246. return get_num_active_contexts() ? &detail::g_infoContexts[0] : nullptr;
  3247. }
  3248. int IReporter::get_num_stringified_contexts() { return detail::g_cs->stringifiedContexts.size(); }
  3249. const String* IReporter::get_stringified_contexts() {
  3250. return get_num_stringified_contexts() ? &detail::g_cs->stringifiedContexts[0] : nullptr;
  3251. }
  3252. namespace detail {
  3253. void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) {
  3254. if(isReporter)
  3255. getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c));
  3256. else
  3257. getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c));
  3258. }
  3259. } // namespace detail
  3260. } // namespace doctest
  3261. #endif // DOCTEST_CONFIG_DISABLE
  3262. #ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
  3263. DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182
  3264. int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); }
  3265. DOCTEST_MSVC_SUPPRESS_WARNING_POP
  3266. #endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
  3267. DOCTEST_CLANG_SUPPRESS_WARNING_POP
  3268. DOCTEST_MSVC_SUPPRESS_WARNING_POP
  3269. DOCTEST_GCC_SUPPRESS_WARNING_POP
  3270. #endif // DOCTEST_LIBRARY_IMPLEMENTATION
  3271. #endif // DOCTEST_CONFIG_IMPLEMENT