| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296 |
- /*
- * Copyright © 2013 Red Hat, Inc.
- * Copyright © 2013 Marcin Slusarz <marcin.slusarz@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- #include "config.h"
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <fnmatch.h>
- #include <getopt.h>
- #include <libudev.h>
- #include <poll.h>
- #include <signal.h>
- #include <stdarg.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/ptrace.h>
- #include <sys/resource.h>
- #include <sys/stat.h>
- #include <sys/sysinfo.h>
- #include <sys/timerfd.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <time.h>
- #include <unistd.h>
- #include "linux/input.h"
- #ifdef HAVE_LIBSYSTEMD
- #include <systemd/sd-bus.h>
- #endif
- #ifdef __FreeBSD__
- #include <termios.h>
- #endif
- #include <libevdev/libevdev.h>
- #include <linux/kd.h>
- #include <valgrind/valgrind.h>
- #include "util-backtrace.h"
- #include "util-files.h"
- #include "util-libinput.h"
- #include "util-mem.h"
- #include "builddir.h"
- #include "libinput-util.h"
- #include "litest-int.h"
- #include "litest-runner.h"
- #include "litest.h"
- #include "quirks.h"
- #define evbit(t, c) ((t) << 16U | (c & 0xffff))
- #define UDEV_RULES_D "/run/udev/rules.d"
- #define UDEV_FUZZ_OVERRIDE_RULE_FILE \
- UDEV_RULES_D \
- "/91-litest-fuzz-override-REMOVEME-XXXXXX.rules"
- #define UDEV_TEST_DEVICE_RULE_FILE \
- UDEV_RULES_D \
- "/91-litest-test-device-REMOVEME-XXXXXXX.rules"
- #define UDEV_DEVICE_GROUPS_FILE \
- UDEV_RULES_D \
- "/80-libinput-device-groups-litest-XXXXXX.rules"
- bool verbose = false;
- bool in_debugger = false;
- bool run_deviceless = false;
- static bool use_system_rules_quirks = false;
- static bool exit_first = false;
- static FILE *outfile = NULL;
- static const char *filter_test = NULL;
- static const char *filter_device = NULL;
- static const char *filter_group = NULL;
- static int filter_rangeval = INT_MIN;
- bool use_colors = false;
- struct param_filter {
- char name[64];
- char glob[64];
- };
- struct param_filter filter_params[8]; /* name=NULL terminated */
- static struct quirks_context *quirks_context;
- struct created_file {
- struct list link;
- char *path;
- };
- static void
- created_file_destroy(struct created_file *f)
- {
- list_remove(&f->link);
- free(f->path);
- free(f);
- }
- static void
- created_file_unlink(struct created_file *f)
- {
- unlink(f->path);
- rmdir(f->path);
- }
- struct suite *current_suite = NULL;
- static void
- litest_init_udev_rules(struct list *created_files_list);
- static void
- litest_remove_udev_rules(struct list *created_files_list);
- static void
- litest_print_event(struct libinput_event *event, const char *message);
- enum quirks_setup_mode {
- QUIRKS_SETUP_USE_SRCDIR,
- QUIRKS_SETUP_ONLY_DEVICE,
- QUIRKS_SETUP_FULL,
- };
- static void
- litest_setup_quirks(struct list *created_files_list, enum quirks_setup_mode mode);
- /* defined for the litest selftest */
- #ifndef LITEST_DISABLE_BACKTRACE_LOGGING
- #define litest_log(...) fprintf(stderr, __VA_ARGS__)
- #define litest_vlog(format_, args_) vfprintf(stderr, format_, args_)
- #else
- #define litest_log(...) \
- { /* __VA_ARGS__ */ \
- }
- #define litest_vlog(...) \
- { /* __VA_ARGS__ */ \
- }
- #endif
- LIBINPUT_ATTRIBUTE_PRINTF(4, 5)
- void
- _litest_checkpoint(const char *func,
- int line,
- const char *color,
- const char *format,
- ...)
- {
- char buf[1024];
- va_list args;
- va_start(args, format);
- if (verbose) {
- vsnprintf(buf, sizeof(buf), format, args);
- fprintf(stderr,
- "%s%s():%d - %s%s%s\n",
- use_colors ? ANSI_BRIGHT_BLUE : "",
- func,
- line,
- use_colors ? color : "",
- buf,
- use_colors ? ANSI_NORMAL : "");
- }
- va_end(args);
- }
- void
- litest_backtrace(const char *func)
- {
- #ifndef LITEST_DISABLE_BACKTRACE_LOGGING
- if (RUNNING_ON_VALGRIND) {
- fprintf(stderr, "Using valgrind, omitting backtrace\n");
- return;
- }
- char buf[256];
- snprintf(buf, sizeof(buf), "in %s", func);
- backtrace_print(stderr,
- use_colors,
- "in litest_backtrace",
- "in litest_runner_test_run",
- func ? buf : NULL);
- #endif
- }
- LIBINPUT_ATTRIBUTE_PRINTF(5, 6)
- __attribute__((noreturn)) void
- litest_fail_condition(const char *file,
- int line,
- const char *func,
- const char *condition,
- const char *message,
- ...)
- {
- litest_log("FAILED: %s\n", condition);
- if (message) {
- char buf[1024];
- va_list args;
- va_start(args, message);
- vsnprintf(buf, sizeof(buf), message, args);
- va_end(args);
- litest_log("%s\n", buf);
- }
- litest_log("in %s() (%s:%d)\n", func, file ? file : "???", line);
- litest_backtrace(func);
- litest_runner_abort();
- }
- __attribute__((noreturn)) void
- litest_fail_comparison_int(const char *file,
- int line,
- const char *func,
- const char *operator,
- int a,
- int b,
- const char *astr,
- const char *bstr)
- {
- litest_log("FAILED COMPARISON: %s %s %s\n", astr, operator, bstr);
- litest_log("Resolved to: %d %s %d\n", a, operator, b);
- litest_log("in %s() (%s:%d)\n", func, file, line);
- litest_backtrace(func);
- litest_runner_abort();
- }
- __attribute__((noreturn)) void
- litest_fail_comparison_double(const char *file,
- int line,
- const char *func,
- const char *operator,
- double a,
- double b,
- const char *astr,
- const char *bstr)
- {
- litest_log("FAILED COMPARISON: %s %s %s\n", astr, operator, bstr);
- litest_log("Resolved to: %.3f %s %.3f\n", a, operator, b);
- litest_log("in %s() (%s:%d)\n", func, file, line);
- litest_backtrace(func);
- litest_runner_abort();
- }
- __attribute__((noreturn)) void
- litest_fail_comparison_ptr(const char *file,
- int line,
- const char *func,
- const char *comparison)
- {
- litest_log("FAILED COMPARISON: %s\n", comparison);
- litest_log("in %s() (%s:%d)\n", func, file, line);
- litest_backtrace(func);
- litest_runner_abort();
- }
- __attribute__((noreturn)) void
- litest_fail_comparison_str(const char *file,
- int line,
- const char *func,
- const char *comparison,
- const char *operator,
- const char *astr,
- const char *bstr)
- {
- litest_log("FAILED COMPARISON: %s %s %s\n", astr, operator, bstr);
- litest_log("Resolved to: %s %s %s\n", astr, operator, bstr);
- litest_log("in %s() (%s:%d)\n", func, file, line);
- litest_backtrace(func);
- litest_runner_abort();
- }
- struct litest_parameter_value {
- size_t refcnt;
- struct list link; /* litest_parameter->values */
- struct multivalue value;
- };
- struct litest_parameter {
- size_t refcnt;
- struct list link; /* litest_parameters.params */
- char name[128];
- char type; /* One of u, i, d, c, s, b */
- struct list values; /* litest_parameter_value */
- };
- struct litest_parameters {
- size_t refcnt;
- struct list params; /* struct litest_parameter */
- };
- static struct litest_parameter_value *
- litest_parameter_value_new(void)
- {
- struct litest_parameter_value *pv = zalloc(sizeof *pv);
- list_init(&pv->link);
- pv->refcnt = 1;
- return pv;
- }
- static inline void
- litest_parameter_add_string(struct litest_parameter *p, const char *s)
- {
- assert(p->type == 's');
- struct litest_parameter_value *pv = litest_parameter_value_new();
- pv->value = multivalue_new_string(s);
- list_append(&p->values, &pv->link);
- }
- static inline void
- litest_parameter_add_char(struct litest_parameter *p, char c)
- {
- assert(p->type == 'c');
- struct litest_parameter_value *pv = litest_parameter_value_new();
- pv->value = multivalue_new_char(c);
- list_append(&p->values, &pv->link);
- }
- static inline void
- litest_parameter_add_bool(struct litest_parameter *p, bool b)
- {
- assert(p->type == 'b');
- struct litest_parameter_value *pv = litest_parameter_value_new();
- pv->value = multivalue_new_bool(b);
- list_append(&p->values, &pv->link);
- }
- static inline void
- litest_parameter_add_u32(struct litest_parameter *p, uint32_t u)
- {
- assert(p->type == 'u');
- struct litest_parameter_value *pv = litest_parameter_value_new();
- pv->value = multivalue_new_u32(u);
- list_append(&p->values, &pv->link);
- }
- static inline void
- litest_parameter_add_i32(struct litest_parameter *p, int32_t i)
- {
- assert(p->type == 'i');
- struct litest_parameter_value *pv = litest_parameter_value_new();
- pv->value = multivalue_new_i32(i);
- list_append(&p->values, &pv->link);
- }
- static void
- litest_parameter_add_double(struct litest_parameter *p, double d)
- {
- assert(p->type == 'd');
- struct litest_parameter_value *pv = litest_parameter_value_new();
- pv->value = multivalue_new_double(d);
- list_append(&p->values, &pv->link);
- }
- static inline void
- litest_parameter_add_named_i32(struct litest_parameter *p,
- const struct litest_named_i32 i)
- {
- assert(p->type == 'I');
- struct litest_parameter_value *pv = litest_parameter_value_new();
- pv->value = multivalue_new_named_i32(i.value, i.name);
- list_append(&p->values, &pv->link);
- }
- #if 0
- static struct litest_parameter_value *
- litest_parameter_value_ref(struct litest_parameter_value *pv) {
- assert(pv);
- assert(pv->refcnt > 0);
- pv->refcnt++;
- return pv;
- }
- #endif
- static struct litest_parameter_value *
- litest_parameter_value_unref(struct litest_parameter_value *pv)
- {
- if (pv) {
- assert(pv->refcnt > 0);
- if (--pv->refcnt == 0) {
- list_remove(&pv->link);
- free(pv);
- }
- }
- return NULL;
- }
- static struct litest_parameter *
- litest_parameter_new(const char *name, char type)
- {
- struct litest_parameter *p = zalloc(sizeof *p);
- switch (type) {
- case 'b':
- case 'c':
- case 'd':
- case 'i':
- case 'I':
- case 's':
- case 'u':
- break;
- default:
- assert(!"Type not yet implemented");
- }
- list_init(&p->link);
- list_init(&p->values);
- snprintf(p->name, sizeof(p->name), "%s", name);
- p->type = type;
- p->refcnt = 1;
- return p;
- }
- static struct litest_parameter *
- litest_parameter_ref(struct litest_parameter *p)
- {
- assert(p);
- assert(p->refcnt > 0);
- p->refcnt++;
- return p;
- }
- static struct litest_parameter *
- litest_parameter_unref(struct litest_parameter *p)
- {
- if (p) {
- assert(p->refcnt > 0);
- if (--p->refcnt == 0) {
- struct litest_parameter_value *pv;
- list_for_each_safe(pv, &p->values, link) {
- litest_parameter_value_unref(pv);
- }
- list_remove(&p->link);
- free(p);
- }
- }
- return NULL;
- }
- DEFINE_UNREF_CLEANUP_FUNC(litest_parameter);
- static void
- litest_parameters_add(struct litest_parameters *ps, struct litest_parameter *param)
- {
- struct litest_parameter *p;
- list_for_each(p, &ps->params, link) {
- assert(!streq(p->name, param->name));
- }
- litest_parameter_ref(param);
- list_append(&ps->params, ¶m->link);
- }
- struct litest_parameters *
- _litest_parameters_new(const char *name, ...)
- {
- struct litest_parameters *ps = zalloc(sizeof *ps);
- list_init(&ps->params);
- ps->refcnt = 1;
- va_list args;
- va_start(args, name);
- while (name) {
- char type = va_arg(args, int);
- _unref_(litest_parameter) *param = litest_parameter_new(name, type);
- if (type == 'b') {
- litest_parameter_add_bool(param, true);
- litest_parameter_add_bool(param, false);
- } else {
- unsigned int nargs = va_arg(args, unsigned int);
- for (unsigned int _ = 0; _ < nargs; _++) {
- switch (type) {
- case 'c': {
- char b = va_arg(args, int);
- litest_parameter_add_char(param, b);
- break;
- }
- case 'u': {
- uint32_t b = va_arg(args, uint32_t);
- litest_parameter_add_u32(param, b);
- break;
- }
- case 'i': {
- int32_t b = va_arg(args, int32_t);
- litest_parameter_add_i32(param, b);
- break;
- }
- case 'd': {
- double b = va_arg(args, double);
- litest_parameter_add_double(param, b);
- break;
- }
- case 's': {
- const char *s = va_arg(args, const char *);
- litest_parameter_add_string(param, s);
- break;
- }
- case 'I': {
- struct litest_named_i32 p =
- va_arg(args, struct litest_named_i32);
- litest_parameter_add_named_i32(param, p);
- break;
- }
- default:
- litest_abort_msg(
- "Unhandled parameter type '%c'",
- type);
- break;
- }
- }
- }
- litest_parameters_add(ps, param);
- name = va_arg(args, const char *);
- }
- va_end(args);
- return ps;
- }
- struct litest_parameters *
- litest_parameters_ref(struct litest_parameters *p)
- {
- assert(p);
- assert(p->refcnt > 0);
- p->refcnt++;
- return p;
- }
- struct litest_parameters *
- litest_parameters_unref(struct litest_parameters *params)
- {
- if (params) {
- assert(params->refcnt > 0);
- if (--params->refcnt == 0) {
- struct litest_parameter *p;
- list_for_each_safe(p, ¶ms->params, link) {
- litest_parameter_unref(p);
- }
- free(params);
- }
- }
- return NULL;
- }
- static inline int
- _permutate(struct litest_parameters_permutation *permutation,
- struct list *next_param,
- void *list_head,
- litest_parameters_permutation_func_t func,
- void *userdata)
- {
- if (next_param->next == list_head) {
- func(permutation, userdata);
- return 0;
- }
- struct litest_parameter_value *pv;
- struct litest_parameter *param = list_first_entry(next_param, param, link);
- list_for_each(pv, ¶m->values, link) {
- struct litest_parameters_permutation_value v = {
- .value = pv->value,
- };
- memcpy(v.name, param->name, min(sizeof(v.name), sizeof(param->name)));
- list_append(&permutation->values, &v.link);
- int rc = _permutate(permutation,
- ¶m->link,
- list_head,
- func,
- userdata);
- if (rc)
- return rc;
- list_remove(&v.link);
- }
- return 0;
- }
- /**
- * Calls the given function func with each permutation of
- * the given test parameters.
- */
- int
- litest_parameters_permutations(struct litest_parameters *params,
- litest_parameters_permutation_func_t func,
- void *userdata)
- {
- struct litest_parameters_permutation permutation;
- list_init(&permutation.values);
- return _permutate(&permutation,
- ¶ms->params,
- ¶ms->params,
- func,
- userdata);
- }
- static struct litest_device *current_device;
- struct litest_device *
- litest_current_device(void)
- {
- return current_device;
- }
- int
- _litest_dispatch(struct libinput *li, const char *func, int line)
- {
- static int dispatch_counter = 0;
- ++dispatch_counter;
- _litest_checkpoint(func,
- line,
- ANSI_MAGENTA,
- "┌──────────────────── dispatch %3d ────────────────────┐",
- dispatch_counter);
- int rc = libinput_dispatch(li);
- enum libinput_event_type type = libinput_next_event_type(li);
- const char *evtype =
- type == LIBINPUT_EVENT_NONE ? "NONE" : litest_event_type_str(type);
- _litest_checkpoint(
- func,
- line,
- ANSI_MAGENTA,
- "└──────────────────── /dispatch %3d ────────────────────┘ pending %s",
- dispatch_counter,
- evtype);
- return rc;
- }
- static void
- grab_device(struct litest_device *device, bool mode)
- {
- struct libinput *li = libinput_device_get_context(device->libinput_device);
- struct litest_context *ctx = libinput_get_user_data(li);
- _unref_(udev_device) * udev_device;
- const char *devnode;
- struct path *p;
- udev_device = libinput_device_get_udev_device(device->libinput_device);
- litest_assert_ptr_notnull(udev_device);
- devnode = udev_device_get_devnode(udev_device);
- /* Note: in some tests we create multiple devices for the same path.
- * This will only grab the first device in the list but we're using
- * list_insert() so the first device is the latest that was
- * initialized, so we should be good.
- */
- list_for_each(p, &ctx->paths, link) {
- if (streq(p->path, devnode)) {
- int rc = ioctl(p->fd, EVIOCGRAB, (void *)mode ? 1 : 0);
- litest_assert_errno_success(rc);
- return;
- }
- }
- litest_abort_msg("Failed to find device %s to %sgrab",
- devnode,
- mode ? "" : "un");
- }
- void
- litest_grab_device(struct litest_device *device)
- {
- grab_device(device, true);
- }
- void
- litest_ungrab_device(struct litest_device *device)
- {
- grab_device(device, false);
- }
- void
- litest_set_current_device(struct litest_device *device)
- {
- current_device = device;
- }
- void
- litest_generic_device_teardown(void)
- {
- litest_device_destroy(current_device);
- current_device = NULL;
- }
- static struct list devices = LIST_INIT(devices); /* struct litest_test_device */
- void
- litest_add_test_device(struct list *device)
- {
- list_append(&devices, device);
- }
- static inline void
- litest_system(const char *command)
- {
- int ret;
- ret = system(command);
- if (ret == -1) {
- litest_abort_msg("Failed to execute: %s", command);
- } else if (WIFEXITED(ret)) {
- if (WEXITSTATUS(ret))
- litest_abort_msg("'%s' failed with %d",
- command,
- WEXITSTATUS(ret));
- } else if (WIFSIGNALED(ret)) {
- litest_abort_msg("'%s' terminated with signal %d",
- command,
- WTERMSIG(ret));
- }
- }
- static void
- litest_reload_udev_rules(void)
- {
- litest_system("udevadm control --reload-rules");
- }
- static bool
- filter_for_rangeval(const struct range *range, int rangeval)
- {
- return !range || filter_rangeval == INT_MIN || filter_rangeval == rangeval;
- }
- static void
- litest_add_tcase_for_device(struct suite *suite,
- const char *funcname,
- const void *func,
- const struct litest_test_device *dev,
- const struct range *range)
- {
- const struct range no_range = range_init_empty();
- if (run_deviceless)
- return;
- if (!range)
- range = &no_range;
- int rangeval = range->lower;
- do {
- if (filter_for_rangeval(range, rangeval)) {
- struct test *t;
- t = zalloc(sizeof(*t));
- t->name = safe_strdup(funcname);
- t->devname = safe_strdup(dev->shortname);
- t->func = func;
- t->setup = dev->setup;
- t->teardown = dev->teardown ? dev->teardown
- : litest_generic_device_teardown;
- if (range)
- t->range = *range;
- t->rangeval = rangeval;
- list_append(&suite->tests, &t->node);
- }
- } while (++rangeval < range->upper);
- }
- struct permutation_userdata {
- struct suite *suite;
- const char *funcname;
- const void *func;
- const struct litest_test_device *dev;
- char devname[64]; /* set if dev == NULL */
- const struct param_filter *param_filters; /* name=NULL terminated */
- };
- static int
- permutation_func(struct litest_parameters_permutation *permutation, void *userdata)
- {
- struct permutation_userdata *data = userdata;
- struct litest_test_parameters *params = litest_test_parameters_new();
- struct litest_parameters_permutation_value *pmv;
- bool filtered = false;
- list_for_each(pmv, &permutation->values, link) {
- const struct param_filter *f = data->param_filters;
- while (!filtered && strlen(f->name)) {
- if (streq(pmv->name, f->name)) {
- _autofree_ char *s = multivalue_as_str(&pmv->value);
- if (fnmatch(f->glob, s, 0) != 0)
- filtered = true;
- }
- f++;
- }
- if (filtered)
- break;
- struct litest_test_param *tp = zalloc(sizeof *tp);
- snprintf(tp->name, sizeof(tp->name), "%s", pmv->name);
- tp->value = multivalue_copy(&pmv->value);
- list_append(¶ms->test_params, &tp->link);
- }
- if (filtered) {
- litest_test_parameters_unref(params);
- return 0;
- }
- struct test *t;
- t = zalloc(sizeof(*t));
- t->name = safe_strdup(data->funcname);
- t->func = data->func;
- if (data->dev) {
- t->devname = safe_strdup(data->dev->shortname);
- t->setup = data->dev->setup;
- t->teardown = data->dev->teardown ? data->dev->teardown
- : litest_generic_device_teardown;
- } else {
- t->devname = safe_strdup(data->devname);
- t->setup = NULL;
- t->teardown = NULL;
- }
- t->rangeval = 0;
- t->params = params;
- list_append(&data->suite->tests, &t->node);
- return 0;
- }
- static void
- litest_add_tcase_for_device_with_params(struct suite *suite,
- const char *funcname,
- const void *func,
- const struct litest_test_device *dev,
- struct litest_parameters *params)
- {
- if (run_deviceless)
- return;
- struct permutation_userdata data = {
- .suite = suite,
- .funcname = funcname,
- .func = func,
- .dev = dev,
- .param_filters = filter_params,
- };
- litest_parameters_permutations(params, permutation_func, &data);
- }
- static void
- litest_add_tcase_no_device(struct suite *suite,
- const void *func,
- const char *funcname,
- const struct range *range)
- {
- const char *test_name = funcname;
- const struct range no_range = range_init_empty();
- if (filter_device && fnmatch(filter_device, test_name, 0) != 0)
- return;
- if (run_deviceless)
- return;
- if (!range)
- range = &no_range;
- int rangeval = range->lower;
- do {
- if (filter_for_rangeval(range, rangeval)) {
- struct test *t;
- t = zalloc(sizeof(*t));
- t->name = safe_strdup(test_name);
- t->devname = safe_strdup("no device");
- t->func = func;
- if (range)
- t->range = *range;
- t->rangeval = rangeval;
- t->setup = NULL;
- t->teardown = NULL;
- list_append(&suite->tests, &t->node);
- }
- } while (++rangeval < range->upper);
- }
- static void
- litest_add_tcase_no_device_with_params(struct suite *suite,
- const void *func,
- const char *funcname,
- struct litest_parameters *params)
- {
- const char *test_name = funcname;
- if (filter_device && fnmatch(filter_device, test_name, 0) != 0)
- return;
- if (run_deviceless)
- return;
- struct permutation_userdata data = {
- .suite = suite,
- .funcname = funcname,
- .func = func,
- .param_filters = filter_params,
- };
- snprintf(data.devname, sizeof(data.devname), "no device");
- litest_parameters_permutations(params, permutation_func, &data);
- }
- static void
- litest_add_tcase_deviceless(struct suite *suite,
- const void *func,
- const char *funcname,
- const struct range *range)
- {
- const char *test_name = funcname;
- const struct range no_range = range_init_empty();
- if (filter_device && fnmatch(filter_device, test_name, 0) != 0)
- return;
- if (!range)
- range = &no_range;
- int rangeval = range->lower;
- do {
- if (filter_for_rangeval(range, rangeval)) {
- struct test *t;
- t = zalloc(sizeof(*t));
- t->deviceless = true;
- t->name = safe_strdup(test_name);
- t->devname = safe_strdup("deviceless");
- t->func = func;
- if (range)
- t->range = *range;
- t->rangeval = rangeval;
- t->setup = NULL;
- t->teardown = NULL;
- list_append(&suite->tests, &t->node);
- }
- } while (++rangeval < range->upper);
- }
- static void
- litest_add_tcase_deviceless_with_params(struct suite *suite,
- const void *func,
- const char *funcname,
- struct litest_parameters *params)
- {
- const char *test_name = funcname;
- if (filter_device && fnmatch(filter_device, test_name, 0) != 0)
- return;
- struct permutation_userdata data = {
- .suite = suite,
- .funcname = funcname,
- .func = func,
- .param_filters = filter_params,
- };
- snprintf(data.devname, sizeof(data.devname), "deviceless");
- litest_parameters_permutations(params, permutation_func, &data);
- }
- static void
- litest_add_tcase(const char *filename,
- const char *funcname,
- const void *func,
- int64_t required,
- int64_t excluded,
- const struct range *range,
- struct litest_parameters *params)
- {
- bool added = false;
- litest_assert(required >= LITEST_DEVICELESS);
- litest_assert(excluded >= LITEST_DEVICELESS);
- if (filter_test && fnmatch(filter_test, funcname, 0) != 0)
- return;
- struct suite *suite = current_suite;
- if (filter_group && fnmatch(filter_group, suite->name, 0) != 0)
- return;
- if (required == LITEST_DEVICELESS && excluded == LITEST_DEVICELESS) {
- if (params)
- litest_add_tcase_deviceless_with_params(suite,
- func,
- funcname,
- params);
- else
- litest_add_tcase_deviceless(suite, func, funcname, range);
- added = true;
- } else if (required == LITEST_DISABLE_DEVICE &&
- excluded == LITEST_DISABLE_DEVICE) {
- if (params)
- litest_add_tcase_no_device_with_params(suite,
- func,
- funcname,
- params);
- else
- litest_add_tcase_no_device(suite, func, funcname, range);
- added = true;
- } else if (required != LITEST_ANY || excluded != LITEST_ANY) {
- struct litest_test_device *dev;
- list_for_each(dev, &devices, node) {
- if (dev->features & LITEST_IGNORED)
- continue;
- if (filter_device &&
- fnmatch(filter_device, dev->shortname, 0) != 0)
- continue;
- if ((dev->features & required) != required ||
- (dev->features & excluded) != 0)
- continue;
- if (params) {
- litest_add_tcase_for_device_with_params(suite,
- funcname,
- func,
- dev,
- params);
- } else {
- litest_add_tcase_for_device(suite,
- funcname,
- func,
- dev,
- range);
- }
- added = true;
- }
- } else {
- struct litest_test_device *dev;
- list_for_each(dev, &devices, node) {
- if (dev->features & LITEST_IGNORED)
- continue;
- if (filter_device &&
- fnmatch(filter_device, dev->shortname, 0) != 0)
- continue;
- if (params) {
- litest_add_tcase_for_device_with_params(suite,
- funcname,
- func,
- dev,
- params);
- } else {
- litest_add_tcase_for_device(suite,
- funcname,
- func,
- dev,
- range);
- }
- added = true;
- }
- }
- if (!added && filter_test == NULL && filter_device == NULL &&
- filter_group == NULL) {
- fprintf(stderr,
- "Test '%s' does not match any devices. Aborting.\n",
- funcname);
- abort();
- }
- }
- void
- _litest_add_no_device(const char *name, const char *funcname, const void *func)
- {
- _litest_add(name, funcname, func, LITEST_DISABLE_DEVICE, LITEST_DISABLE_DEVICE);
- }
- void
- _litest_add_parametrized_no_device(const char *name,
- const char *funcname,
- const void *func,
- struct litest_parameters *params)
- {
- _litest_add_parametrized(name,
- funcname,
- func,
- LITEST_DISABLE_DEVICE,
- LITEST_DISABLE_DEVICE,
- params);
- }
- void
- _litest_add_ranged_no_device(const char *name,
- const char *funcname,
- const void *func,
- const struct range *range)
- {
- _litest_add_ranged(name,
- funcname,
- func,
- LITEST_DISABLE_DEVICE,
- LITEST_DISABLE_DEVICE,
- range);
- }
- void
- _litest_add_deviceless(const char *name, const char *funcname, const void *func)
- {
- _litest_add_ranged(name,
- funcname,
- func,
- LITEST_DEVICELESS,
- LITEST_DEVICELESS,
- NULL);
- }
- void
- _litest_add_parametrized_deviceless(const char *name,
- const char *funcname,
- const void *func,
- struct litest_parameters *params)
- {
- _litest_add_parametrized(name,
- funcname,
- func,
- LITEST_DISABLE_DEVICE,
- LITEST_DISABLE_DEVICE,
- params);
- }
- void
- _litest_add(const char *name,
- const char *funcname,
- const void *func,
- int64_t required,
- int64_t excluded)
- {
- _litest_add_ranged(name, funcname, func, required, excluded, NULL);
- }
- void
- _litest_add_ranged(const char *name,
- const char *funcname,
- const void *func,
- int64_t required,
- int64_t excluded,
- const struct range *range)
- {
- litest_add_tcase(name, funcname, func, required, excluded, range, NULL);
- }
- void
- _litest_add_parametrized(const char *name,
- const char *funcname,
- const void *func,
- int64_t required,
- int64_t excluded,
- struct litest_parameters *params)
- {
- litest_add_tcase(name, funcname, func, required, excluded, NULL, params);
- }
- void
- _litest_add_for_device(const char *name,
- const char *funcname,
- const void *func,
- enum litest_device_type type)
- {
- _litest_add_ranged_for_device(name, funcname, func, type, NULL);
- }
- void
- _litest_add_ranged_for_device(const char *filename,
- const char *funcname,
- const void *func,
- enum litest_device_type type,
- const struct range *range)
- {
- struct litest_test_device *dev;
- bool device_filtered = false;
- litest_assert(type < LITEST_NO_DEVICE);
- if (filter_test && fnmatch(filter_test, funcname, 0) != 0)
- return;
- struct suite *s = current_suite;
- if (filter_group && fnmatch(filter_group, s->name, 0) != 0)
- return;
- list_for_each(dev, &devices, node) {
- if (filter_device && fnmatch(filter_device, dev->shortname, 0) != 0) {
- device_filtered = true;
- continue;
- }
- if (dev->type == type) {
- litest_add_tcase_for_device(s, funcname, func, dev, range);
- return;
- }
- }
- /* only abort if no filter was set, that's a bug */
- if (!device_filtered)
- litest_abort_msg("Invalid test device type");
- }
- void
- _litest_add_parametrized_for_device(const char *filename,
- const char *funcname,
- const void *func,
- enum litest_device_type type,
- struct litest_parameters *params)
- {
- struct litest_test_device *dev;
- bool device_filtered = false;
- litest_assert(type < LITEST_NO_DEVICE);
- if (filter_test && fnmatch(filter_test, funcname, 0) != 0)
- return;
- struct suite *s = current_suite;
- if (filter_group && fnmatch(filter_group, s->name, 0) != 0)
- return;
- list_for_each(dev, &devices, node) {
- if (filter_device && fnmatch(filter_device, dev->shortname, 0) != 0) {
- device_filtered = true;
- continue;
- }
- if (dev->type == type) {
- litest_add_tcase_for_device_with_params(s,
- funcname,
- func,
- dev,
- params);
- return;
- }
- }
- /* only abort if no filter was set, that's a bug */
- if (!device_filtered)
- litest_abort_msg("Invalid test device type");
- }
- static int
- is_actual_error(const char *error, size_t index, void *data)
- {
- /* We don't want to abort on these errors */
- if (((RUNNING_ON_VALGRIND || in_debugger) &&
- strstr(error, "scheduled expiry is in the past")) ||
- strstr(error, "event processing lagging behind")) {
- return 0;
- }
- return 1;
- }
- LIBINPUT_ATTRIBUTE_PRINTF(3, 0)
- static void
- litest_log_handler(struct libinput *libinput,
- enum libinput_log_priority pri,
- const char *format,
- va_list args)
- {
- const char *priority = NULL;
- const char *color = ""; // NOLINT: deadcode.DeadStores
- const char *color_reset = ANSI_NORMAL;
- switch (pri) {
- case LIBINPUT_LOG_PRIORITY_INFO:
- priority = "info ";
- color = ANSI_BOLD;
- break;
- case LIBINPUT_LOG_PRIORITY_ERROR:
- priority = "error";
- color = ANSI_BRIGHT_RED;
- break;
- case LIBINPUT_LOG_PRIORITY_DEBUG:
- priority = "debug";
- color = ANSI_NORMAL;
- break;
- default:
- abort();
- }
- _autofree_ char *msg = strdup_vprintf(format, args);
- if (!use_colors)
- color_reset = "";
- else if (strstr(format, "tap:"))
- color = ANSI_BLUE;
- else if (strstr(format, "thumb state:"))
- color = ANSI_YELLOW;
- else if (strstr(format, "button state:"))
- color = ANSI_MAGENTA;
- else if (strstr(format, "touch-size:") || strstr(format, "pressure:"))
- color = ANSI_GREEN;
- else if (strstr(format, "palm:") || strstr(format, "thumb:"))
- color = ANSI_CYAN;
- else if (strstr(format, "edge-scroll:"))
- color = ANSI_BRIGHT_GREEN;
- else if (strstr(format, "gesture:"))
- color = ANSI_YELLOW;
- else if (strstr(msg, "Plugin:"))
- color = ANSI_BRIGHT_CYAN;
- fprintf(stderr, "%slitest %s %s%s", color, priority, msg, color_reset);
- if (strstr(msg, "client bug: ") || strstr(msg, "libinput bug: ") ||
- strstr(msg, "plugin bug: ")) {
- /* valgrind is too slow and some of our offsets are too
- * short, don't abort if during a valgrind run we get a
- * negative offset */
- if ((RUNNING_ON_VALGRIND || in_debugger) &&
- strstr(format, "scheduled expiry is in the past")) {
- /* noop */
- } else if (strstr(format, "event processing lagging behind")) {
- /* noop */
- } else {
- litest_abort_msg("libinput bug triggered, aborting.");
- }
- }
- if (strstr(msg, "Touch jump detected and discarded")) {
- litest_abort_msg("libinput touch jump triggered, aborting.");
- }
- }
- static void
- litest_init_device_udev_rules(struct litest_test_device *dev, FILE *f)
- {
- const struct key_value_str *kv;
- static int count;
- bool need_keyboard_builtin = false;
- if (dev->udev_properties[0].key == NULL)
- return;
- count++;
- fprintf(f, "# %s\n", dev->shortname);
- fprintf(f, "ACTION==\"remove\", GOTO=\"rule%d_end\"\n", count);
- fprintf(f, "KERNEL!=\"event*\", GOTO=\"rule%d_end\"\n", count);
- fprintf(f, "ATTRS{name}==\"litest %s*\"", dev->name);
- kv = dev->udev_properties;
- while (kv->key) {
- fprintf(f, ", \\\n\tENV{%s}=\"%s\"", kv->key, kv->value);
- if (strstartswith(kv->key, "EVDEV_ABS_"))
- need_keyboard_builtin = true;
- kv++;
- }
- fprintf(f, "\n");
- /* Special case: the udev keyboard builtin is only run for hwdb
- * matches but we don't set any up in litest. So instead scan the
- * device's udev properties for any EVDEV_ABS properties and where
- * they exist, force a (re-)run of the keyboard builtin to set up
- * the evdev device correctly.
- * This needs to be done as separate rule apparently, otherwise the
- * ENV variables aren't set yet by the time the builtin runs.
- */
- if (need_keyboard_builtin) {
- fprintf(f,
- ""
- "ATTRS{name}==\"litest %s*\","
- " IMPORT{builtin}=\"keyboard\"\n",
- dev->name);
- }
- fprintf(f, "LABEL=\"rule%d_end\"\n\n", count);
- ;
- }
- static void
- litest_init_all_device_udev_rules(struct list *created_files)
- {
- struct created_file *file = zalloc(sizeof(*file));
- struct litest_test_device *dev;
- FILE *f;
- int fd;
- char *path = strdup_printf("%s/99-litest-XXXXXX.rules", UDEV_RULES_D);
- litest_assert_ptr_notnull(path);
- fd = mkstemps(path, 6);
- litest_assert_errno_success(fd);
- f = fdopen(fd, "w");
- litest_assert_notnull(f);
- list_for_each(dev, &devices, node)
- litest_init_device_udev_rules(dev, f);
- fclose(f);
- file->path = path;
- list_insert(created_files, &file->link);
- }
- static int
- open_restricted(const char *path, int flags, void *userdata)
- {
- const char prefix[] = "/dev/input/event";
- struct litest_context *ctx = userdata;
- struct path *p;
- int fd;
- litest_assert_ptr_notnull(ctx);
- fd = open(path, flags);
- if (fd < 0)
- return -errno;
- if (strstartswith(path, prefix)) {
- p = zalloc(sizeof *p);
- p->path = safe_strdup(path);
- p->fd = fd;
- /* We specifically insert here so that the most-recently
- * opened path is the first one in the list. This helps when
- * we have multiple test devices with the same device path,
- * the fd of the most recent device is the first one to get
- * grabbed
- */
- list_insert(&ctx->paths, &p->link);
- }
- return fd;
- }
- static void
- close_restricted(int fd, void *userdata)
- {
- struct litest_context *ctx = userdata;
- struct path *p;
- list_for_each_safe(p, &ctx->paths, link) {
- if (p->fd != fd)
- continue;
- list_remove(&p->link);
- free(p->path);
- free(p);
- }
- close(fd);
- }
- static struct libinput_interface interface = {
- .open_restricted = open_restricted,
- .close_restricted = close_restricted,
- };
- LIBINPUT_ATTRIBUTE_PRINTF(3, 0)
- static inline void
- quirk_log_handler(struct libinput *unused,
- enum libinput_log_priority priority,
- const char *format,
- va_list args)
- {
- if (priority < LIBINPUT_LOG_PRIORITY_ERROR)
- return;
- vfprintf(stderr, format, args);
- }
- static enum litest_runner_result
- init_quirks(void *userdata)
- {
- const char *data_path = getenv("LIBINPUT_QUIRKS_DIR");
- if (!data_path)
- data_path = LIBINPUT_QUIRKS_DIR;
- quirks_context = quirks_init_subsystem(data_path,
- NULL,
- quirk_log_handler,
- NULL,
- QLOG_LIBINPUT_LOGGING);
- return LITEST_PASS;
- }
- static void
- teardown_quirks(void *userdata)
- {
- quirks_context_unref(quirks_context);
- }
- static int
- litest_run_suite(struct list *suites, int njobs)
- {
- size_t ntests = 0;
- enum litest_runner_result result = LITEST_SKIP;
- struct suite *s;
- _destroy_(litest_runner) *runner = litest_runner_new();
- litest_runner_set_num_parallel(runner, njobs > 0 ? njobs : 0);
- if (outfile)
- litest_runner_set_output_file(runner, outfile);
- litest_runner_set_verbose(runner, verbose);
- litest_runner_set_use_colors(runner, use_colors);
- litest_runner_set_timeout(runner, 30);
- litest_runner_set_exit_on_fail(runner, exit_first);
- litest_runner_set_setup_funcs(runner, init_quirks, teardown_quirks, NULL);
- list_for_each(s, suites, node) {
- struct test *t;
- list_for_each(t, &s->tests, node) {
- struct litest_runner_test_description tdesc = { 0 };
- if (range_is_valid(&t->range)) {
- snprintf(tdesc.name,
- sizeof(tdesc.name),
- "%s:%s:%s:%d",
- s->name,
- t->name,
- t->devname,
- t->rangeval);
- } else if (t->params) {
- char buf[256] = { 0 };
- struct litest_test_param *tp;
- bool is_first = true;
- list_for_each(tp, &t->params->test_params, link) {
- _autofree_ char *val =
- multivalue_as_str(&tp->value);
- snprintf(buf + strlen(buf),
- sizeof(buf) - strlen(buf),
- "%s%s:%s",
- is_first ? "" : ",",
- tp->name,
- val);
- is_first = false;
- }
- snprintf(tdesc.name,
- sizeof(tdesc.name),
- "%s:%s:%s:%s",
- s->name,
- t->name,
- t->devname,
- buf);
- } else {
- snprintf(tdesc.name,
- sizeof(tdesc.name),
- "%s:%s:%s",
- s->name,
- t->name,
- t->devname);
- }
- tdesc.func = t->func;
- tdesc.setup = t->setup;
- tdesc.teardown = t->teardown;
- tdesc.args.range = t->range;
- tdesc.rangeval = t->rangeval;
- tdesc.params = t->params;
- litest_runner_add_test(runner, &tdesc);
- ntests++;
- }
- }
- if (ntests > 0)
- result = litest_runner_run_tests(runner);
- return result;
- }
- static inline int
- inhibit(void)
- {
- int lock_fd = -1;
- #ifdef HAVE_LIBSYSTEMD
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _unref_(sd_bus_message) *m = NULL;
- _unref_(sd_bus) *bus = NULL;
- int rc;
- if (run_deviceless)
- return -1;
- rc = sd_bus_open_system(&bus);
- if (rc != 0) {
- fprintf(stderr, "Warning: inhibit failed: %s\n", strerror(-rc));
- goto out;
- }
- rc = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "Inhibit",
- &error,
- &m,
- "ssss",
- "sleep:shutdown:handle-lid-switch:handle-power-key:handle-suspend-key:"
- "handle-hibernate-key",
- "libinput test-suite runner",
- "testing in progress",
- "block");
- if (rc < 0) {
- fprintf(stderr, "Warning: inhibit failed: %s\n", error.message);
- goto out;
- }
- rc = sd_bus_message_read(m, "h", &lock_fd);
- if (rc < 0) {
- fprintf(stderr, "Warning: inhibit failed: %s\n", strerror(-rc));
- goto out;
- }
- lock_fd = dup(lock_fd);
- out:
- sd_bus_close(bus);
- #endif
- return lock_fd;
- }
- static int
- disable_tty(void)
- {
- int tty_mode = -1;
- if (isatty(STDIN_FILENO) && ioctl(STDIN_FILENO, KDGKBMODE, &tty_mode) == 0) {
- #ifdef __linux__
- ioctl(STDIN_FILENO, KDSKBMODE, K_OFF);
- #elif __FreeBSD__
- ioctl(STDIN_FILENO, KDSKBMODE, K_RAW);
- /* Put the tty into raw mode */
- struct termios tios;
- if (tcgetattr(STDIN_FILENO, &tios))
- fprintf(stderr,
- "Failed to get terminal attribute: %d - %s\n",
- errno,
- strerror(errno));
- cfmakeraw(&tios);
- if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios))
- fprintf(stderr,
- "Failed to set terminal attribute: %d - %s\n",
- errno,
- strerror(errno));
- #endif
- }
- return tty_mode;
- }
- static void
- restore_tty(int tty_mode)
- {
- if (tty_mode != -1) {
- ioctl(STDIN_FILENO, KDSKBMODE, tty_mode);
- #ifdef __FreeBSD__
- /* Put the tty into "sane" mode */
- struct termios tios;
- if (tcgetattr(STDIN_FILENO, &tios))
- fprintf(stderr,
- "Failed to get terminal attribute: %d - %s\n",
- errno,
- strerror(errno));
- cfmakesane(&tios);
- if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios))
- fprintf(stderr,
- "Failed to set terminal attribute: %d - %s\n",
- errno,
- strerror(errno));
- #endif
- }
- }
- enum litest_runner_result
- litest_run(struct list *suites, int njobs)
- {
- const struct rlimit corelimit = { 0, 0 };
- int inhibit_lock_fd;
- int tty_mode = -1;
- setenv("LIBINPUT_RUNNING_TEST_SUITE", "1", 1);
- if (setrlimit(RLIMIT_CORE, &corelimit) != 0)
- perror("WARNING: Core dumps not disabled");
- struct list created_files_list = LIST_INIT(created_files_list);
- if (run_deviceless) {
- litest_setup_quirks(&created_files_list, QUIRKS_SETUP_USE_SRCDIR);
- } else {
- enum quirks_setup_mode mode;
- litest_init_udev_rules(&created_files_list);
- mode = use_system_rules_quirks ? QUIRKS_SETUP_ONLY_DEVICE
- : QUIRKS_SETUP_FULL;
- litest_setup_quirks(&created_files_list, mode);
- }
- /* If we're running 'normally' on the VT, disable the keyboard to
- * avoid messing up our host. But if we're inside gdb or running
- * without forking, leave it as-is.
- */
- if (!run_deviceless && njobs > 1 && !in_debugger)
- tty_mode = disable_tty();
- inhibit_lock_fd = inhibit();
- enum litest_runner_result result = litest_run_suite(suites, njobs);
- close(inhibit_lock_fd);
- restore_tty(tty_mode);
- litest_remove_udev_rules(&created_files_list);
- return result;
- }
- static struct input_absinfo *
- merge_absinfo(const struct input_absinfo *orig, const struct input_absinfo *override)
- {
- struct input_absinfo *abs;
- unsigned int nelem, i;
- size_t sz = ABS_MAX + 1;
- if (!orig)
- return NULL;
- abs = zalloc(sz * sizeof(*abs));
- litest_assert_ptr_notnull(abs);
- nelem = 0;
- while (orig[nelem].value != -1) {
- abs[nelem] = orig[nelem];
- nelem++;
- litest_assert_int_lt(nelem, sz);
- }
- /* just append, if the same axis is present twice, libevdev will
- only use the last value anyway */
- i = 0;
- while (override && override[i].value != -1) {
- abs[nelem++] = override[i++];
- litest_assert_int_lt(nelem, sz);
- }
- litest_assert_int_lt(nelem, sz);
- abs[nelem].value = -1;
- return abs;
- }
- static int *
- merge_events(const int *orig, const int *override)
- {
- int *events;
- unsigned int nelem, i;
- size_t sz = KEY_MAX * 3;
- if (!orig)
- return NULL;
- events = zalloc(sz * sizeof(int));
- litest_assert_ptr_notnull(events);
- nelem = 0;
- while (orig[nelem] != -1) {
- events[nelem] = orig[nelem];
- nelem++;
- litest_assert_int_lt(nelem, sz);
- }
- /* just append, if the same axis is present twice, libevdev will
- * ignore the double definition anyway */
- i = 0;
- while (override && override[i] != -1) {
- events[nelem++] = override[i++];
- litest_assert_int_le(nelem, sz);
- }
- litest_assert_int_lt(nelem, sz);
- events[nelem] = -1;
- return events;
- }
- static inline struct created_file *
- litest_copy_file(const char *dest, const char *src, const char *header, bool is_file)
- {
- int in, out, length;
- struct created_file *file;
- file = zalloc(sizeof(*file));
- file->path = safe_strdup(dest);
- if (strstr(dest, "XXXXXX")) {
- int suffixlen;
- suffixlen = file->path + strlen(file->path) - rindex(file->path, '.');
- out = mkstemps(file->path, suffixlen);
- } else {
- out = open(file->path, O_CREAT | O_WRONLY, 0644);
- }
- if (out == -1)
- litest_abort_msg("Failed to write to file %s (%s)",
- file->path,
- strerror(errno));
- litest_assert_errno_success(chmod(file->path, 0644));
- if (header) {
- length = strlen(header);
- litest_assert_int_eq(write(out, header, length), length);
- }
- if (is_file) {
- in = open(src, O_RDONLY);
- if (in == -1)
- litest_abort_msg("Failed to open file %s (%s)",
- src,
- strerror(errno));
- /* lazy, just check for error and empty file copy */
- litest_assert_int_gt(litest_send_file(out, in), 0);
- close(in);
- } else {
- size_t written = write(out, src, strlen(src));
- litest_assert_int_eq(written, strlen(src));
- }
- close(out);
- return file;
- }
- static inline void
- litest_install_model_quirks(struct list *created_files_list)
- {
- const char *warning =
- "#################################################################\n"
- "# WARNING: REMOVE THIS FILE\n"
- "# This is a run-time file for the libinput test suite and\n"
- "# should be removed on exit. If the test-suite is not currently \n"
- "# running, remove this file\n"
- "#################################################################\n\n";
- struct created_file *file;
- const char *test_device_udev_rule =
- "KERNELS==\"*input*\", "
- "ATTRS{name}==\"litest *\", "
- "ENV{LIBINPUT_TEST_DEVICE}=\"1\"";
- file = litest_copy_file(UDEV_TEST_DEVICE_RULE_FILE,
- test_device_udev_rule,
- warning,
- false);
- list_insert(created_files_list, &file->link);
- /* Only install the litest device rule when we're running as system
- * test suite, we expect the others to be in place already */
- if (use_system_rules_quirks)
- return;
- file = litest_copy_file(UDEV_DEVICE_GROUPS_FILE,
- LIBINPUT_DEVICE_GROUPS_RULES_FILE,
- warning,
- true);
- list_insert(created_files_list, &file->link);
- file = litest_copy_file(UDEV_FUZZ_OVERRIDE_RULE_FILE,
- LIBINPUT_FUZZ_OVERRIDE_UDEV_RULES_FILE,
- warning,
- true);
- list_insert(created_files_list, &file->link);
- }
- static char *
- litest_init_device_quirk_file(const char *data_dir, struct litest_test_device *dev)
- {
- int fd;
- FILE *f;
- char path[PATH_MAX];
- static int count;
- if (!dev->quirk_file)
- return NULL;
- snprintf(path,
- sizeof(path),
- "%s/99-%03d-%s.quirks",
- data_dir,
- ++count,
- dev->shortname);
- fd = open(path, O_CREAT | O_WRONLY, 0644);
- litest_assert_errno_success(fd);
- f = fdopen(fd, "w");
- litest_assert_notnull(f);
- litest_assert_int_ge(fputs(dev->quirk_file, f), 0);
- fclose(f);
- return safe_strdup(path);
- }
- static int
- is_quirks_file(const struct dirent *dir)
- {
- return strendswith(dir->d_name, ".quirks");
- }
- /**
- * Install the quirks from the quirks/ source directory.
- */
- static void
- litest_install_source_quirks(struct list *created_files_list, const char *dirname)
- {
- _autofree_ struct dirent **namelist;
- int ndev;
- ndev = scandir(LIBINPUT_QUIRKS_SRCDIR, &namelist, is_quirks_file, versionsort);
- litest_assert_int_ge(ndev, 0);
- for (int idx = 0; idx < ndev; idx++) {
- struct created_file *file;
- char *filename;
- char dest[PATH_MAX];
- char src[PATH_MAX];
- _autofree_ struct dirent *entry = namelist[idx];
- filename = entry->d_name;
- snprintf(src, sizeof(src), "%s/%s", LIBINPUT_QUIRKS_SRCDIR, filename);
- snprintf(dest, sizeof(dest), "%s/%s", dirname, filename);
- file = litest_copy_file(dest, src, NULL, true);
- list_append(created_files_list, &file->link);
- }
- }
- /**
- * Install the quirks from the various litest test devices
- */
- static void
- litest_install_device_quirks(struct list *created_files_list, const char *dirname)
- {
- struct litest_test_device *dev;
- list_for_each(dev, &devices, node) {
- char *path;
- path = litest_init_device_quirk_file(dirname, dev);
- if (path) {
- struct created_file *file = zalloc(sizeof(*file));
- file->path = path;
- list_insert(created_files_list, &file->link);
- }
- }
- }
- static void
- litest_setup_quirks(struct list *created_files_list, enum quirks_setup_mode mode)
- {
- struct created_file *file = NULL;
- const char *dirname;
- char tmpdir[] = "/run/litest-XXXXXX";
- switch (mode) {
- case QUIRKS_SETUP_USE_SRCDIR:
- if (builddir_lookup(NULL))
- dirname = LIBINPUT_QUIRKS_SRCDIR;
- else
- dirname = LIBINPUT_QUIRKS_DIR;
- break;
- case QUIRKS_SETUP_ONLY_DEVICE:
- dirname = LIBINPUT_QUIRKS_DIR;
- litest_install_device_quirks(created_files_list, dirname);
- break;
- case QUIRKS_SETUP_FULL:
- litest_assert_notnull(mkdtemp(tmpdir));
- litest_assert_errno_success(chmod(tmpdir, 0755));
- file = zalloc(sizeof *file);
- file->path = safe_strdup(tmpdir);
- dirname = tmpdir;
- litest_install_source_quirks(created_files_list, dirname);
- litest_install_device_quirks(created_files_list, dirname);
- list_append(created_files_list, &file->link);
- break;
- }
- setenv("LIBINPUT_QUIRKS_DIR", dirname, 1);
- }
- static inline void
- litest_init_udev_rules(struct list *created_files)
- {
- litest_assert_neg_errno_success(mkdir_p(UDEV_RULES_D));
- litest_install_model_quirks(created_files);
- litest_init_all_device_udev_rules(created_files);
- litest_reload_udev_rules();
- }
- static inline void
- litest_remove_udev_rules(struct list *created_files_list)
- {
- struct created_file *f;
- bool reload_udev;
- reload_udev = !list_empty(created_files_list);
- list_for_each_safe(f, created_files_list, link) {
- created_file_unlink(f);
- created_file_destroy(f);
- }
- if (reload_udev)
- litest_reload_udev_rules();
- }
- /**
- * Creates a uinput device but does not add it to a libinput context
- */
- struct litest_device *
- litest_create(enum litest_device_type which,
- const char *name_override,
- struct input_id *id_override,
- const struct input_absinfo *abs_override,
- const int *events_override)
- {
- struct litest_device *d = NULL;
- struct litest_test_device *dev;
- const char *name;
- const struct input_id *id;
- _autofree_ struct input_absinfo *abs;
- _autofree_ int *events;
- int *e;
- const char *path;
- int fd, rc;
- bool found = false;
- bool create_device = true;
- list_for_each(dev, &devices, node) {
- if (dev->type == which) {
- found = true;
- break;
- }
- }
- if (!found)
- litest_abort_msg("Invalid device type %d", which);
- d = zalloc(sizeof(*d));
- d->which = which;
- /* device has custom create method */
- if (dev->create) {
- create_device = dev->create(d);
- if (abs_override || events_override) {
- litest_abort_msg("Custom create cannot be overridden");
- }
- }
- abs = merge_absinfo(dev->absinfo, abs_override);
- events = merge_events(dev->events, events_override);
- name = name_override ? name_override : dev->name;
- id = id_override ? id_override : dev->id;
- if (create_device) {
- d->uinput = litest_create_uinput_device_from_description(name,
- id,
- abs,
- events);
- d->interface = dev->interface;
- for (e = events; *e != -1; e += 2) {
- unsigned int type = *e, code = *(e + 1);
- if (type == INPUT_PROP_MAX && code == INPUT_PROP_SEMI_MT) {
- d->semi_mt.is_semi_mt = true;
- break;
- }
- }
- }
- path = libevdev_uinput_get_devnode(d->uinput);
- litest_assert_ptr_notnull(path);
- fd = open(path, O_RDWR | O_NONBLOCK);
- litest_assert_errno_success(fd);
- rc = libevdev_new_from_fd(fd, &d->evdev);
- litest_assert_neg_errno_success(rc);
- return d;
- }
- struct libinput *
- litest_create_context_with_plugindir(const char *plugindir)
- {
- struct libinput *libinput;
- struct litest_context *ctx;
- ctx = zalloc(sizeof *ctx);
- list_init(&ctx->paths);
- libinput = libinput_path_create_context(&interface, ctx);
- litest_assert_notnull(libinput);
- libinput_log_set_handler(libinput, litest_log_handler);
- if (verbose)
- libinput_log_set_priority(libinput, LIBINPUT_LOG_PRIORITY_DEBUG);
- if (plugindir)
- libinput_plugin_system_append_path(libinput, plugindir);
- return libinput;
- }
- struct libinput *
- litest_create_context(void)
- {
- struct libinput *li = litest_create_context_with_plugindir(NULL);
- libinput_plugin_system_load_plugins(li, LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
- return li;
- }
- void
- litest_destroy_context(struct libinput *li)
- {
- if (li) {
- _autofree_ struct litest_context *ctx = libinput_get_user_data(li);
- litest_assert_ptr_notnull(ctx);
- libinput_unref(li);
- struct path *p;
- list_for_each_safe(p, &ctx->paths, link) {
- litest_abort_msg("Device paths should be removed by now");
- }
- }
- }
- void
- litest_context_set_user_data(struct libinput *li, void *data)
- {
- struct litest_user_data *litest_data = libinput_get_user_data(li);
- litest_assert_ptr_notnull(litest_data);
- litest_data->private = data;
- }
- void *
- litest_context_get_user_data(struct libinput *li)
- {
- struct litest_user_data *litest_data = libinput_get_user_data(li);
- litest_assert_ptr_notnull(litest_data);
- return litest_data->private;
- }
- void
- litest_disable_log_handler(struct libinput *libinput)
- {
- libinput_log_set_handler(libinput, NULL);
- }
- void
- litest_restore_log_handler(struct libinput *libinput)
- {
- libinput_log_set_handler(libinput, litest_log_handler);
- if (verbose)
- libinput_log_set_priority(libinput, LIBINPUT_LOG_PRIORITY_DEBUG);
- }
- LIBINPUT_ATTRIBUTE_PRINTF(3, 0)
- static void
- litest_bug_log_handler(struct libinput *libinput,
- enum libinput_log_priority pri,
- const char *format,
- va_list args)
- {
- if (pri != LIBINPUT_LOG_PRIORITY_ERROR || strstr(format, "client bug: ") ||
- strstr(format, "libinput bug: ") || strstr(format, "kernel bug: "))
- return;
- /* messages from plugins don't have the string in the format, it's one of the
- * args... */
- _autofree_ char *msg = strdup_vprintf(format, args);
- if (strstr(msg, "plugin bug:"))
- return;
- litest_abort_msg("Expected bug statement in log msg ('%s'), aborting.", msg);
- }
- void
- litest_set_log_handler_bug(struct libinput *libinput)
- {
- libinput_log_set_handler(libinput, litest_bug_log_handler);
- }
- struct litest_device *
- litest_add_device_with_overrides(struct libinput *libinput,
- enum litest_device_type which,
- const char *name_override,
- struct input_id *id_override,
- const struct input_absinfo *abs_override,
- const int *events_override)
- {
- struct litest_device *d;
- const char *path;
- d = litest_create(which,
- name_override,
- id_override,
- abs_override,
- events_override);
- path = libevdev_uinput_get_devnode(d->uinput);
- litest_assert_ptr_notnull(path);
- d->libinput = libinput;
- d->libinput_device = libinput_path_add_device(d->libinput, path);
- litest_assert_ptr_notnull(d->libinput_device);
- _unref_(udev_device) *ud = libinput_device_get_udev_device(d->libinput_device);
- d->quirks = quirks_fetch_for_device(quirks_context, ud);
- libinput_device_ref(d->libinput_device);
- if (d->interface) {
- unsigned int code;
- code = ABS_X;
- if (!libevdev_has_event_code(d->evdev, EV_ABS, code))
- code = ABS_MT_POSITION_X;
- if (libevdev_has_event_code(d->evdev, EV_ABS, code)) {
- d->interface->min[ABS_X] =
- libevdev_get_abs_minimum(d->evdev, code);
- d->interface->max[ABS_X] =
- libevdev_get_abs_maximum(d->evdev, code);
- }
- code = ABS_Y;
- if (!libevdev_has_event_code(d->evdev, EV_ABS, code))
- code = ABS_MT_POSITION_Y;
- if (libevdev_has_event_code(d->evdev, EV_ABS, code)) {
- d->interface->min[ABS_Y] =
- libevdev_get_abs_minimum(d->evdev, code);
- d->interface->max[ABS_Y] =
- libevdev_get_abs_maximum(d->evdev, code);
- }
- d->interface->tool_type = BTN_TOOL_PEN;
- }
- return d;
- }
- struct litest_device *
- litest_add_device(struct libinput *libinput, enum litest_device_type which)
- {
- return litest_add_device_with_overrides(libinput,
- which,
- NULL,
- NULL,
- NULL,
- NULL);
- }
- struct litest_device *
- litest_create_device_with_overrides(enum litest_device_type which,
- const char *name_override,
- struct input_id *id_override,
- const struct input_absinfo *abs_override,
- const int *events_override)
- {
- struct litest_device *dev =
- litest_add_device_with_overrides(litest_create_context(),
- which,
- name_override,
- id_override,
- abs_override,
- events_override);
- dev->owns_context = true;
- return dev;
- }
- struct litest_device *
- litest_create_device(enum litest_device_type which)
- {
- return litest_create_device_with_overrides(which, NULL, NULL, NULL, NULL);
- }
- static struct udev_monitor *
- udev_setup_monitor(void)
- {
- _unref_(udev) *udev = udev_new();
- _unref_(udev_monitor) *udev_monitor = NULL;
- int rc;
- litest_assert_notnull(udev);
- udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
- litest_assert_notnull(udev_monitor);
- udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input", NULL);
- /* remove O_NONBLOCK */
- rc = fcntl(udev_monitor_get_fd(udev_monitor), F_SETFL, 0);
- litest_assert_errno_success(rc);
- litest_assert_int_eq(udev_monitor_enable_receiving(udev_monitor), 0);
- return steal(&udev_monitor);
- }
- static struct udev_device *
- udev_wait_for_device_event(struct udev_monitor *udev_monitor,
- const char *udev_event,
- const char *syspath)
- {
- /* blocking, we don't want to continue until udev is ready */
- while (1) {
- _unref_(udev_device) *udev_device = NULL;
- const char *udev_syspath = NULL;
- const char *udev_action;
- udev_device = udev_monitor_receive_device(udev_monitor);
- if (!udev_device) {
- if (errno == EAGAIN)
- continue;
- litest_abort_msg(
- "Failed to receive udev device from monitor: %s (%d)",
- strerror(errno),
- errno);
- }
- udev_action = udev_device_get_action(udev_device);
- if (!udev_action || !streq(udev_action, udev_event)) {
- continue;
- }
- udev_syspath = udev_device_get_syspath(udev_device);
- if (strstartswith(udev_syspath, syspath))
- return steal(&udev_device);
- }
- }
- void
- litest_device_destroy(struct litest_device *d)
- {
- _unref_(udev_monitor) *udev_monitor = NULL;
- _unref_(udev_device) *udev_device = NULL;
- char path[PATH_MAX];
- if (!d)
- return;
- udev_monitor = udev_setup_monitor();
- snprintf(path,
- sizeof(path),
- "%s/event",
- libevdev_uinput_get_syspath(d->uinput));
- litest_assert_int_eq(d->skip_ev_syn, 0);
- quirks_unref(d->quirks);
- if (d->libinput_device) {
- libinput_path_remove_device(d->libinput_device);
- libinput_device_unref(d->libinput_device);
- }
- if (d->owns_context) {
- libinput_dispatch(d->libinput);
- litest_destroy_context(d->libinput);
- }
- close(libevdev_get_fd(d->evdev));
- libevdev_free(d->evdev);
- libevdev_uinput_destroy(d->uinput);
- free(d->private);
- memset(d, 0, sizeof(*d));
- free(d);
- udev_device = // NOLINT: deadcode.DeadStores
- udev_wait_for_device_event(udev_monitor, "remove", path);
- }
- void
- litest_event_unchecked(struct litest_device *d,
- unsigned int type,
- unsigned int code,
- int value)
- {
- int ret = libevdev_uinput_write_event(d->uinput, type, code, value);
- litest_assert_neg_errno_success(ret);
- }
- void
- litest_event(struct litest_device *d, unsigned int type, unsigned int code, int value)
- {
- if (!libevdev_has_event_code(d->evdev, type, code))
- return;
- if (type == EV_SYN && code == SYN_REPORT) {
- if (d->skip_ev_syn)
- return;
- for (size_t i = 0; i < d->frame.nevents; i++) {
- struct input_event *e = &d->frame.events[i];
- int ret = libevdev_uinput_write_event(d->uinput,
- e->type,
- e->code,
- e->value);
- litest_assert_neg_errno_success(ret);
- }
- int ret = libevdev_uinput_write_event(d->uinput,
- EV_SYN,
- SYN_REPORT,
- value);
- litest_assert_neg_errno_success(ret);
- d->frame.nevents = 0;
- } else {
- size_t i;
- if (type == EV_SYN || (type == EV_ABS && code >= ABS_MT_SLOT)) {
- i = d->frame.nevents;
- } else {
- for (i = 0; i < d->frame.nevents; i++) {
- if (d->frame.events[i].type == type &&
- d->frame.events[i].code == code)
- break;
- }
- }
- litest_assert_int_lt(i, ARRAY_LENGTH(d->frame.events));
- d->frame.events[i] = (struct input_event){
- .type = type,
- .code = code,
- .value = value,
- };
- if (i >= d->frame.nevents)
- d->frame.nevents++;
- }
- }
- static bool
- axis_replacement_value(struct litest_device *d,
- struct axis_replacement *axes,
- int32_t evcode,
- int32_t *value)
- {
- struct axis_replacement *axis = axes;
- if (!axes)
- return false;
- while (axis->evcode != -1) {
- if (axis->evcode == evcode) {
- switch (evcode) {
- case ABS_MISC:
- case ABS_MT_SLOT:
- case ABS_MT_TRACKING_ID:
- case ABS_MT_TOOL_TYPE:
- *value = axis->value;
- break;
- default:
- *value = litest_scale(d, evcode, axis->value);
- break;
- }
- return true;
- }
- axis++;
- }
- return false;
- }
- int
- litest_auto_assign_value(struct litest_device *d,
- const struct input_event *ev,
- int slot,
- double x,
- double y,
- struct axis_replacement *axes,
- bool touching)
- {
- static int tracking_id;
- int value = ev->value;
- if (value != LITEST_AUTO_ASSIGN || ev->type != EV_ABS)
- return value;
- switch (ev->code) {
- case ABS_X:
- case ABS_MT_POSITION_X:
- value = litest_scale(d, ABS_X, x);
- break;
- case ABS_Y:
- case ABS_MT_POSITION_Y:
- value = litest_scale(d, ABS_Y, y);
- break;
- case ABS_MT_TRACKING_ID:
- value = ++tracking_id;
- break;
- case ABS_MT_SLOT:
- value = slot;
- break;
- case ABS_MT_DISTANCE:
- value = touching ? 0 : 1;
- break;
- case ABS_MT_TOOL_TYPE:
- if (!axis_replacement_value(d, axes, ev->code, &value))
- value = MT_TOOL_FINGER;
- break;
- default:
- if (!axis_replacement_value(d, axes, ev->code, &value) &&
- d->interface->get_axis_default) {
- int error = d->interface->get_axis_default(d, ev->code, &value);
- if (error) {
- litest_abort_msg(
- "Failed to get default axis value for %s (%d)",
- libevdev_event_code_get_name(EV_ABS, ev->code),
- ev->code);
- }
- }
- break;
- }
- return value;
- }
- static void
- send_btntool(struct litest_device *d, bool hover)
- {
- litest_event(d, EV_KEY, BTN_TOUCH, d->ntouches_down != 0 && !hover);
- litest_event(d, EV_KEY, BTN_TOOL_FINGER, d->ntouches_down == 1);
- litest_event(d, EV_KEY, BTN_TOOL_DOUBLETAP, d->ntouches_down == 2);
- litest_event(d, EV_KEY, BTN_TOOL_TRIPLETAP, d->ntouches_down == 3);
- litest_event(d, EV_KEY, BTN_TOOL_QUADTAP, d->ntouches_down == 4);
- litest_event(d, EV_KEY, BTN_TOOL_QUINTTAP, d->ntouches_down == 5);
- }
- static void
- slot_start(struct litest_device *d,
- unsigned int slot,
- double x,
- double y,
- struct axis_replacement *axes,
- bool touching,
- bool filter_abs_xy)
- {
- struct input_event *ev;
- litest_assert_int_ge(d->ntouches_down, 0);
- d->ntouches_down++;
- send_btntool(d, !touching);
- /* If the test device overrides touch_down and says it didn't
- * handle the event, let's continue normally */
- if (d->interface->touch_down && d->interface->touch_down(d, slot, x, y))
- return;
- for (ev = d->interface->touch_down_events;
- ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1;
- ev++) {
- int value = litest_auto_assign_value(d, ev, slot, x, y, axes, touching);
- if (value == LITEST_AUTO_ASSIGN)
- continue;
- if (filter_abs_xy && ev->type == EV_ABS &&
- (ev->code == ABS_X || ev->code == ABS_Y))
- continue;
- litest_event(d, ev->type, ev->code, value);
- }
- }
- static void
- slot_move(struct litest_device *d,
- unsigned int slot,
- double x,
- double y,
- struct axis_replacement *axes,
- bool touching,
- bool filter_abs_xy)
- {
- struct input_event *ev;
- if (d->interface->touch_move && d->interface->touch_move(d, slot, x, y))
- return;
- for (ev = d->interface->touch_move_events;
- ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1;
- ev++) {
- int value = litest_auto_assign_value(d, ev, slot, x, y, axes, touching);
- if (value == LITEST_AUTO_ASSIGN)
- continue;
- if (filter_abs_xy && ev->type == EV_ABS &&
- (ev->code == ABS_X || ev->code == ABS_Y))
- continue;
- litest_event(d, ev->type, ev->code, value);
- }
- }
- static void
- touch_up(struct litest_device *d, unsigned int slot)
- {
- struct input_event *ev;
- struct input_event up[] = {
- { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
- { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = -1 },
- { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = 0 },
- { .type = EV_ABS, .code = ABS_MT_TOUCH_MAJOR, .value = 0 },
- { .type = EV_ABS, .code = ABS_MT_TOUCH_MINOR, .value = 0 },
- { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
- { .type = -1, .code = -1 }
- };
- litest_assert_int_gt(d->ntouches_down, 0);
- d->ntouches_down--;
- send_btntool(d, false);
- if (d->interface->touch_up && d->interface->touch_up(d, slot)) {
- return;
- } else if (d->interface->touch_up_events) {
- ev = d->interface->touch_up_events;
- } else
- ev = up;
- for (/* */; ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1; ev++) {
- int value = litest_auto_assign_value(d, ev, slot, 0, 0, NULL, false);
- litest_event(d, ev->type, ev->code, value);
- }
- }
- static void
- litest_slot_start(struct litest_device *d,
- unsigned int slot,
- double x,
- double y,
- struct axis_replacement *axes,
- bool touching)
- {
- double t, l, r = 0, b = 0; /* top, left, right, bottom */
- bool filter_abs_xy = false;
- if (!d->semi_mt.is_semi_mt) {
- slot_start(d, slot, x, y, axes, touching, filter_abs_xy);
- return;
- }
- if (d->ntouches_down >= 2 || slot > 1)
- return;
- slot = d->ntouches_down;
- if (d->ntouches_down == 0) {
- l = x;
- t = y;
- } else {
- int other = (slot + 1) % 2;
- l = min(x, d->semi_mt.touches[other].x);
- t = min(y, d->semi_mt.touches[other].y);
- r = max(x, d->semi_mt.touches[other].x);
- b = max(y, d->semi_mt.touches[other].y);
- }
- litest_with_event_frame(d) {
- if (d->ntouches_down == 0)
- slot_start(d, 0, l, t, axes, touching, filter_abs_xy);
- else
- slot_move(d, 0, l, t, axes, touching, filter_abs_xy);
- if (slot == 1) {
- filter_abs_xy = true;
- slot_start(d, 1, r, b, axes, touching, filter_abs_xy);
- }
- }
- d->semi_mt.touches[slot].x = x;
- d->semi_mt.touches[slot].y = y;
- }
- void
- litest_touch_sequence(struct litest_device *d,
- unsigned int slot,
- double x_from,
- double y_from,
- double x_to,
- double y_to,
- int steps)
- {
- litest_touch_down(d, slot, x_from, y_from);
- litest_touch_move_to(d, slot, x_from, y_from, x_to, y_to, steps);
- litest_touch_up(d, slot);
- }
- void
- litest_touch_down(struct litest_device *d, unsigned int slot, double x, double y)
- {
- litest_slot_start(d, slot, x, y, NULL, true);
- }
- void
- litest_touch_down_extended(struct litest_device *d,
- unsigned int slot,
- double x,
- double y,
- struct axis_replacement *axes)
- {
- litest_slot_start(d, slot, x, y, axes, true);
- }
- static void
- litest_slot_move(struct litest_device *d,
- unsigned int slot,
- double x,
- double y,
- struct axis_replacement *axes,
- bool touching)
- {
- double t, l, r = 0, b = 0; /* top, left, right, bottom */
- bool filter_abs_xy = false;
- if (!d->semi_mt.is_semi_mt) {
- slot_move(d, slot, x, y, axes, touching, filter_abs_xy);
- return;
- }
- if (d->ntouches_down > 2 || slot > 1)
- return;
- if (d->ntouches_down == 1) {
- l = x;
- t = y;
- } else {
- int other = (slot + 1) % 2;
- l = min(x, d->semi_mt.touches[other].x);
- t = min(y, d->semi_mt.touches[other].y);
- r = max(x, d->semi_mt.touches[other].x);
- b = max(y, d->semi_mt.touches[other].y);
- }
- litest_with_event_frame(d) {
- slot_move(d, 0, l, t, axes, touching, filter_abs_xy);
- if (d->ntouches_down == 2) {
- filter_abs_xy = true;
- slot_move(d, 1, r, b, axes, touching, filter_abs_xy);
- }
- }
- d->semi_mt.touches[slot].x = x;
- d->semi_mt.touches[slot].y = y;
- }
- void
- litest_touch_up(struct litest_device *d, unsigned int slot)
- {
- if (!d->semi_mt.is_semi_mt) {
- touch_up(d, slot);
- return;
- }
- if (d->ntouches_down > 2 || slot > 1)
- return;
- litest_with_event_frame(d) {
- touch_up(d, d->ntouches_down - 1);
- /* if we have one finger left, send x/y coords for that finger left.
- this is likely to happen with a real touchpad */
- if (d->ntouches_down == 1) {
- bool touching = true;
- bool filter_abs_xy = false;
- int other = (slot + 1) % 2;
- slot_move(d,
- 0,
- d->semi_mt.touches[other].x,
- d->semi_mt.touches[other].y,
- NULL,
- touching,
- filter_abs_xy);
- }
- }
- }
- void
- litest_touch_move(struct litest_device *d, unsigned int slot, double x, double y)
- {
- litest_slot_move(d, slot, x, y, NULL, true);
- }
- void
- litest_touch_move_extended(struct litest_device *d,
- unsigned int slot,
- double x,
- double y,
- struct axis_replacement *axes)
- {
- litest_slot_move(d, slot, x, y, axes, true);
- }
- void
- litest_touch_move_to(struct litest_device *d,
- unsigned int slot,
- double x_from,
- double y_from,
- double x_to,
- double y_to,
- int steps)
- {
- litest_touch_move_to_extended(d, slot, x_from, y_from, x_to, y_to, NULL, steps);
- }
- void
- litest_touch_move_to_extended(struct litest_device *d,
- unsigned int slot,
- double x_from,
- double y_from,
- double x_to,
- double y_to,
- struct axis_replacement *axes,
- int steps)
- {
- int sleep_ms = 10;
- for (int i = 1; i < steps; i++) {
- litest_touch_move_extended(d,
- slot,
- x_from + (x_to - x_from) / steps * i,
- y_from + (y_to - y_from) / steps * i,
- axes);
- libinput_dispatch(d->libinput);
- msleep(sleep_ms);
- libinput_dispatch(d->libinput);
- }
- litest_touch_move_extended(d, slot, x_to, y_to, axes);
- }
- static int
- auto_assign_tablet_value(struct litest_device *d,
- const struct input_event *ev,
- int x,
- int y,
- struct axis_replacement *axes)
- {
- static int tracking_id;
- int value = ev->value;
- if (ev->type != EV_ABS)
- return value;
- switch (ev->code) {
- case ABS_MT_TRACKING_ID:
- value = ++tracking_id;
- break;
- case ABS_X:
- case ABS_MT_POSITION_X:
- value = litest_scale(d, ABS_X, x);
- break;
- case ABS_Y:
- case ABS_MT_POSITION_Y:
- value = litest_scale(d, ABS_Y, y);
- break;
- default:
- if (!axis_replacement_value(d, axes, ev->code, &value) &&
- value == LITEST_AUTO_ASSIGN && d->interface->get_axis_default) {
- int error = d->interface->get_axis_default(d, ev->code, &value);
- if (error) {
- litest_abort_msg(
- "Failed to get default axis value for %s (%d)",
- libevdev_event_code_get_name(EV_ABS, ev->code),
- ev->code);
- }
- }
- break;
- }
- return value;
- }
- static int
- tablet_ignore_event(const struct input_event *ev, int value)
- {
- return value == -1 && (ev->code == ABS_PRESSURE || ev->code == ABS_DISTANCE);
- }
- void
- litest_tablet_set_tool_type(struct litest_device *d, unsigned int code)
- {
- switch (code) {
- case BTN_TOOL_PEN:
- case BTN_TOOL_RUBBER:
- case BTN_TOOL_BRUSH:
- case BTN_TOOL_PENCIL:
- case BTN_TOOL_AIRBRUSH:
- case BTN_TOOL_MOUSE:
- case BTN_TOOL_LENS:
- break;
- default:
- abort();
- }
- d->interface->tool_type = code;
- }
- static void
- litest_tool_event(struct litest_device *d, int value)
- {
- unsigned int tool = d->interface->tool_type;
- litest_event(d, EV_KEY, tool, value);
- }
- void
- litest_tablet_proximity_in(struct litest_device *d,
- double x,
- double y,
- struct axis_replacement *axes)
- {
- struct input_event *ev;
- /* If the test device overrides proximity_in and says it didn't
- * handle the event, let's continue normally */
- if (d->interface->tablet_proximity_in &&
- d->interface->tablet_proximity_in(d, d->interface->tool_type, &x, &y, axes))
- return;
- ev = d->interface->tablet_proximity_in_events;
- while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
- int value;
- switch (evbit(ev->type, ev->code)) {
- case evbit(EV_KEY, LITEST_BTN_TOOL_AUTO):
- litest_tool_event(d, ev->value);
- break;
- default:
- value = auto_assign_tablet_value(d, ev, x, y, axes);
- if (!tablet_ignore_event(ev, value))
- litest_event(d, ev->type, ev->code, value);
- }
- ev++;
- }
- }
- void
- litest_tablet_proximity_out(struct litest_device *d)
- {
- struct input_event *ev;
- /* If the test device overrides proximity_out and says it didn't
- * handle the event, let's continue normally */
- if (d->interface->tablet_proximity_out &&
- d->interface->tablet_proximity_out(d, d->interface->tool_type))
- return;
- ev = d->interface->tablet_proximity_out_events;
- while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
- int value;
- switch (evbit(ev->type, ev->code)) {
- case evbit(EV_KEY, LITEST_BTN_TOOL_AUTO):
- litest_tool_event(d, ev->value);
- break;
- case evbit(EV_ABS, ABS_MT_TRACKING_ID):
- if (ev->value == -1) {
- litest_event(d, ev->type, ev->code, ev->value);
- break;
- }
- _fallthrough_;
- default:
- value = auto_assign_tablet_value(d, ev, 0, 0, NULL);
- if (!tablet_ignore_event(ev, value))
- litest_event(d, ev->type, ev->code, value);
- break;
- }
- ev++;
- }
- }
- void
- litest_tablet_motion(struct litest_device *d,
- double x,
- double y,
- struct axis_replacement *axes)
- {
- struct input_event *ev;
- /* If the test device overrides proximity_out and says it didn't
- * handle the event, let's continue normally */
- if (d->interface->tablet_motion && d->interface->tablet_motion(d, &x, &y, axes))
- return;
- ev = d->interface->tablet_motion_events;
- while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
- int value = auto_assign_tablet_value(d, ev, x, y, axes);
- if (!tablet_ignore_event(ev, value))
- litest_event(d, ev->type, ev->code, value);
- ev++;
- }
- }
- void
- litest_tablet_tip_down(struct litest_device *d,
- double x,
- double y,
- struct axis_replacement *axes)
- {
- /* If the test device overrides tip_down and says it didn't
- * handle the event, let's continue normally */
- if (d->interface->tablet_tip_down &&
- d->interface->tablet_tip_down(d, &x, &y, axes))
- return;
- litest_event(d, EV_KEY, BTN_TOUCH, 1);
- litest_tablet_motion(d, x, y, axes);
- }
- void
- litest_tablet_tip_up(struct litest_device *d,
- double x,
- double y,
- struct axis_replacement *axes)
- {
- /* If the test device overrides tip_down and says it didn't
- * handle the event, let's continue normally */
- if (d->interface->tablet_tip_up && d->interface->tablet_tip_up(d, &x, &y, axes))
- return;
- litest_event(d, EV_KEY, BTN_TOUCH, 0);
- litest_tablet_motion(d, x, y, axes);
- }
- void
- litest_touch_move_two_touches(struct litest_device *d,
- double x0,
- double y0,
- double x1,
- double y1,
- double dx,
- double dy,
- int steps)
- {
- int sleep_ms = 10;
- for (int i = 1; i < steps; i++) {
- litest_with_event_frame(d) {
- litest_touch_move(d,
- 0,
- x0 + dx / steps * i,
- y0 + dy / steps * i);
- litest_touch_move(d,
- 1,
- x1 + dx / steps * i,
- y1 + dy / steps * i);
- }
- libinput_dispatch(d->libinput);
- msleep(sleep_ms);
- libinput_dispatch(d->libinput);
- }
- litest_with_event_frame(d) {
- litest_touch_move(d, 0, x0 + dx, y0 + dy);
- litest_touch_move(d, 1, x1 + dx, y1 + dy);
- }
- }
- void
- litest_touch_move_three_touches(struct litest_device *d,
- double x0,
- double y0,
- double x1,
- double y1,
- double x2,
- double y2,
- double dx,
- double dy,
- int steps)
- {
- int sleep_ms = 10;
- for (int i = 1; i <= steps; i++) {
- double step_x = dx / steps * i;
- double step_y = dy / steps * i;
- litest_with_event_frame(d) {
- litest_touch_move(d, 0, x0 + step_x, y0 + step_y);
- litest_touch_move(d, 1, x1 + step_x, y1 + step_y);
- litest_touch_move(d, 2, x2 + step_x, y2 + step_y);
- }
- libinput_dispatch(d->libinput);
- msleep(sleep_ms);
- }
- libinput_dispatch(d->libinput);
- }
- void
- litest_hover_start(struct litest_device *d, unsigned int slot, double x, double y)
- {
- struct axis_replacement axes[] = {
- { ABS_MT_PRESSURE, 0 },
- { ABS_PRESSURE, 0 },
- { -1, -1 },
- };
- litest_slot_start(d, slot, x, y, axes, 0);
- }
- void
- litest_hover_end(struct litest_device *d, unsigned int slot)
- {
- struct input_event *ev;
- struct input_event up[] = {
- { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
- { .type = EV_ABS, .code = ABS_MT_DISTANCE, .value = 1 },
- { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = -1 },
- { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
- { .type = -1, .code = -1 }
- };
- litest_assert_int_gt(d->ntouches_down, 0);
- d->ntouches_down--;
- send_btntool(d, true);
- if (d->interface->touch_up) {
- d->interface->touch_up(d, slot);
- return;
- } else if (d->interface->touch_up_events) {
- ev = d->interface->touch_up_events;
- } else
- ev = up;
- while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
- int value = litest_auto_assign_value(d, ev, slot, 0, 0, NULL, false);
- litest_event(d, ev->type, ev->code, value);
- ev++;
- }
- }
- void
- litest_hover_move(struct litest_device *d, unsigned int slot, double x, double y)
- {
- struct axis_replacement axes[] = {
- { ABS_MT_PRESSURE, 0 },
- { ABS_PRESSURE, 0 },
- { -1, -1 },
- };
- litest_slot_move(d, slot, x, y, axes, false);
- }
- void
- litest_hover_move_to(struct litest_device *d,
- unsigned int slot,
- double x_from,
- double y_from,
- double x_to,
- double y_to,
- int steps)
- {
- int sleep_ms = 10;
- for (int i = 0; i < steps - 1; i++) {
- litest_hover_move(d,
- slot,
- x_from + (x_to - x_from) / steps * i,
- y_from + (y_to - y_from) / steps * i);
- libinput_dispatch(d->libinput);
- msleep(sleep_ms);
- libinput_dispatch(d->libinput);
- }
- litest_hover_move(d, slot, x_to, y_to);
- }
- void
- litest_hover_move_two_touches(struct litest_device *d,
- double x0,
- double y0,
- double x1,
- double y1,
- double dx,
- double dy,
- int steps)
- {
- int sleep_ms = 10;
- for (int i = 0; i < steps - 1; i++) {
- litest_with_event_frame(d) {
- litest_hover_move(d,
- 0,
- x0 + dx / steps * i,
- y0 + dy / steps * i);
- litest_hover_move(d,
- 1,
- x1 + dx / steps * i,
- y1 + dy / steps * i);
- }
- libinput_dispatch(d->libinput);
- msleep(sleep_ms);
- libinput_dispatch(d->libinput);
- }
- litest_with_event_frame(d) {
- litest_hover_move(d, 0, x0 + dx, y0 + dy);
- litest_hover_move(d, 1, x1 + dx, y1 + dy);
- }
- }
- void
- litest_button_click(struct litest_device *d, unsigned int button, bool is_press)
- {
- struct input_event click[] = {
- { .type = EV_KEY, .code = button, .value = is_press ? 1 : 0 },
- { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
- };
- ARRAY_FOR_EACH(click, ev)
- litest_event(d, ev->type, ev->code, ev->value);
- }
- void
- litest_button_click_debounced(struct litest_device *d,
- struct libinput *li,
- unsigned int button,
- bool is_press)
- {
- litest_button_click(d, button, is_press);
- litest_timeout_debounce(li);
- }
- void
- litest_button_scroll(struct litest_device *dev,
- unsigned int button,
- double dx,
- double dy)
- {
- struct libinput *li = dev->libinput;
- litest_button_click_debounced(dev, li, button, 1);
- litest_timeout_buttonscroll(li);
- litest_event(dev, EV_REL, REL_X, dx);
- litest_event(dev, EV_REL, REL_Y, dy);
- litest_event(dev, EV_SYN, SYN_REPORT, 0);
- litest_button_click_debounced(dev, li, button, 0);
- libinput_dispatch(li);
- }
- void
- litest_button_scroll_locked(struct litest_device *dev,
- unsigned int button,
- double dx,
- double dy)
- {
- struct libinput *li = dev->libinput;
- litest_button_click_debounced(dev, li, button, 1);
- litest_button_click_debounced(dev, li, button, 0);
- litest_timeout_buttonscroll(li);
- litest_event(dev, EV_REL, REL_X, dx);
- litest_event(dev, EV_REL, REL_Y, dy);
- litest_event(dev, EV_SYN, SYN_REPORT, 0);
- libinput_dispatch(li);
- }
- void
- litest_keyboard_key(struct litest_device *d, unsigned int key, bool is_press)
- {
- struct input_event click[] = {
- { .type = EV_KEY, .code = key, .value = is_press ? 1 : 0 },
- { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
- };
- ARRAY_FOR_EACH(click, ev)
- litest_event(d, ev->type, ev->code, ev->value);
- }
- void
- litest_switch_action(struct litest_device *dev,
- enum libinput_switch sw,
- enum libinput_switch_state state)
- {
- unsigned int code;
- switch (sw) {
- case LIBINPUT_SWITCH_LID:
- code = SW_LID;
- break;
- case LIBINPUT_SWITCH_TABLET_MODE:
- code = SW_TABLET_MODE;
- break;
- case LIBINPUT_SWITCH_KEYPAD_SLIDE:
- code = SW_KEYPAD_SLIDE;
- break;
- default:
- litest_abort_msg("Invalid switch %d", sw);
- break;
- }
- litest_event(dev, EV_SW, code, state);
- litest_event(dev, EV_SYN, SYN_REPORT, 0);
- }
- static int
- litest_scale_axis(const struct litest_device *d, unsigned int axis, double val)
- {
- const struct input_absinfo *abs;
- litest_assert_double_ge(val, 0.0);
- /* major/minor must be able to beyond 100% for large fingers */
- if (axis != ABS_MT_TOUCH_MAJOR && axis != ABS_MT_TOUCH_MINOR) {
- litest_assert_double_le(val, 100.0);
- }
- abs = libevdev_get_abs_info(d->evdev, axis);
- litest_assert_notnull(abs);
- return (abs->maximum - abs->minimum) * val / 100.0 + abs->minimum;
- }
- static inline int
- litest_scale_range(int min, int max, double val)
- {
- litest_assert_int_ge((int)val, 0);
- litest_assert_int_le((int)val, 100);
- return (max - min) * val / 100.0 + min;
- }
- int
- litest_scale(const struct litest_device *d, unsigned int axis, double val)
- {
- int min, max;
- litest_assert_double_ge(val, 0.0);
- /* major/minor must be able to beyond 100% for large fingers */
- if (axis != ABS_MT_TOUCH_MAJOR && axis != ABS_MT_TOUCH_MINOR)
- litest_assert_double_le(val, 100.0);
- if (axis <= ABS_Y) {
- min = d->interface->min[axis];
- max = d->interface->max[axis];
- return litest_scale_range(min, max, val);
- } else {
- return litest_scale_axis(d, axis, val);
- }
- }
- static inline int
- auto_assign_pad_value(struct litest_device *dev, struct input_event *ev, double value)
- {
- const struct input_absinfo *abs;
- if (ev->value != LITEST_AUTO_ASSIGN)
- return value;
- if (ev->type == EV_REL) {
- switch (ev->code) {
- case REL_WHEEL:
- case REL_HWHEEL:
- case REL_DIAL:
- assert(fmod(value, 120.0) ==
- 0.0); /* Fractions not supported yet */
- return value / 120.0;
- default:
- return value;
- }
- } else if (ev->type != EV_ABS) {
- return value;
- }
- abs = libevdev_get_abs_info(dev->evdev, ev->code);
- litest_assert_notnull(abs);
- if (ev->code == ABS_RX || ev->code == ABS_RY) {
- double min = abs->minimum != 0 ? log2(abs->minimum) : 0,
- max = abs->maximum != 0 ? log2(abs->maximum) : 0;
- /* Value 0 is reserved for finger up, so a value of 0% is
- * actually 1 */
- if (value == 0.0) {
- return 1;
- } else {
- value = litest_scale_range(min, max, value);
- return pow(2, value);
- }
- } else {
- return litest_scale_range(abs->minimum, abs->maximum, value);
- }
- }
- static void
- litest_pad_events(struct litest_device *d, struct input_event *evs, double value)
- {
- while (evs && (int16_t)evs->type != -1 && (int16_t)evs->code != -1) {
- if (evs->type == EV_SYN && evs->code == SYN_REPORT)
- value = 0;
- value = auto_assign_pad_value(d, evs, value);
- litest_event(d, evs->type, evs->code, value);
- evs++;
- }
- }
- void
- litest_pad_ring_start(struct litest_device *d, double value)
- {
- litest_pad_events(d, d->interface->pad_ring_start_events, value);
- }
- void
- litest_pad_ring_change(struct litest_device *d, double value)
- {
- litest_pad_events(d, d->interface->pad_ring_change_events, value);
- }
- void
- litest_pad_ring_end(struct litest_device *d)
- {
- struct input_event *ev;
- ev = d->interface->pad_ring_end_events;
- while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
- litest_event(d, ev->type, ev->code, ev->value);
- ev++;
- }
- }
- void
- litest_pad_strip_start(struct litest_device *d, double value)
- {
- litest_pad_events(d, d->interface->pad_strip_start_events, value);
- }
- void
- litest_pad_strip_change(struct litest_device *d, double value)
- {
- litest_pad_events(d, d->interface->pad_strip_change_events, value);
- }
- void
- litest_pad_strip_end(struct litest_device *d)
- {
- struct input_event *ev;
- ev = d->interface->pad_strip_end_events;
- while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
- litest_event(d, ev->type, ev->code, ev->value);
- ev++;
- }
- }
- void
- litest_wait_for_event(struct libinput *li)
- {
- return litest_wait_for_event_of_type(li, -1);
- }
- void
- _litest_wait_for_event_of_type(struct libinput *li, const char *func, int lineno, ...)
- {
- va_list args;
- enum libinput_event_type types[32] = { LIBINPUT_EVENT_NONE };
- size_t ntypes = 0;
- enum libinput_event_type type;
- struct pollfd fds;
- va_start(args, lineno);
- type = va_arg(args, int);
- while ((int)type != -1) {
- litest_assert_int_gt(type, 0U);
- litest_assert_int_lt(ntypes, ARRAY_LENGTH(types));
- types[ntypes++] = type;
- type = va_arg(args, int);
- }
- va_end(args);
- fds.fd = libinput_get_fd(li);
- fds.events = POLLIN;
- fds.revents = 0;
- const int timeout = 2000;
- usec_t expiry = usec_from_uint64_t(0);
- int rc = now_in_us(&expiry);
- expiry = usec_add_millis(expiry, timeout);
- litest_assert_errno_success(rc);
- while (1) {
- size_t i;
- enum libinput_event_type type;
- while ((type = libinput_next_event_type(li)) == LIBINPUT_EVENT_NONE) {
- int rc = poll(&fds, 1, timeout);
- litest_assert_errno_success(rc);
- litest_assert_int_gt(rc, 0);
- litest_dispatch(li);
- }
- if (type == LIBINPUT_EVENT_NONE) {
- usec_t now;
- now_in_us(&now);
- if (usec_cmp(now, expiry) > 0) {
- _litest_abort_msg(
- NULL,
- lineno,
- func,
- "Waited >%dms for events, but no events are pending",
- timeout);
- }
- }
- /* no event mask means wait for any event */
- if (ntypes == 0)
- return;
- for (i = 0; i < ntypes; i++) {
- if (type == types[i])
- return;
- }
- _destroy_(libinput_event) *event = libinput_get_event(li);
- if (verbose) {
- litest_print_event(event, "Discarding event while waiting: ");
- }
- }
- }
- void
- litest_drain_events(struct libinput *li)
- {
- do {
- libinput_dispatch(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- if (!event)
- break;
- if (verbose) {
- litest_print_event(event, "litest: draining event: ");
- }
- } while (true);
- }
- void
- _litest_drain_events_of_type(struct libinput *li, ...)
- {
- enum libinput_event_type type;
- enum libinput_event_type types[32] = { LIBINPUT_EVENT_NONE };
- size_t ntypes = 0;
- va_list args;
- va_start(args, li);
- type = va_arg(args, int);
- while ((int)type != -1) {
- litest_assert_int_gt(type, 0U);
- litest_assert_int_lt(ntypes, ARRAY_LENGTH(types));
- types[ntypes++] = type;
- type = va_arg(args, int);
- }
- va_end(args);
- libinput_dispatch(li);
- type = libinput_next_event_type(li);
- while (type != LIBINPUT_EVENT_NONE) {
- bool found = false;
- type = libinput_next_event_type(li);
- for (size_t i = 0; i < ntypes; i++) {
- if (type == types[i]) {
- found = true;
- break;
- }
- }
- if (!found)
- return;
- _destroy_(libinput_event) *event = libinput_get_event(li);
- if (verbose)
- litest_print_event(event, "litest: draining typed event: ");
- libinput_dispatch(li);
- }
- }
- const char *
- litest_event_type_str(enum libinput_event_type type)
- {
- const char *str = NULL;
- switch (type) {
- case LIBINPUT_EVENT_NONE:
- abort();
- case LIBINPUT_EVENT_DEVICE_ADDED:
- str = "ADDED";
- break;
- case LIBINPUT_EVENT_DEVICE_REMOVED:
- str = "REMOVED";
- break;
- case LIBINPUT_EVENT_KEYBOARD_KEY:
- str = "KEY";
- break;
- case LIBINPUT_EVENT_POINTER_MOTION:
- str = "MOTION";
- break;
- case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
- str = "ABSOLUTE";
- break;
- case LIBINPUT_EVENT_POINTER_BUTTON:
- str = "BUTTON";
- break;
- case LIBINPUT_EVENT_POINTER_AXIS:
- str = "AXIS";
- break;
- case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
- str = "SCROLL_WHEEL";
- break;
- case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
- str = "SCROLL_FINGER";
- break;
- case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
- str = "SCROLL_CONTINUOUS";
- break;
- case LIBINPUT_EVENT_TOUCH_DOWN:
- str = "TOUCH DOWN";
- break;
- case LIBINPUT_EVENT_TOUCH_UP:
- str = "TOUCH UP";
- break;
- case LIBINPUT_EVENT_TOUCH_MOTION:
- str = "TOUCH MOTION";
- break;
- case LIBINPUT_EVENT_TOUCH_CANCEL:
- str = "TOUCH CANCEL";
- break;
- case LIBINPUT_EVENT_TOUCH_FRAME:
- str = "TOUCH FRAME";
- break;
- case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
- str = "GESTURE SWIPE BEGIN";
- break;
- case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
- str = "GESTURE SWIPE UPDATE";
- break;
- case LIBINPUT_EVENT_GESTURE_SWIPE_END:
- str = "GESTURE SWIPE END";
- break;
- case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
- str = "GESTURE PINCH BEGIN";
- break;
- case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
- str = "GESTURE PINCH UPDATE";
- break;
- case LIBINPUT_EVENT_GESTURE_PINCH_END:
- str = "GESTURE PINCH END";
- break;
- case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN:
- str = "GESTURE HOLD BEGIN";
- break;
- case LIBINPUT_EVENT_GESTURE_HOLD_END:
- str = "GESTURE HOLD END";
- break;
- case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
- str = "TABLET TOOL AXIS";
- break;
- case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
- str = "TABLET TOOL PROX";
- break;
- case LIBINPUT_EVENT_TABLET_TOOL_TIP:
- str = "TABLET TOOL TIP";
- break;
- case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
- str = "TABLET TOOL BUTTON";
- break;
- case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
- str = "TABLET PAD BUTTON";
- break;
- case LIBINPUT_EVENT_TABLET_PAD_RING:
- str = "TABLET PAD RING";
- break;
- case LIBINPUT_EVENT_TABLET_PAD_STRIP:
- str = "TABLET PAD STRIP";
- break;
- case LIBINPUT_EVENT_TABLET_PAD_KEY:
- str = "TABLET PAD KEY";
- break;
- case LIBINPUT_EVENT_TABLET_PAD_DIAL:
- str = "TABLET PAD DIAL";
- break;
- case LIBINPUT_EVENT_SWITCH_TOGGLE:
- str = "SWITCH TOGGLE";
- break;
- }
- return str;
- }
- static const char *
- litest_event_get_type_str(struct libinput_event *event)
- {
- return litest_event_type_str(libinput_event_get_type(event));
- }
- static void
- litest_print_event(struct libinput_event *event, const char *message)
- {
- _autofree_ char *event_str = libinput_event_to_str(event, 0, NULL);
- fprintf(stderr, "litest: %s %s\n", message, event_str);
- }
- void
- _litest_assert_event_type_is_one_of(struct libinput_event *event,
- const char *func,
- int lineno,
- ...)
- {
- va_list args;
- enum libinput_event_type expected_type;
- enum libinput_event_type actual_type = libinput_event_get_type(event);
- bool match = false;
- va_start(args, lineno);
- expected_type = va_arg(args, int);
- while ((int)expected_type != -1 && !match) {
- match = (actual_type == expected_type);
- expected_type = va_arg(args, int);
- }
- va_end(args);
- if (match)
- return;
- fprintf(stderr,
- "FAILED EVENT TYPE: %s: have %s (%d) but want ",
- libinput_device_get_name(libinput_event_get_device(event)),
- litest_event_get_type_str(event),
- libinput_event_get_type(event));
- va_start(args, lineno);
- expected_type = va_arg(args, int);
- while ((int)expected_type != -1) {
- fprintf(stderr,
- "%s (%d)",
- litest_event_type_str(expected_type),
- expected_type);
- expected_type = va_arg(args, int);
- if ((int)expected_type != -1)
- fprintf(stderr, " || ");
- }
- va_end(args);
- fprintf(stderr, "\n");
- litest_print_event(event, "Wrong event is:");
- litest_backtrace(func);
- litest_runner_abort();
- }
- void
- _litest_assert_event_type(struct libinput_event *event,
- enum libinput_event_type want,
- const char *func,
- int lineno)
- {
- _litest_assert_event_type_is_one_of(event, func, lineno, want, -1);
- }
- void
- _litest_assert_event_type_not_one_of(struct libinput_event *event,
- const char *func,
- int lineno,
- ...)
- {
- va_list args;
- enum libinput_event_type not_expected_type;
- enum libinput_event_type actual_type = libinput_event_get_type(event);
- bool match = false;
- va_start(args, lineno);
- not_expected_type = va_arg(args, int);
- while ((int)not_expected_type != -1 && !match) {
- match = (actual_type == not_expected_type);
- not_expected_type = va_arg(args, int);
- }
- va_end(args);
- if (!match)
- return;
- fprintf(stderr,
- "FAILED EVENT TYPE: %s: have %s (%d) but didn't want that\n",
- libinput_device_get_name(libinput_event_get_device(event)),
- litest_event_get_type_str(event),
- libinput_event_get_type(event));
- litest_print_event(event, "\nWrong event is: ");
- litest_backtrace(func);
- litest_runner_abort();
- }
- void
- _litest_assert_empty_queue(struct libinput *li, const char *func, int line)
- {
- bool empty_queue = true;
- struct libinput_event *event;
- _litest_checkpoint(func, line, ANSI_BRIGHT_CYAN, "asserting empty queue");
- libinput_dispatch(li);
- while ((event = libinput_get_event(li))) {
- empty_queue = false;
- litest_print_event(event, "Unexpected event: ");
- libinput_event_destroy(event);
- libinput_dispatch(li);
- }
- litest_assert(empty_queue);
- }
- static struct libevdev_uinput *
- litest_create_uinput(const char *name,
- const struct input_id *id,
- const struct input_absinfo *abs_info,
- const int *events)
- {
- struct libevdev_uinput *uinput;
- _free_(libevdev) *dev = libevdev_new();
- int type, code;
- int rc;
- const struct input_absinfo *abs;
- const struct input_absinfo default_abs = { .value = 0,
- .minimum = 0,
- .maximum = 100,
- .fuzz = 0,
- .flat = 0,
- .resolution = 100 };
- /* See kernel commit 206f533a0a7c ("Input: uinput - reject requests with
- * unreasonable number of slots") */
- const struct input_absinfo default_abs_mt_slot = { .value = 0,
- .minimum = 0,
- .maximum = 64,
- .fuzz = 0,
- .flat = 0,
- .resolution = 100 };
- char buf[512];
- litest_assert_ptr_notnull(dev);
- snprintf(buf, sizeof(buf), "litest %s", name);
- libevdev_set_name(dev, buf);
- if (id) {
- libevdev_set_id_bustype(dev, id->bustype);
- libevdev_set_id_vendor(dev, id->vendor);
- libevdev_set_id_product(dev, id->product);
- libevdev_set_id_version(dev, id->version);
- }
- abs = abs_info;
- while (abs && abs->value != -1) {
- struct input_absinfo a = *abs;
- /* abs_info->value is used for the code and may be outside
- of [min, max] */
- a.value = abs->minimum;
- rc = libevdev_enable_event_code(dev, EV_ABS, abs->value, &a);
- litest_assert_int_eq(rc, 0);
- abs++;
- }
- while (events && (type = *events++) != -1 && (code = *events++) != -1) {
- if (type == INPUT_PROP_MAX) {
- rc = libevdev_enable_property(dev, code);
- } else {
- const struct input_absinfo *abs = (code == ABS_MT_SLOT)
- ? &default_abs_mt_slot
- : &default_abs;
- rc = libevdev_enable_event_code(dev,
- type,
- code,
- type == EV_ABS ? abs : NULL);
- }
- litest_assert_int_eq(rc, 0);
- }
- rc = libevdev_uinput_create_from_device(dev,
- LIBEVDEV_UINPUT_OPEN_MANAGED,
- &uinput);
- litest_assert_msg(rc == 0,
- "Failed to create uinput device: %s\n",
- strerror(-rc));
- return uinput;
- }
- struct libevdev_uinput *
- litest_create_uinput_device_from_description(const char *name,
- const struct input_id *id,
- const struct input_absinfo *abs_info,
- const int *events)
- {
- struct libevdev_uinput *uinput;
- const char *syspath;
- char path[PATH_MAX];
- _unref_(udev_monitor) *udev_monitor = udev_setup_monitor();
- _unref_(udev_device) *udev_device = NULL;
- uinput = litest_create_uinput(name, id, abs_info, events);
- syspath = libevdev_uinput_get_syspath(uinput);
- snprintf(path, sizeof(path), "%s/event", syspath);
- udev_device = udev_wait_for_device_event(udev_monitor, "add", path);
- litest_assert(udev_device_get_property_value(udev_device, "ID_INPUT"));
- return uinput;
- }
- static struct libevdev_uinput *
- litest_create_uinput_abs_device_v(const char *name,
- struct input_id *id,
- const struct input_absinfo *abs,
- va_list args)
- {
- int events[KEY_MAX * 2 + 2]; /* increase this if not sufficient */
- int *event = events;
- int type, code;
- while ((type = va_arg(args, int)) != -1 && (code = va_arg(args, int)) != -1) {
- *event++ = type;
- *event++ = code;
- litest_assert(event < &events[ARRAY_LENGTH(events) - 2]);
- }
- *event++ = -1;
- *event++ = -1;
- return litest_create_uinput_device_from_description(name, id, abs, events);
- }
- struct libevdev_uinput *
- litest_create_uinput_abs_device(const char *name,
- struct input_id *id,
- const struct input_absinfo *abs,
- ...)
- {
- struct libevdev_uinput *uinput;
- va_list args;
- va_start(args, abs);
- uinput = litest_create_uinput_abs_device_v(name, id, abs, args);
- va_end(args);
- return uinput;
- }
- struct libevdev_uinput *
- litest_create_uinput_device(const char *name, struct input_id *id, ...)
- {
- struct libevdev_uinput *uinput;
- va_list args;
- va_start(args, id);
- uinput = litest_create_uinput_abs_device_v(name, id, NULL, args);
- va_end(args);
- return uinput;
- }
- struct libinput_event_pointer *
- litest_is_button_event(struct libinput_event *event,
- unsigned int button,
- enum libinput_button_state state)
- {
- struct libinput_event_pointer *ptrev;
- enum libinput_event_type type = LIBINPUT_EVENT_POINTER_BUTTON;
- litest_assert_ptr_notnull(event);
- litest_assert_event_type(event, type);
- ptrev = libinput_event_get_pointer_event(event);
- litest_assert_int_eq(libinput_event_pointer_get_button(ptrev), button);
- litest_assert_int_eq(libinput_event_pointer_get_button_state(ptrev), state);
- return ptrev;
- }
- struct libinput_event_pointer *
- litest_is_axis_event(struct libinput_event *event,
- enum libinput_event_type axis_type,
- enum libinput_pointer_axis axis,
- enum libinput_pointer_axis_source source)
- {
- struct libinput_event_pointer *ptrev;
- litest_assert(axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL ||
- axis_type == LIBINPUT_EVENT_POINTER_SCROLL_FINGER ||
- axis_type == LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
- litest_assert_ptr_notnull(event);
- litest_assert_event_type_is_one_of(event,
- LIBINPUT_EVENT_POINTER_AXIS,
- axis_type);
- ptrev = libinput_event_get_pointer_event(event);
- litest_assert(libinput_event_pointer_has_axis(ptrev, axis));
- if (source != 0)
- litest_assert_int_eq(litest_event_pointer_get_axis_source(ptrev),
- source);
- return ptrev;
- }
- bool
- litest_is_high_res_axis_event(struct libinput_event *event)
- {
- litest_assert_event_type_is_one_of(event,
- LIBINPUT_EVENT_POINTER_AXIS,
- LIBINPUT_EVENT_POINTER_SCROLL_WHEEL,
- LIBINPUT_EVENT_POINTER_SCROLL_FINGER,
- LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
- return (libinput_event_get_type(event) != LIBINPUT_EVENT_POINTER_AXIS);
- }
- struct libinput_event_pointer *
- litest_is_motion_event(struct libinput_event *event)
- {
- struct libinput_event_pointer *ptrev;
- enum libinput_event_type type = LIBINPUT_EVENT_POINTER_MOTION;
- double x, y, ux, uy;
- litest_assert_ptr_notnull(event);
- litest_assert_event_type(event, type);
- ptrev = libinput_event_get_pointer_event(event);
- x = libinput_event_pointer_get_dx(ptrev);
- y = libinput_event_pointer_get_dy(ptrev);
- ux = libinput_event_pointer_get_dx_unaccelerated(ptrev);
- uy = libinput_event_pointer_get_dy_unaccelerated(ptrev);
- /* No 0 delta motion events */
- litest_assert(x != 0.0 || y != 0.0 || ux != 0.0 || uy != 0.0);
- return ptrev;
- }
- void
- _litest_assert_key_event(struct libinput *li,
- unsigned int key,
- enum libinput_key_state state,
- const char *func,
- int lineno)
- {
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_is_keyboard_event(event, key, state);
- }
- void
- _litest_assert_button_event(struct libinput *li,
- unsigned int button,
- enum libinput_button_state state,
- const char *func,
- int line)
- {
- _litest_checkpoint(func,
- line,
- ANSI_CYAN,
- "asserting button event %s (%d) state %d",
- libevdev_event_code_get_name(EV_KEY, button),
- button,
- state);
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_is_button_event(event, button, state);
- }
- struct libinput_event_touch *
- litest_is_touch_event(struct libinput_event *event, enum libinput_event_type type)
- {
- struct libinput_event_touch *touch;
- litest_assert_ptr_notnull(event);
- if (type == 0)
- type = libinput_event_get_type(event);
- switch (type) {
- case LIBINPUT_EVENT_TOUCH_DOWN:
- case LIBINPUT_EVENT_TOUCH_UP:
- case LIBINPUT_EVENT_TOUCH_MOTION:
- case LIBINPUT_EVENT_TOUCH_FRAME:
- case LIBINPUT_EVENT_TOUCH_CANCEL:
- litest_assert_event_type(event, type);
- break;
- default:
- litest_abort_msg("%s: invalid touch type %d", __func__, type);
- }
- touch = libinput_event_get_touch_event(event);
- return touch;
- }
- struct libinput_event_keyboard *
- litest_is_keyboard_event(struct libinput_event *event,
- unsigned int key,
- enum libinput_key_state state)
- {
- struct libinput_event_keyboard *kevent;
- enum libinput_event_type type = LIBINPUT_EVENT_KEYBOARD_KEY;
- litest_assert_ptr_notnull(event);
- litest_assert_event_type(event, type);
- kevent = libinput_event_get_keyboard_event(event);
- litest_assert_ptr_notnull(kevent);
- litest_assert_int_eq(libinput_event_keyboard_get_key(kevent), key);
- litest_assert_int_eq(libinput_event_keyboard_get_key_state(kevent), state);
- return kevent;
- }
- struct libinput_event_gesture *
- litest_is_gesture_event(struct libinput_event *event,
- enum libinput_event_type type,
- int nfingers)
- {
- struct libinput_event_gesture *gevent;
- litest_assert_ptr_notnull(event);
- litest_assert_event_type(event, type);
- gevent = libinput_event_get_gesture_event(event);
- litest_assert_ptr_notnull(gevent);
- if (nfingers != -1)
- litest_assert_int_eq(libinput_event_gesture_get_finger_count(gevent),
- nfingers);
- return gevent;
- }
- void
- _litest_assert_gesture_event(struct libinput *li,
- enum libinput_event_type type,
- int nfingers,
- const char *func,
- int line)
- {
- _litest_checkpoint(func,
- line,
- ANSI_CYAN,
- "asserting gesture event %s %dfg",
- litest_event_type_str(type),
- nfingers);
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_is_gesture_event(event, type, nfingers);
- }
- struct libinput_event_tablet_tool *
- litest_is_tablet_event(struct libinput_event *event, enum libinput_event_type type)
- {
- struct libinput_event_tablet_tool *tevent;
- litest_assert_ptr_notnull(event);
- litest_assert_event_type(event, type);
- tevent = libinput_event_get_tablet_tool_event(event);
- litest_assert_ptr_notnull(tevent);
- return tevent;
- }
- void
- _litest_assert_tablet_button_event(struct libinput *li,
- unsigned int button,
- enum libinput_button_state state,
- const char *func,
- int lineno)
- {
- struct libinput_event_tablet_tool *tev;
- enum libinput_event_type type = LIBINPUT_EVENT_TABLET_TOOL_BUTTON;
- _litest_checkpoint(func,
- lineno,
- ANSI_CYAN,
- "asserting tablet button event button %d down: %s",
- button,
- yesno(state));
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_assert_notnull(event);
- litest_assert_event_type(event, type);
- tev = libinput_event_get_tablet_tool_event(event);
- litest_assert_int_eq(libinput_event_tablet_tool_get_button(tev), button);
- litest_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev), state);
- }
- struct libinput_event_tablet_tool *
- litest_is_proximity_event(struct libinput_event *event,
- enum libinput_tablet_tool_proximity_state state)
- {
- struct libinput_event_tablet_tool *tev;
- enum libinput_event_type type = LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY;
- litest_assert_notnull(event);
- litest_assert_event_type(event, type);
- tev = libinput_event_get_tablet_tool_event(event);
- litest_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
- state);
- return tev;
- }
- double
- litest_event_pointer_get_value(struct libinput_event_pointer *ptrev,
- enum libinput_pointer_axis axis)
- {
- struct libinput_event *event;
- enum libinput_event_type type;
- event = libinput_event_pointer_get_base_event(ptrev);
- type = libinput_event_get_type(event);
- switch (type) {
- case LIBINPUT_EVENT_POINTER_AXIS:
- return libinput_event_pointer_get_axis_value(ptrev, axis);
- case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
- return libinput_event_pointer_get_scroll_value_v120(ptrev, axis);
- case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
- case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
- return libinput_event_pointer_get_scroll_value(ptrev, axis);
- default:
- abort();
- }
- }
- enum libinput_pointer_axis_source
- litest_event_pointer_get_axis_source(struct libinput_event_pointer *ptrev)
- {
- struct libinput_event *event;
- enum libinput_event_type type;
- event = libinput_event_pointer_get_base_event(ptrev);
- type = libinput_event_get_type(event);
- if (type == LIBINPUT_EVENT_POINTER_AXIS)
- return libinput_event_pointer_get_axis_source(ptrev);
- switch (type) {
- case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
- return LIBINPUT_POINTER_AXIS_SOURCE_WHEEL;
- case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
- return LIBINPUT_POINTER_AXIS_SOURCE_FINGER;
- case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
- return LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS;
- default:
- abort();
- }
- }
- void
- _litest_assert_tablet_axis_event(struct libinput *li, const char *func, int lineno)
- {
- _litest_checkpoint(func, lineno, ANSI_CYAN, "asserting axis event");
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
- }
- void
- _litest_assert_tablet_proximity_event(struct libinput *li,
- enum libinput_tablet_tool_proximity_state state,
- const char *func,
- int lineno)
- {
- _litest_checkpoint(func,
- lineno,
- ANSI_CYAN,
- "asserting proximity %s event",
- state ? "in" : "out");
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_is_proximity_event(event, state);
- }
- void
- _litest_assert_tablet_tip_event(struct libinput *li,
- enum libinput_tablet_tool_tip_state state,
- const char *func,
- int lineno)
- {
- struct libinput_event_tablet_tool *tev;
- enum libinput_event_type type = LIBINPUT_EVENT_TABLET_TOOL_TIP;
- _litest_checkpoint(func,
- lineno,
- ANSI_CYAN,
- "asserting tip %s event",
- state ? "down" : "up");
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_assert_notnull(event);
- litest_assert_event_type(event, type);
- tev = libinput_event_get_tablet_tool_event(event);
- litest_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tev), state);
- }
- struct libinput_event_tablet_pad *
- litest_is_pad_button_event(struct libinput_event *event,
- unsigned int button,
- enum libinput_button_state state)
- {
- struct libinput_event_tablet_pad *p;
- enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_BUTTON;
- litest_assert_ptr_notnull(event);
- litest_assert_event_type(event, type);
- p = libinput_event_get_tablet_pad_event(event);
- litest_assert_ptr_notnull(p);
- litest_assert_int_eq(libinput_event_tablet_pad_get_button_number(p), button);
- litest_assert_int_eq(libinput_event_tablet_pad_get_button_state(p), state);
- return p;
- }
- struct libinput_event_tablet_pad *
- litest_is_pad_dial_event(struct libinput_event *event, unsigned int number)
- {
- struct libinput_event_tablet_pad *p;
- enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_DIAL;
- litest_assert_ptr_notnull(event);
- litest_assert_event_type(event, type);
- p = libinput_event_get_tablet_pad_event(event);
- litest_assert_int_eq(libinput_event_tablet_pad_get_dial_number(p), number);
- return p;
- }
- struct libinput_event_tablet_pad *
- litest_is_pad_ring_event(struct libinput_event *event,
- unsigned int number,
- enum libinput_tablet_pad_ring_axis_source source)
- {
- struct libinput_event_tablet_pad *p;
- enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_RING;
- litest_assert_ptr_notnull(event);
- litest_assert_event_type(event, type);
- p = libinput_event_get_tablet_pad_event(event);
- litest_assert_int_eq(libinput_event_tablet_pad_get_ring_number(p), number);
- litest_assert_int_eq(libinput_event_tablet_pad_get_ring_source(p), source);
- return p;
- }
- struct libinput_event_tablet_pad *
- litest_is_pad_strip_event(struct libinput_event *event,
- unsigned int number,
- enum libinput_tablet_pad_strip_axis_source source)
- {
- struct libinput_event_tablet_pad *p;
- enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_STRIP;
- litest_assert_ptr_notnull(event);
- litest_assert_event_type(event, type);
- p = libinput_event_get_tablet_pad_event(event);
- litest_assert_int_eq(libinput_event_tablet_pad_get_strip_number(p), number);
- litest_assert_int_eq(libinput_event_tablet_pad_get_strip_source(p), source);
- return p;
- }
- struct libinput_event_tablet_pad *
- litest_is_pad_key_event(struct libinput_event *event,
- unsigned int key,
- enum libinput_key_state state)
- {
- struct libinput_event_tablet_pad *p;
- enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_KEY;
- litest_assert(event != NULL);
- litest_assert_event_type(event, type);
- p = libinput_event_get_tablet_pad_event(event);
- litest_assert(p != NULL);
- litest_assert_int_eq(libinput_event_tablet_pad_get_key(p), key);
- litest_assert_int_eq(libinput_event_tablet_pad_get_key_state(p), state);
- return p;
- }
- struct libinput_event_switch *
- litest_is_switch_event(struct libinput_event *event,
- enum libinput_switch sw,
- enum libinput_switch_state state)
- {
- struct libinput_event_switch *swev;
- enum libinput_event_type type = LIBINPUT_EVENT_SWITCH_TOGGLE;
- litest_assert_notnull(event);
- litest_assert_event_type(event, type);
- swev = libinput_event_get_switch_event(event);
- litest_assert_int_eq(libinput_event_switch_get_switch(swev), sw);
- litest_assert_int_eq(libinput_event_switch_get_switch_state(swev), state);
- return swev;
- }
- void
- _litest_assert_switch_event(struct libinput *li,
- enum libinput_switch sw,
- enum libinput_switch_state state,
- const char *func,
- int lineno)
- {
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_is_switch_event(event, sw, state);
- }
- void
- _litest_assert_pad_button_event(struct libinput *li,
- unsigned int button,
- enum libinput_button_state state,
- const char *func,
- int lineno)
- {
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_is_pad_button_event(event, button, state);
- }
- void
- _litest_assert_pad_key_event(struct libinput *li,
- unsigned int key,
- enum libinput_key_state state,
- const char *func,
- int lineno)
- {
- litest_wait_for_event(li);
- _destroy_(libinput_event) *event = libinput_get_event(li);
- litest_is_pad_key_event(event, key, state);
- }
- void
- litest_assert_scroll(struct libinput *li,
- enum libinput_event_type axis_type,
- enum libinput_pointer_axis axis,
- int minimum_movement)
- {
- struct libinput_event *event;
- struct libinput_event_pointer *ptrev;
- bool last_hi_res_event_found, last_low_res_event_found;
- int value;
- int nevents = 0;
- litest_assert(axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL ||
- axis_type == LIBINPUT_EVENT_POINTER_SCROLL_FINGER ||
- axis_type == LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
- last_hi_res_event_found = false;
- last_low_res_event_found = false;
- event = libinput_get_event(li);
- litest_assert_ptr_notnull(event);
- while (event) {
- int min = minimum_movement;
- ptrev = litest_is_axis_event(event, axis_type, axis, 0);
- nevents++;
- /* Due to how the hysteresis works on touchpad
- * events, the first event is reduced by the
- * hysteresis margin that can cause the first event
- * go under the minimum we expect for all other
- * events */
- if (nevents == 1)
- min = minimum_movement / 2;
- value = litest_event_pointer_get_value(ptrev, axis);
- if (litest_is_high_res_axis_event(event)) {
- litest_assert(!last_hi_res_event_found);
- if (axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL)
- min *= 120;
- if (value == 0)
- last_hi_res_event_found = true;
- } else {
- litest_assert(!last_low_res_event_found);
- if (value == 0)
- last_low_res_event_found = true;
- }
- if (value != 0) {
- if (minimum_movement > 0)
- litest_assert_int_ge(value, min);
- else
- litest_assert_int_le(value, min);
- }
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- }
- litest_assert(last_low_res_event_found);
- litest_assert(last_hi_res_event_found);
- }
- void
- litest_assert_axis_end_sequence(struct libinput *li,
- enum libinput_event_type axis_type,
- enum libinput_pointer_axis axis,
- enum libinput_pointer_axis_source source)
- {
- struct libinput_event_pointer *ptrev;
- bool last_hi_res_event_found, last_low_res_event_found;
- double val;
- int i;
- litest_assert(axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL ||
- axis_type == LIBINPUT_EVENT_POINTER_SCROLL_FINGER ||
- axis_type == LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
- last_hi_res_event_found = false;
- last_low_res_event_found = false;
- /* both high and low scroll end events must be sent */
- for (i = 0; i < 2; i++) {
- _destroy_(libinput_event) *event = libinput_get_event(li);
- ptrev = litest_is_axis_event(event, axis_type, axis, source);
- val = litest_event_pointer_get_value(ptrev, axis);
- litest_assert(val == 0.0);
- if (litest_is_high_res_axis_event(event)) {
- litest_assert(!last_hi_res_event_found);
- last_hi_res_event_found = true;
- } else {
- litest_assert(!last_low_res_event_found);
- last_low_res_event_found = true;
- }
- }
- litest_assert(last_low_res_event_found);
- litest_assert(last_hi_res_event_found);
- }
- void
- _litest_assert_only_typed_events(struct libinput *li,
- enum libinput_event_type type,
- const char *func,
- int line)
- {
- struct libinput_event *event;
- litest_assert(type != LIBINPUT_EVENT_NONE);
- _litest_checkpoint(func,
- line,
- ANSI_CYAN,
- "asserting only typed events %s",
- litest_event_type_str(type));
- libinput_dispatch(li);
- event = libinput_get_event(li);
- litest_assert_notnull(event);
- while (event) {
- litest_assert_event_type(event, type);
- libinput_event_destroy(event);
- libinput_dispatch(li);
- event = libinput_get_event(li);
- }
- }
- void
- litest_assert_only_axis_events(struct libinput *li, enum libinput_event_type axis_type)
- {
- struct libinput_event *event;
- litest_assert(axis_type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL ||
- axis_type == LIBINPUT_EVENT_POINTER_SCROLL_FINGER ||
- axis_type == LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS);
- libinput_dispatch(li);
- event = libinput_get_event(li);
- litest_assert_notnull(event);
- while (event) {
- litest_assert_event_type_is_one_of(event,
- LIBINPUT_EVENT_POINTER_AXIS,
- axis_type);
- libinput_event_destroy(event);
- libinput_dispatch(li);
- event = libinput_get_event(li);
- }
- }
- void
- litest_assert_no_typed_events(struct libinput *li, enum libinput_event_type type)
- {
- struct libinput_event *event;
- litest_assert(type != LIBINPUT_EVENT_NONE);
- libinput_dispatch(li);
- event = libinput_get_event(li);
- while (event) {
- litest_assert_int_ne(libinput_event_get_type(event), type);
- libinput_event_destroy(event);
- libinput_dispatch(li);
- event = libinput_get_event(li);
- }
- }
- void
- litest_assert_touch_sequence(struct libinput *li)
- {
- struct libinput_event *event;
- struct libinput_event_touch *tev;
- int slot;
- event = libinput_get_event(li);
- tev = litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_DOWN);
- slot = libinput_event_touch_get_slot(tev);
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- do {
- tev = litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_MOTION);
- litest_assert_int_eq(slot, libinput_event_touch_get_slot(tev));
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- litest_assert_notnull(event);
- } while (libinput_event_get_type(event) != LIBINPUT_EVENT_TOUCH_UP);
- tev = litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_UP);
- litest_assert_int_eq(slot, libinput_event_touch_get_slot(tev));
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
- libinput_event_destroy(event);
- }
- void
- litest_assert_touch_motion_frame(struct libinput *li)
- {
- struct libinput_event *event;
- /* expect at least one, but maybe more */
- event = libinput_get_event(li);
- litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_MOTION);
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- while (event) {
- litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_MOTION);
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
- libinput_event_destroy(event);
- event = libinput_get_event(li);
- }
- }
- void
- litest_assert_touch_down_frame(struct libinput *li)
- {
- _destroy_(libinput_event) *down = libinput_get_event(li);
- litest_is_touch_event(down, LIBINPUT_EVENT_TOUCH_DOWN);
- _destroy_(libinput_event) *frame = libinput_get_event(li);
- litest_is_touch_event(frame, LIBINPUT_EVENT_TOUCH_FRAME);
- }
- void
- litest_assert_touch_up_frame(struct libinput *li)
- {
- _destroy_(libinput_event) *up = libinput_get_event(li);
- litest_is_touch_event(up, LIBINPUT_EVENT_TOUCH_UP);
- _destroy_(libinput_event) *frame = libinput_get_event(li);
- litest_is_touch_event(frame, LIBINPUT_EVENT_TOUCH_FRAME);
- }
- void
- litest_assert_touch_cancel(struct libinput *li)
- {
- _destroy_(libinput_event) *cancel = libinput_get_event(li);
- litest_is_touch_event(cancel, LIBINPUT_EVENT_TOUCH_CANCEL);
- _destroy_(libinput_event) *frame = libinput_get_event(li);
- litest_is_touch_event(frame, LIBINPUT_EVENT_TOUCH_FRAME);
- }
- void
- _litest_timeout(struct libinput *li, const char *func, int lineno, int millis)
- {
- if (li)
- _litest_dispatch(li, func, lineno);
- msleep(millis);
- if (li)
- _litest_dispatch(li, func, lineno);
- }
- void
- _litest_assert_logcapture_no_errors(struct litest_logcapture *capture,
- const char *file,
- const char *func,
- int line)
- {
- litest_assert_ptr_notnull(capture);
- if (capture->errors &&
- strv_for_each((const char **)capture->errors, is_actual_error, NULL)) {
- _autofree_ char *errors = strv_join(capture->errors, "\n");
- _litest_abort_msg(file,
- line,
- func,
- "Unexpected errors in log capture:\n%s\n",
- errors);
- }
- }
- void
- litest_logcapture_destroy(struct litest_logcapture *c)
- {
- strv_free(c->errors);
- strv_free(c->infos);
- strv_free(c->debugs);
- strv_free(c->bugs);
- free(c);
- }
- LIBINPUT_ATTRIBUTE_PRINTF(3, 0)
- static void
- litest_log_handler_msgcapture(struct libinput *libinput,
- enum libinput_log_priority pri,
- const char *format,
- va_list args)
- {
- struct litest_user_data *user_data = libinput_get_user_data(libinput);
- struct litest_logcapture *capture = user_data->private;
- const char *priority = NULL;
- const char *color =
- use_colors ? ANSI_RGB(255, 255, 70) ANSI_RGB_BG(40, 40, 40) : "";
- switch (pri) {
- case LIBINPUT_LOG_PRIORITY_ERROR:
- priority = "error ";
- break;
- case LIBINPUT_LOG_PRIORITY_INFO:
- priority = "info ";
- break;
- case LIBINPUT_LOG_PRIORITY_DEBUG:
- priority = "debug ";
- break;
- }
- _autofree_ char *message = strdup_vprintf(format, args);
- fprintf(stderr,
- "%slitest captured: %-6s%s %s",
- color,
- priority,
- use_colors ? ANSI_NORMAL : "",
- message);
- if (strstr(message, "kernel bug: ") || strstr(message, "client bug: ") ||
- strstr(message, "libinput bug: ") || strstr(message, "plugin bug: ")) {
- capture->bugs = strv_append_strdup(capture->bugs, message);
- }
- switch (pri) {
- case LIBINPUT_LOG_PRIORITY_ERROR:
- capture->errors = strv_append_take(capture->errors, &message);
- break;
- case LIBINPUT_LOG_PRIORITY_INFO:
- capture->infos = strv_append_take(capture->infos, &message);
- break;
- case LIBINPUT_LOG_PRIORITY_DEBUG:
- capture->debugs = strv_append_take(capture->debugs, &message);
- break;
- }
- }
- struct litest_logcapture *
- litest_logcapture_setup(struct libinput *li)
- {
- struct litest_logcapture *c = zalloc(sizeof(*c));
- litest_context_set_user_data(li, c);
- libinput_log_set_handler(li, litest_log_handler_msgcapture);
- return c;
- }
- struct litest_logcapture *
- litest_logcapture_remove(struct libinput *li, struct litest_logcapture *capture)
- {
- litest_restore_log_handler(li);
- litest_logcapture_destroy(capture);
- return NULL;
- }
- #define litest_with_logcapture(li_, capture_) \
- for (struct litest_logcapture *capture_ = litest_logcapture_setup(li_); \
- capture_ != NULL; capture_ = litest_logcapture_remove(li_, capture_))
- void
- _litest_assert_strv_substring(char **strv,
- char *substring,
- const char *file,
- const char *func,
- int line)
- {
- if (!strv) {
- _litest_abort_msg(file,
- line,
- func,
- "Expected substring '%s' but strv is NULL",
- substring);
- }
- bool found = strv_find_substring(strv, substring, NULL);
- if (!found) {
- _autofree_ char *strv_str = strv_join(strv, "', '");
- _litest_abort_msg(file,
- line,
- func,
- "Expected substring '%s' not found in strv: ['%s']",
- substring,
- strv_str);
- }
- }
- void
- _litest_assert_strv_no_substring(char **strv,
- char *substring,
- const char *file,
- const char *func,
- int line)
- {
- if (!strv)
- return;
- size_t index;
- bool found = strv_find_substring(strv, substring, &index);
- if (found) {
- _autofree_ char *strv_str = strv_join(strv, "', '");
- _litest_abort_msg(
- file,
- line,
- func,
- "Unexpected substring '%s' present at index %zd in strv: ['%s']",
- substring,
- index,
- strv_str);
- }
- }
- void
- litest_push_event_frame(struct litest_device *dev)
- {
- litest_assert_int_ge(dev->skip_ev_syn, 0);
- dev->skip_ev_syn++;
- }
- void
- litest_pop_event_frame(struct litest_device *dev)
- {
- litest_assert_int_gt(dev->skip_ev_syn, 0);
- dev->skip_ev_syn--;
- if (dev->skip_ev_syn == 0)
- litest_event(dev, EV_SYN, SYN_REPORT, 0);
- }
- void
- litest_filter_event(struct litest_device *dev, unsigned int type, unsigned int code)
- {
- libevdev_disable_event_code(dev->evdev, type, code);
- }
- void
- litest_unfilter_event(struct litest_device *dev, unsigned int type, unsigned int code)
- {
- /* would need an non-NULL argument for re-enabling, so simply abort
- * until we need to be more sophisticated */
- litest_assert_int_ne(type, (unsigned int)EV_ABS);
- libevdev_enable_event_code(dev->evdev, type, code, NULL);
- }
- static void
- send_abs_xy(struct litest_device *d, double x, double y)
- {
- struct input_event e;
- int val;
- e.type = EV_ABS;
- e.code = ABS_X;
- e.value = LITEST_AUTO_ASSIGN;
- val = litest_auto_assign_value(d, &e, 0, x, y, NULL, true);
- litest_event(d, EV_ABS, ABS_X, val);
- e.code = ABS_Y;
- val = litest_auto_assign_value(d, &e, 0, x, y, NULL, true);
- litest_event(d, EV_ABS, ABS_Y, val);
- }
- static void
- send_abs_mt_xy(struct litest_device *d, double x, double y)
- {
- struct input_event e;
- int val;
- e.type = EV_ABS;
- e.code = ABS_MT_POSITION_X;
- e.value = LITEST_AUTO_ASSIGN;
- val = litest_auto_assign_value(d, &e, 0, x, y, NULL, true);
- litest_event(d, EV_ABS, ABS_MT_POSITION_X, val);
- e.code = ABS_MT_POSITION_Y;
- e.value = LITEST_AUTO_ASSIGN;
- val = litest_auto_assign_value(d, &e, 0, x, y, NULL, true);
- litest_event(d, EV_ABS, ABS_MT_POSITION_Y, val);
- }
- void
- litest_semi_mt_touch_down(struct litest_device *d,
- struct litest_semi_mt *semi_mt,
- unsigned int slot,
- double x,
- double y)
- {
- double t, l, r = 0, b = 0; /* top, left, right, bottom */
- if (d->ntouches_down > 2 || slot > 1)
- return;
- if (d->ntouches_down == 1) {
- l = x;
- t = y;
- } else {
- int other = (slot + 1) % 2;
- l = min(x, semi_mt->touches[other].x);
- t = min(y, semi_mt->touches[other].y);
- r = max(x, semi_mt->touches[other].x);
- b = max(y, semi_mt->touches[other].y);
- }
- send_abs_xy(d, l, t);
- litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
- if (d->ntouches_down == 1)
- litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++semi_mt->tracking_id);
- send_abs_mt_xy(d, l, t);
- if (d->ntouches_down == 2) {
- litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
- litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++semi_mt->tracking_id);
- send_abs_mt_xy(d, r, b);
- }
- litest_event(d, EV_SYN, SYN_REPORT, 0);
- semi_mt->touches[slot].x = x;
- semi_mt->touches[slot].y = y;
- }
- void
- litest_semi_mt_touch_move(struct litest_device *d,
- struct litest_semi_mt *semi_mt,
- unsigned int slot,
- double x,
- double y)
- {
- double t, l, r = 0, b = 0; /* top, left, right, bottom */
- if (d->ntouches_down > 2 || slot > 1)
- return;
- if (d->ntouches_down == 1) {
- l = x;
- t = y;
- } else {
- int other = (slot + 1) % 2;
- l = min(x, semi_mt->touches[other].x);
- t = min(y, semi_mt->touches[other].y);
- r = max(x, semi_mt->touches[other].x);
- b = max(y, semi_mt->touches[other].y);
- }
- send_abs_xy(d, l, t);
- litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
- send_abs_mt_xy(d, l, t);
- if (d->ntouches_down == 2) {
- litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
- send_abs_mt_xy(d, r, b);
- }
- litest_event(d, EV_SYN, SYN_REPORT, 0);
- semi_mt->touches[slot].x = x;
- semi_mt->touches[slot].y = y;
- }
- void
- litest_semi_mt_touch_up(struct litest_device *d,
- struct litest_semi_mt *semi_mt,
- unsigned int slot)
- {
- /* note: ntouches_down is decreased before we get here */
- if (d->ntouches_down >= 2 || slot > 1)
- return;
- litest_event(d, EV_ABS, ABS_MT_SLOT, d->ntouches_down);
- litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, -1);
- /* if we have one finger left, send x/y coords for that finger left.
- this is likely to happen with a real touchpad */
- if (d->ntouches_down == 1) {
- int other = (slot + 1) % 2;
- send_abs_xy(d, semi_mt->touches[other].x, semi_mt->touches[other].y);
- litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
- send_abs_mt_xy(d, semi_mt->touches[other].x, semi_mt->touches[other].y);
- }
- litest_event(d, EV_SYN, SYN_REPORT, 0);
- }
- enum litest_mode
- litest_parse_argv(int argc, char **argv, int *njobs_out)
- {
- enum {
- OPT_EXIT_FIRST,
- OPT_FILTER_TEST,
- OPT_FILTER_DEVICE,
- OPT_FILTER_GROUP,
- OPT_FILTER_RANGEVAL,
- OPT_FILTER_DEVICELESS,
- OPT_FILTER_PARAMETER,
- OPT_OUTPUT_FILE,
- OPT_JOBS,
- OPT_LIST,
- OPT_VERBOSE,
- };
- static const struct option opts[] = {
- { "filter-test", 1, 0, OPT_FILTER_TEST },
- { "filter-device", 1, 0, OPT_FILTER_DEVICE },
- { "filter-group", 1, 0, OPT_FILTER_GROUP },
- { "filter-rangeval", 1, 0, OPT_FILTER_RANGEVAL },
- { "filter-deviceless", 0, 0, OPT_FILTER_DEVICELESS },
- { "filter-parameter", 1, 0, OPT_FILTER_PARAMETER },
- { "output-file", 1, 0, OPT_OUTPUT_FILE },
- { "exitfirst", 0, 0, OPT_EXIT_FIRST },
- { "jobs", 1, 0, OPT_JOBS },
- { "list", 0, 0, OPT_LIST },
- { "verbose", 0, 0, OPT_VERBOSE },
- { "help", 0, 0, 'h' },
- { 0, 0, 0, 0 }
- };
- enum {
- JOBS_DEFAULT,
- JOBS_NONE,
- JOBS_SINGLE,
- JOBS_CUSTOM
- } want_jobs = JOBS_DEFAULT;
- char *jobs_env;
- int jobs = 0;
- /* If we are not running from the builddir, we assume we're running
- * against the system as installed */
- if (!builddir_lookup(NULL))
- use_system_rules_quirks = true;
- if (in_debugger)
- want_jobs = JOBS_NONE;
- if ((jobs_env = getenv("LITEST_JOBS"))) {
- if (!safe_atoi(jobs_env, &jobs)) {
- fprintf(stderr,
- "LITEST_JOBS environment variable must be positive integer\n");
- exit(EXIT_FAILURE);
- }
- }
- while (1) {
- int c;
- int option_index = 0;
- c = getopt_long(argc, argv, "j:x", opts, &option_index);
- if (c == -1)
- break;
- switch (c) {
- default:
- case 'h':
- printf("Usage: %s [--verbose] [--jobs] [--filter-...]\n"
- "\n"
- "Options:\n"
- " -x | --exitfirst\n"
- " Exit instantly on first failed test\n"
- " --filter-test=.... \n"
- " Glob to filter on test names\n"
- " --filter-device=.... \n"
- " Glob to filter on device names\n"
- " --filter-group=.... \n"
- " Glob to filter on test groups\n"
- " --filter-rangeval=N \n"
- " Only run tests with the given range value\n"
- " --filter-deviceless \n"
- " Only run tests that do not create test devices\n"
- " --filter-parameter=param1:glob,param2:glob,... \n"
- " Glob(s) to filter on the given parameters in their string "
- "representation.\n"
- " Boolean parameters are filtered via 'true' and 'false'.\n"
- " --verbose\n"
- " Enable verbose output\n"
- " --jobs 8\n"
- " Number of parallel test suites to run (default: 8).\n"
- " This overrides the LITEST_JOBS environment variable.\n"
- " --list\n"
- " List all tests\n"
- "\n"
- "See the libinput-test-suite(1) man page for details.\n",
- program_invocation_short_name);
- exit(c != 'h');
- break;
- case OPT_FILTER_TEST:
- filter_test = optarg;
- if (want_jobs == JOBS_DEFAULT)
- want_jobs = JOBS_SINGLE;
- break;
- case OPT_FILTER_DEVICE:
- filter_device = optarg;
- if (want_jobs == JOBS_DEFAULT)
- want_jobs = JOBS_SINGLE;
- break;
- case OPT_FILTER_DEVICELESS:
- run_deviceless = true;
- break;
- case OPT_FILTER_GROUP:
- filter_group = optarg;
- break;
- case OPT_FILTER_RANGEVAL:
- filter_rangeval = atoi(optarg);
- break;
- case OPT_FILTER_PARAMETER: {
- size_t nelems;
- _autostrvfree_ char **params =
- strv_from_string(optarg, ",", &nelems);
- const size_t max_filters = ARRAY_LENGTH(filter_params) - 1;
- if (nelems >= max_filters) {
- fprintf(stderr,
- "Only %zd parameter filters are supported\n",
- max_filters);
- exit(1);
- }
- for (size_t i = 0; i < nelems; i++) {
- size_t n;
- _autostrvfree_ char **strv =
- strv_from_string(params[i], ":", &n);
- assert(n == 2);
- const char *name = strv[0];
- const char *glob = strv[1];
- struct param_filter *f = &filter_params[i];
- snprintf(f->name, sizeof(f->name), "%s", name);
- snprintf(f->glob, sizeof(f->glob), "%s", glob);
- }
- break;
- }
- case 'j':
- case OPT_JOBS:
- jobs = atoi(optarg);
- want_jobs = JOBS_CUSTOM;
- break;
- case OPT_LIST:
- return LITEST_MODE_LIST;
- case OPT_VERBOSE:
- verbose = true;
- break;
- case OPT_OUTPUT_FILE:
- outfile = fopen(optarg, "w+");
- if (!outfile) {
- fprintf(stderr, "Failed to open %s: %m\n", optarg);
- exit(1);
- }
- break;
- case 'x':
- case OPT_EXIT_FIRST:
- exit_first = true;
- break;
- }
- }
- switch (want_jobs) {
- case JOBS_SINGLE:
- jobs = 1;
- break;
- case JOBS_NONE:
- jobs = 0;
- break;
- default:
- break;
- }
- *njobs_out = jobs;
- return LITEST_MODE_TEST;
- }
|