PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB` sh-3ll

HOME


sh-3ll 1.0
DIR:/home/.cpan/build/Test2-Suite-0.000148-0/t/modules/Tools/
Upload File :
Current File : /home/.cpan/build/Test2-Suite-0.000148-0/t/modules/Tools/Compare.t
use Test2::Bundle::Extended -target => 'Test2::Tools::Compare';
use Test2::Util::Table();

BEGIN {
    $ENV{TABLE_TERM_SIZE} = 80;
    $ENV{T2_AUTO_DUMP}    = 0;
    $ENV{T2_AUTO_DEPARSE} = 0;
}

{
    package My::Boolean;
    use overload bool => sub { ${$_[0]} };
}

{
    package My::String;
    use overload '""' => sub { "xxx" };
}

sub fail_table {
    my %args = @_;

    my $string = join "\n" => Test2::Util::Table::table(%args, sanitize => 1, mark_tail => 1);

    event Fail => sub {
        call facet_data => hash {
            field assert => hash { field pass => 0; etc };
            field info => array {
                item hash {
                    field details => match(qr/^\Q$string\E/);
                    field table   => hash {
                        field header => bag { item $_ for @{$args{header}}; etc };
                        field rows   => bag {
                            item bag { item $_ for @{$_}; etc } for @{$args{rows}};
                            etc;
                        };
                        etc;
                    };
                    etc;
                };
                etc;
            };
            etc;
        };
    };
}

subtest simple => sub {
    imported_ok qw{
        match mismatch validator
        hash array bag object meta number float rounded within string bool
        in_set not_in_set check_set
        item field call call_list call_hash prop check all_items all_keys all_vals all_values
        etc end filter_items
        T F D DF E DNE FDNE U L
        event
        exact_ref
    };
};

subtest is => sub {
    my $events = intercept {
        def ok => (is(1, 1), '2 arg pass');

        def ok => (is('a', 'a', "simple pass", 'diag'), 'simple pass');
        def ok => (!is('a', 'b', "simple fail", 'diag'), 'simple fail');

        def ok => (is([{'a' => 1}], [{'a' => 1}], "complex pass", 'diag'), 'complex pass');
        def ok => (!is([{'a' => 2, 'b' => 3}], [{'a' => 1}], "complex fail", 'diag'), 'complex fail');

        def ok => (is(undef, undef), 'undef pass');
        def ok => (!is(0, undef), 'undef fail');

        my $true  = do { bless \(my $dummy = 1), "My::Boolean" };
        my $false = do { bless \(my $dummy = 0), "My::Boolean" };
        def ok => (is($true,  $true,  "true scalar ref is itself"),  "true scalar ref is itself");
        def ok => (is($false, $false, "false scalar ref is itself"), "false scalar ref is itself");

        def ok => (is(v1.2.3, v1.2.3, 'vstring pass'), 'vstring pass');
        def ok => (is(\v1.2.3, \v1.2.3, 'vstring refs pass'), 'vstring refs pass');
        def ok => (!is(v1.2.3, v1.2.4, 'vstring fail'), 'vstring fail');
        def ok => (!is(\v1.2.3, \v1.2.4, 'vstring refs fail'), 'vstring refs fail');

        my $x = \\"123";
        def ok => (is($x, \\"123", "Ref-Ref check 1"), "Ref-Ref check 1");

        $x = \[123];
        def ok => (is($x, \["123"], "Ref-Ref check 2"), "Ref-Ref check 2");

        def ok => (!is(\$x, \\["124"], "Ref-Ref check 3"), "Ref-Ref check 3");
    };

    do_def;

    like(
        $events,
        array {
            event Ok => sub {
                call pass => T();
                call name => undef;
            };

            event Ok => sub {
                call pass => T();
                call name => 'simple pass';
            };

            fail_table(
                header => [qw/GOT OP CHECK/],
                rows   => [[qw/a eq b/]],
            );

            event Ok => sub {
                call pass => T();
                call name => 'complex pass';
            };

            fail_table(
                header => [qw/PATH GOT OP CHECK/],
                rows   => [
                    [qw/[0]{a} 2 eq 1/],
                    [qw/[0]{b} 3 !exists/, '<DOES NOT EXIST>'],
                ],
            );

            event Ok => sub {
                call pass => T();
            };

            fail_table(
                header => [qw/GOT OP CHECK/],
                rows   => [[qw/0 IS <UNDEF>/]],
            );

            event Ok => sub {
                call pass => T();
                call name => "true scalar ref is itself";
            };

            event Ok => sub {
                call pass => T();
                call name => "false scalar ref is itself";
            };

            event Ok => sub {
                call pass => T();
                call name => 'vstring pass';
            };

            event Ok => sub {
                call pass => T();
                call name => 'vstring refs pass';
            };

            fail_table(
                header => [qw/GOT OP CHECK/],
                rows   => [["\N{U+1}\N{U+2}\N{U+3}", 'eq', "\N{U+1}\N{U+2}\N{U+4}"]],
            );

            fail_table(
                header => [qw/PATH GOT OP CHECK/],
                rows   => [['$*', "\N{U+1}\N{U+2}\N{U+3}", 'eq', "\N{U+1}\N{U+2}\N{U+4}"]],
            );

            event Ok => sub {
                call pass => T();
                call name => "Ref-Ref check 1";
            };

            event Ok => sub {
                call pass => T();
                call name => "Ref-Ref check 2";
            };

            event Fail => sub {
                call name => 'Ref-Ref check 3';
            };

            end;
        },
        "Got expected events"
    );

    $events = intercept { is({foo => {bar => 'a'}, a => 1}, {foo => {baz => 'a'}, a => 2}, "Typo") };
    chomp(my $want = <<"    EOT");
+------------+------------------+---------+------------------+
| PATH       | GOT              | OP      | CHECK            |
+------------+------------------+---------+------------------+
| {a}        | 1                | eq      | 2                |
| {foo}{baz} | <DOES NOT EXIST> |         | a                |
| {foo}{bar} | a                | !exists | <DOES NOT EXIST> |
+------------+------------------+---------+------------------+
==== Summary of missing/extra items ====
{foo}{baz}:   DOES NOT EXIST
{foo}{bar}: SHOULD NOT EXIST
== end summary of missing/extra items ==
    EOT

    like(
        $events->[0]->facet_data->{info}->[0]->{details},
        $want,
        "Got summary of missing/extra"
    );
};

subtest like => sub {
    my $events = intercept {
        def ok => (like(1, 1), '2 arg pass');

        def ok => (like('a', qr/a/, "simple pass", 'diag'), 'simple pass');
        def ok => (!like('b', qr/a/, "simple fail", 'diag'), 'simple fail');

        def ok => (like([{'a' => 1, 'b' => 2}, 'a'], [{'a' => 1}], "complex pass", 'diag'), 'complex pass');
        def ok => (!like([{'a' => 2, 'b' => 2}, 'a'], [{'a' => 1}], "complex fail", 'diag'), 'complex fail');

        my $str = bless {}, 'My::String';
        def ok => (like($str, qr/xxx/, 'overload pass'), "overload pass");
        def ok => (!like($str, qr/yyy/, 'overload fail'), "overload fail");

    };

    do_def;

    my $rx = "" . qr/a/;

    like(
        $events,
        array {
            event Ok => sub {
                call pass => T();
                call name => undef;
            };

            event Ok => sub {
                call pass => T();
                call name => 'simple pass';
            };

            fail_table(
                header => [qw/GOT OP CHECK/],
                rows   => [[qw/b =~/, "$rx"]],
            );

            event Ok => sub {
                call pass => T();
                call name => 'complex pass';
            };

            fail_table(
                header => [qw/PATH GOT OP CHECK/],
                rows   => [[qw/[0]{a} 2 eq 1/]],
            );

            event Ok => sub {
                call pass => T();
                call name => 'overload pass';
            };

            $rx = qr/yyy/;
            fail_table(
                header => [qw/GOT OP CHECK/],
                rows   => [[qw/xxx =~/, "$rx"]],
            );

            end;
        },
        "Got expected events"
    );
};

subtest shortcuts => sub {
    is(1,            T(), "true");
    is('a',          T(), "true");
    is(' ',          T(), "true");
    is('0 but true', T(), "true");

    my @lines;
    my $events = intercept {
        is(0, T(), "not true");     push @lines => __LINE__;
        is('', T(), "not true");    push @lines => __LINE__;
        is(undef, T(), "not true"); push @lines => __LINE__;
    };
    like(
        $events,
        array {
            filter_items { grep { !$_->isa('Test2::Event::Diag') } @_ };
            event Fail => sub { prop line => $lines[0]; prop file => __FILE__; };
            event Fail => sub { prop line => $lines[1]; prop file => __FILE__; };
            event Fail => sub { prop line => $lines[2]; prop file => __FILE__; };
            end()
        },
        "T() fails for untrue",
    );

    is(0,     F(), "false");
    is('',    F(), "false");
    is(undef, F(), "false");

    $events = intercept {
        is(1,   F(), "not false");
        is('a', F(), "not false");
        is(' ', F(), "not false");
    };
    like(
        $events,
        array {
            filter_items { grep { !$_->isa('Test2::Event::Diag') } @_ };
            event Fail => {};
            event Fail => {};
            event Fail => {};
            end()
        },
        "F() fails for true",
    );

    is(undef, U(), "not defined");

    like(
        intercept { is(0, U(), "not defined") },
        array { event Fail => {} },
        "0 is defined"
    );

    is(0,            D(), "defined");
    is(1,            D(), "defined");
    is('',           D(), "defined");
    is(' ',          D(), "defined");
    is('0 but true', D(), "defined");

    like(
        intercept { is(undef, D(), "not defined") },
        array { event Fail => { } },
        "undef is not defined"
    );

    is(0,            DF(), "defined but false");
    is('',           DF(), "defined but false");

    like(
        intercept {
          is(undef,        DF());
          is(1,            DF());
          is(' ',          DF());
          is('0 but true', DF());
        },
        array {
          filter_items { grep { !$_->isa('Test2::Event::Diag') } @_ };
          event Fail => {};
          event Fail => {};
          event Fail => {};
          event Fail => {};
        },
        "got fail for DF"
    );

    is([undef], [E()],   "does exist");
    is([],      [DNE()], "does not exist");
    is({}, {a => DNE()}, "does not exist");
    $events = intercept {
        is([], [E()]);
        is([undef], [DNE()]);
        is({a => undef}, {a => DNE()});
    };
    like(
        $events,
        array {
            filter_items { grep { !$_->isa('Test2::Event::Diag') } @_ };
            event Fail => {};
            event Fail => {};
            event Fail => {};
        },
        "got failed event"
    );

    is([], [FDNE()], "does not exist");
    is({}, {a => FDNE()}, "does not exist");
    is([undef], [FDNE()], "false");
    is({a => undef}, {a => FDNE()}, "false");

    $events = intercept {
        is([1], [FDNE()]);
        is({a => 1}, {a => FDNE()});
    };
    like(
        $events,
        array {
            filter_items { grep { !$_->isa('Test2::Event::Diag') } @_ };
            event Fail => {};
            event Fail => {};
        },
        "got failed event"
    );

    is('foo', L(), "defined and has length");
    is(0,     L(), "defined and has length");
    is([],    L(), "defined and has length");

    like(
        intercept {
          is(undef, L());
          is('',    L());
        },
        array {
          filter_items { grep { !$_->isa('Test2::Event::Diag') } @_ };
          event Fail => {};
          event Fail => {};
        },
        "got fail for L"
    );
};

subtest exact_ref => sub {
    my $ref = {};

    my $check = exact_ref($ref); my $line  = __LINE__;
    is($check->lines, [$line], "correct line");

    my $hash = {};
    my $events = intercept {
        is($ref,  $check, "pass");
        is($hash, $check, "fail");
    };

    like(
        $events,
        array {
            event Ok => {pass => 1};

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [["$hash", '==', "$ref", $line]],
            );

            end;
        },
        "Got events"
    );
};

subtest string => sub {
    my $check = string "foo"; my $line = __LINE__;
    is($check->lines, [$line], "Got line number");

    my $events = intercept {
        is('foo', $check, "pass");
        is('bar', $check, "fail");
    };

    like(
        $events,
        array {
            event Ok => {pass => 1};

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[qw/bar eq foo/, $line]],
            );
            end;
        },
        "Got events"
    );

    my ($check1, $check2) = (string("foo", negate => 1), !string("foo"));
    $line = __LINE__ - 1;

    for $check ($check1, $check2) {
        is($check->lines, [$line], "Got line number");

        $events = intercept {
            is('bar', $check, "pass");
            is('foo', $check, "fail");
        };

        like(
            $events,
            array {
                event Ok => {pass => 1};

                fail_table(
                    header => [qw/GOT OP CHECK LNs/],
                    rows   => [[qw/foo ne foo/, $line]],
                );
                end;
            },
            "Got events"
        );
    }
};

subtest number => sub {
    my $check = number "22.0"; my $line = __LINE__;
    is($check->lines, [$line], "Got line number");

    my $events = intercept {
        is(22, $check, "pass");
        is("22.0", $check, "pass");
        is(12, $check, "fail");
        is('xxx', $check, "fail");
    };

    like(
        $events,
        array {
            event Ok => {pass => 1};
            event Ok => {pass => 1};

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[qw/12 == 22.0/, $line]],
            );

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[qw/xxx == 22.0/, $line]],
            );
            end;
        },
        "Got events"
    );

    my ($check1, $check2) = (number("22.0", negate => 1), !number("22.0"));
    $line = __LINE__ - 1;

    for $check ($check1, $check2) {
        is($check->lines, [$line], "Got line number");

        $events = intercept {
            is(12, $check, "pass");
            is(22, $check, "fail");
            is("22.0", $check, "fail");
            is('xxx', $check, "fail");
        };

        like(
            $events,
            array {
                event Ok => {pass => 1};

                fail_table(
                    header => [qw/GOT OP CHECK LNs/],
                    rows   => [[qw/22 != 22.0/, $line]],
                );

                fail_table(
                    header => [qw/GOT OP CHECK LNs/],
                    rows   => [[qw/22.0 != 22.0/, $line]],
                );

                fail_table(
                    header => [qw/GOT OP CHECK LNs/],
                    rows   => [[qw/xxx != 22.0/, $line]],
                );

                end;
            },
            "Got events"
        );
    }
};

subtest float => sub {
    subtest float_number => sub {
        # float should pass all of the number subtests
        my $check = float("22.0"); my $line = __LINE__;
        is($check->lines, [$line], "Got line number");

        my $events = intercept {
            is(22, $check, "pass");
            is("22.0", $check, "pass");
            is(12, $check, "fail");
            is('xxx', $check, "fail");
        };

        like(
            $events,
            array {
                event Ok => {pass => 1};
                event Ok => {pass => 1};

                fail_table(
                    header => [qw/GOT OP CHECK LNs/],
                    rows   => [['12', '==', $check->name, $line]],
                );

                fail_table(
                    header => [qw/GOT OP CHECK LNs/],
                    rows   => [['xxx', '==', $check->name, $line]],
                );

                end;
            },
            "Got events"
        );

        my ($check1, $check2) = (float("22.0", negate => 1), !float("22.0"));
        $line = __LINE__ - 1;

        for $check ($check1, $check2) {
            is($check->lines, [$line], "Got line number");

            $events = intercept {
                is(12, $check, "pass");
                is(22, $check, "fail");
                is("22.0", $check, "fail");
                is('xxx', $check, "fail");
            };

            like(
                $events,
                array {
                    event Ok => {pass => 1};

                    fail_table(
                        header => [qw/GOT OP CHECK LNs/],
                        rows   => [['22', '!=', $check->name, $line]],
                    );

                    fail_table(
                        header => [qw/GOT OP CHECK LNs/],
                        rows   => [['22.0', '!=', $check->name, $line]],
                    );

                    fail_table(
                        header => [qw/GOT OP CHECK LNs/],
                        rows   => [['xxx', '!=', $check->name, $line]],
                    );

                    end;
                },
                "Got float events"
            );
        }
    };
    subtest float_rounding => sub {
        my $check = float("22.0");
        my $check_3 = float("22.0", tolerance => .001);

        is($check->tolerance,   1e-08, "default tolerance");
        is($check_3->tolerance, 0.001, "custom tolerance");

        my $check_p3 = float("22.0", precision => 3);
        is($check_p3->precision,        3, "custom precision");
        is($check_p3->name,      "22.000", "custom precision name");
    };
    subtest rounded_and_within => sub {
        my $check   = within("22.0");
        my $check_3 = within("22.0", .001);

        is($check->tolerance,   1e-08, "default tolerance");
        is($check_3->tolerance, 0.001, "custom tolerance");

        my $check_p3 = rounded("22.0", 3);
        is($check_p3->precision,        3, "custom precision");
        is($check_p3->name,      "22.000", "custom precision name");
    };
};


subtest bool => sub {
    my @true = (1, 'yup', '0 but true', ' ', {});
    my @false = (0, '0', '', undef);

    for my $true (@true) {
        for my $true2 (@true) {
            is($true2, bool($true), "Both true");

            my $line = __LINE__ + 2;
            is(
                intercept { is($true2, !bool($true)) },
                array {
                    fail_table(
                        header => [qw/GOT OP CHECK LNs/],
                        rows   => [["<TRUE ($true2)>", '!=', "<TRUE ($true)>", $line]],
                    );
                    end;
                },
                "true($true2) + true($true) + negate"
            );
        }

        for my $false (@false) {
            is($false, !bool($true), "true + false + !");
            is($false, bool($true, negate => 1), "true + false + negate");

            my $render = '<FALSE (' . (defined($false) ? length($false) ? $false : "''" : 'undef') . ')>';

            my $line = __LINE__ + 2;
            is(
                intercept { is($false, bool($true)) },
                array {
                    fail_table(
                        header => [qw/GOT OP CHECK LNs/],
                        rows   => [[$render, '==', "<TRUE ($true)>", $line]],
                    );
                    end;
                },
                "$render + TRUE ($true) + negate"
            );
        }
    }

    for my $false (@false) {
        my $render1 = '<FALSE (' . (defined($false) ? length($false) ? $false : "''" : 'undef') . ')>';
        for my $false2 (@false) {
            is($false2, bool($false), "false + false");

            my $render2 = '<FALSE (' . (defined($false2) ? length($false2) ? $false2 : "''" : 'undef') . ')>';

            my $line = __LINE__ + 2;
            is(
                intercept { is($false2, !bool($false)) },
                array {
                    fail_table(
                        header => [qw/GOT OP CHECK LNs/],
                        rows   => [[$render2, '!=', $render1, $line]],
                    );
                    end;
                },
                "$render2 + $render1 + negate"
            );
        }

        for my $true (@true) {
            is($true, !bool($false), "true + false + !");
            is($true, bool($false, negate => 1), "true + false + negate");

            my $line = __LINE__ + 2;
            is(
                intercept { is($true, bool($false)) },
                array {
                    fail_table(
                        header => [qw/GOT OP CHECK LNs/],
                        rows   => [["<TRUE ($true)>", '==', $render1, $line]],
                    );
                    end;
                },
                "TRUE ($true) + $render1 + negate"
            );
        }
    }

    my $arr  = [];
    my $line = __LINE__ + 2;
    is(
        intercept { is($arr, [bool(0)]) },
        array {
            fail_table(
                header => [qw/PATH GOT OP CHECK LNs/],
                rows   => [['[0]', "<DOES NOT EXIST>", '==', '<FALSE (0)>', $line],],
            );
            end;
        },
        "Value must exist"
    );
};

{
    package Foo;

    package Foo::Bar;
    our @ISA = 'Foo';

    package Baz;
}

subtest check_isa => sub {
    my $check = check_isa "Foo"; my $line = __LINE__;
    is($check->lines, [$line], "Got line number");

    my $foo_bar = bless {}, 'Foo::Bar';
    my $baz     = bless {}, 'Baz';

    my $events = intercept {
        is($foo_bar, $check, "pass");
        is($baz,     $check, "fail");
    };

    like(
        $events,
        array {
            event Ok => {pass => 1};

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [["$baz", qw/isa Foo/, $line]],
            );
            end;
        },
        "Got events"
    );

    my ($check1, $check2) = (check_isa("Foo", negate => 1), !check_isa("Foo"));
    $line = __LINE__ - 1;

    for $check ($check1, $check2) {
        is($check->lines, [$line], "Got line number");

        $events = intercept {
            is($baz,     $check, "pass");
            is($foo_bar, $check, "fail");
        };

        like(
            $events,
            array {
                event Ok => {pass => 1};

                fail_table(
                    header => [qw/GOT OP CHECK LNs/],
                    rows   => [["$foo_bar", qw/!isa Foo/, $line]],
                );
                end;
            },
            "Got events"
        );
    }
};


subtest match => sub {
    my $check = match qr/xyz/; my $line = __LINE__;
    is($check->lines, [$line], "Got line number");

    my $events = intercept {
        is('axyzb', $check, "pass");
        is('abcde', $check, "fail");
    };

    my $rx = "" . qr/xyz/;
    like(
        $events,
        array {
            event Ok => {pass => 1};

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[qw/abcde =~/, "$rx", $line]],
            );

            end;
        },
        "Got events"
    );
};

subtest '!match' => sub {
    my $check = !match qr/xyz/; my $line = __LINE__;
    is($check->lines, [$line], "Got line number");

    my $events = intercept {
        is('abcde', $check, "pass");
        is('axyzb', $check, "fail");
    };

    my $rx = "" . qr/xyz/;
    like(
        $events,
        array {
            event Ok => {pass => 1};

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[qw/axyzb !~/, "$rx", $line]],
            );

            end;
        },
        "Got events"
    );
};

subtest '!mismatch' => sub {
    my $check = !mismatch qr/xyz/; my $line = __LINE__;
    is($check->lines, [$line], "Got line number");

    my $events = intercept {
        is('axyzb', $check, "pass");
        is('abcde', $check, "fail");
    };

    my $rx = "" . qr/xyz/;
    like(
        $events,
        array {
            event Ok => {pass => 1};

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[qw/abcde =~/, "$rx", $line]],
            );

            end;
        },
        "Got events"
    );
};

subtest mismatch => sub {
    my $check = mismatch qr/xyz/; my $line = __LINE__;
    is($check->lines, [$line], "Got line number");

    my $events = intercept {
        is('abcde', $check, "pass");
        is('axyzb', $check, "fail");
    };

    my $rx = "" . qr/xyz/;
    like(
        $events,
        array {
            event Ok => {pass => 1};

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[qw/axyzb !~/, "$rx", $line]],
            );

            end;
        },
        "Got events"
    );
};

subtest check => sub {
    my @lines;
    my $one = validator sub { $_ ? 1 : 0 }; push @lines => __LINE__;
    my $two = validator two => sub { $_ ? 1 : 0 }; push @lines => __LINE__;
    my $thr = validator 't', thr => sub { $_ ? 1 : 0 }; push @lines => __LINE__;

    is($one->lines, [$lines[0]], "line 1");
    is($two->lines, [$lines[1]], "line 2");
    is($thr->lines, [$lines[2]], "line 3");

    my $events = intercept {
        is(1, $one, 'pass');
        is(1, $two, 'pass');
        is(1, $thr, 'pass');

        is(0, $one, 'fail');
        is(0, $two, 'fail');
        is(0, $thr, 'fail');
    };

    like(
        $events,
        array {
            event Ok => {pass => 1};
            event Ok => {pass => 1};
            event Ok => {pass => 1};

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[0, 'CODE(...)', '<Custom Code>', $lines[0]]],
            );

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[0, 'CODE(...)', 'two', $lines[1]]],
            );

            fail_table(
                header => [qw/GOT OP CHECK LNs/],
                rows   => [[0, 't', 'thr', $lines[2]]],
            );

            end;
        },
        "Got events"
    );
};

subtest prop => sub {
    like(
        dies { prop x => 1 },
        qr/No current build/,
        "Need a build"
    );

    like(
        dies { [meta { my $x = prop x => 1 }] },
        qr/'prop' should only ever be called in void context/,
        "restricted context"
    );

    is(
        [1],
        array { prop size => 1; etc; },
        "Array builder supports 'prop'"
    );

    is(
        [1],
        bag { prop size => 1; etc; },
        "Bag builder supports 'prop'"
    );

    is(
        { foo => 1, },
        hash { prop size => 1; etc; },
        "Hash builder supports 'prop'"
    );

    my $events = intercept {
        is( [1],           array { prop size => 2; etc; } );
        is( [1],           bag   { prop size => 2; etc; } );
        is( { foo => 1, }, hash  { prop size => 2; etc; } );
    };

    is(
        $events,
        array {
            filter_items { grep { ref =~ /::Ok/ } @_ };
            all_items object { call pass => F };
            etc;
        }
    );
};

subtest end => sub {
    like(
        dies { end() },
        qr/No current build/,
        "Need a build"
    );

    like(
        dies { [meta { end() }] },
        qr/'Test2::Compare::Meta.*' does not support 'ending'/,
        "Build does not support end"
    );

    like(
        dies { [array { [end()] }] },
        qr/'end' should only ever be called in void context/,
        "end context"
    );
};

subtest field => sub {
    like(
        dies { field a => 1 },
        qr/No current build/,
        "Need a build"
    );

    like(
        dies { [array { field a => 1 }] },
        qr/'Test2::Compare::Array.*' does not support hash field checks/,
        "Build does not take fields"
    );

    like(
        dies { [hash { [field a => 1] }] },
        qr/'field' should only ever be called in void context/,
        "field context"
    );
};

subtest filter_items => sub {
    like(
        dies { filter_items {1} },
        qr/No current build/,
        "Need a build"
    );

    like(
        dies { [hash { filter_items {1} }] },
        qr/'Test2::Compare::Hash.*' does not support filters/,
        "Build does not take filters"
    );

    like(
        dies { [array { [filter_items {1}] }] },
        qr/'filter_items' should only ever be called in void context/,
        "filter context"
    );
};

subtest item => sub {
    like(
        dies { item 0 => 'a' },
        qr/No current build/,
        "Need a build"
    );

    like(
        dies { [hash { item 0 => 'a' }] },
        qr/'Test2::Compare::Hash.*' does not support array item checks/,
        "Build does not take items"
    );

    like(
        dies { [array { [ item 0 => 'a' ] }] },
        qr/'item' should only ever be called in void context/,
        "item context"
    );
};

subtest call => sub {
    like(
        dies { call foo => 1 },
        qr/No current build/,
        "Need a build"
    );

    like(
        dies { [hash { call foo => 1 }] },
        qr/'Test2::Compare::Hash.*' does not support method calls/,
        "Build does not take methods"
    );

    like(
        dies { [object { [ call foo => 1 ] }] },
        qr/'call' should only ever be called in void context/,
        "call context"
    );
};

subtest check => sub {
    like(
        dies { check 'a' },
        qr/No current build/,
        "Need a build"
    );

    like(
        dies { [hash { check 'a' }] },
        qr/'Test2::Compare::Hash.*' is not a check-set/,
        "Build must support checks"
    );

    like(
        dies { [in_set(sub { [ check 'a' ] })] },
        qr/'check' should only ever be called in void context/,
        "check context"
    );
};

subtest meta => sub {
    my $x = bless {}, 'Foo';
    my $check = meta {
        prop blessed => 'Foo';
        prop reftype => 'HASH';
        prop this    => $x;
    };
    my @lines = map { __LINE__ - $_ } reverse 1 .. 5;

    is($x, $check, "meta pass");

    my $array = [];
    my $events = intercept { is($array, $check, "meta fail") };
    like(
        $events,
        array {
            fail_table(
                header => [qw/PATH GOT OP CHECK LNs/],
                rows   => [
                    ["",          "$array",    '',   '<META CHECKS>', "$lines[0], $lines[4]"],
                    ['<blessed>', '<UNDEF>', '',   'Foo',           $lines[1]],
                    ['<reftype>', 'ARRAY',   'eq', 'HASH',          $lines[2]],
                    ['<this>',    "$array",    '',   '<HASH>',        $lines[3]],
                ],
            );
        },
        "got failure"
    );
};

subtest hash => sub {
    my $empty = hash { etc };

    my $full = hash {
        field a => 1;
        field b => 2;
        etc;
    };

    my $closed = hash {
        field a => 1;
        field b => 2;
        end();
    };

    isa_ok($_, 'Test2::Compare::Base', 'Test2::Compare::Hash') for $empty, $full, $closed;

    is({}, $empty, "empty hash");
    is({a => 1}, $empty, "unclosed empty matches anything");

    is({a => 1, b => 2}, $full, "full exact match");
    is({a => 1, b => 2, c => 3 }, $full, "full with extra");

    is({a => 1, b => 2}, $closed, "closed");

    my $events = intercept {
        is([], $empty);
        is(undef, $empty);
        is(1, $empty);
        is('HASH', $empty);

        is({}, $full);
        is({a => 2, b => 2}, $full);

        is({a => 1, b => 2, c => 3}, $closed);
    };

    @$events = grep {$_->isa('Test2::Event::Fail')} @$events;

    is(@$events, 7, '7 fail events');
};

subtest array => sub {
    my $empty = array { etc };

    my $simple = array {
        item 'a';
        item 'b';
        item 'c';
        etc;
    };

    my $filtered = array {
        filter_items { grep { m/a/ } @_ };
        item 0 => 'a';
        item 1 => 'a';
        item 2 => 'a';
        etc;
    };

    my $shotgun = array {
        item 1 => 'b';
        item 3 => 'd';
        etc;
    };

    my $closed = array {
        item 0 => 'a';
        item 1 => 'b';
        item 2 => 'c';
        end;
    };

    is([], $empty, "empty array");
    is(['a'], $empty, "any array matches empty");

    is([qw/a b c/], $simple, "simple exact match");
    is([qw/a b c d e/], $simple, "simple with extra");

    is([qw/x a b c a v a t t/], $filtered, "filtered out unwanted values");

    is([qw/a b c d e/], $shotgun, "selected indexes only");

    is([qw/a b c/], $closed, "closed array");

    my $events = intercept {
        is({}, $empty);
        is(undef, $empty);
        is(1, $empty);
        is('ARRAY', $empty);

        is([qw/x y z/], $simple);
        is([qw/a b x/], $simple);
        is([qw/x b c/], $simple);

        is([qw/aa a a a b/], $filtered);

        is([qw/b c d e f/], $shotgun);

        is([qw/a b c d/], $closed);
    };

    @$events = grep {$_->isa('Test2::Event::Fail')} @$events;
    is(@$events, 10, "10 fail events");
};

subtest bag => sub {
    my $empty = bag { etc };

    my $simple = bag {
        item 'a';
        item 'b';
        item 'c';
        etc;
    };

    my $closed = array {
        item 0 => 'a';
        item 1 => 'b';
        item 2 => 'c';
        end;
    };

    is([], $empty, "empty array");
    is(['a'], $empty, "any array matches empty");

    is([qw/a b c/], $simple, "simple exact match");
    is([qw/b c a/], $simple, "simple out of order");
    is([qw/a b c d e/], $simple, "simple with extra");
    is([qw/b a d e c/], $simple, "simple with extra, out of order");

    is([qw/a b c/], $closed, "closed array");

    my $events = intercept {
        is({}, $empty);
        is(undef, $empty);
        is(1, $empty);
        is('ARRAY', $empty);

        is([qw/x y z/], $simple);
        is([qw/a b x/], $simple);
        is([qw/x b c/], $simple);

        is([qw/a b c d/], $closed);
    };

    @$events = grep {$_->isa('Test2::Event::Fail')} @$events;
    is(@$events, 8, "8 fail events");
};

subtest object => sub {
    my $empty = object { };

    my $simple = object {
        call foo => 'foo';
        call bar => 'bar';
        call_list many => [1,2,3,4];
        call_hash many => {1=>2,3=>4};
        call [args => qw(a b)] => {a=>'b'};
    };

    my $array = object {
        call foo => 'foo';
        call bar => 'bar';
        call_list many => [1,2,3,4];
        call_hash many => {1=>2,3=>4};
        call [args => qw(a b)] => {a=>'b'};
        item 0 => 'x';
        item 1 => 'y';
        etc;
    };

    my $closed_array = object {
        call foo => 'foo';
        call bar => 'bar';
        call_list many => [1,2,3,4];
        call_hash many => {1=>2,3=>4};
        call [args => qw(a b)] => {a=>'b'};
        item 0 => 'x';
        item 1 => 'y';
        end();
    };

    my $hash = object {
        call foo => 'foo';
        call bar => 'bar';
        call_list many => [1,2,3,4];
        call_hash many => {1=>2,3=>4};
        call [args => qw(a b)] => {a=>'b'};
        field x => 1;
        field y => 2;
        etc;
    };

    my $closed_hash = object {
        call foo => 'foo';
        call bar => 'bar';
        call_list many => [1,2,3,4];
        call_hash many => {1=>2,3=>4};
        call [args => qw(a b)] => {a=>'b'};
        field x => 1;
        field y => 2;
        end();
    };

    my $meta = object {
        call foo => 'foo';
        call bar => 'bar';
        call_list many => [1,2,3,4];
        call_hash many => {1=>2,3=>4};
        call [args => qw(a b)] => {a=>'b'};
        prop blessed => 'ObjectFoo';
        prop reftype => 'HASH';
        prop isa => 'ObjectFoo';
        etc;
    };

    my $mix = object {
        call foo => 'foo';
        call bar => 'bar';
        call_list many => [1,2,3,4];
        call_hash many => {1=>2,3=>4};
        call [args => qw(a b)] => {a=>'b'};
        field x => 1;
        field y => 2;
        prop blessed => 'ObjectFoo';
        prop reftype => 'HASH';
        etc;
    };

    my $obf = mock 'ObjectFoo' => (add => [
        foo => sub { 'foo' },
        bar => sub { 'bar' },
        baz => sub {'baz'},
        many => sub { (1,2,3,4) },
        args => sub { shift; +{@_} },
    ]);
    my $obb = mock 'ObjectBar' => (add => [
        foo => sub { 'nop' },
        baz => sub { 'baz' },
        many => sub { (1,2,3,4) },
        args => sub { shift; +{@_} },
    ]);

    is(bless({}, 'ObjectFoo'), $empty, "Empty matches any object");
    is(bless({}, 'ObjectBar'), $empty, "Empty matches any object");

    is(bless({}, 'ObjectFoo'), $simple, "simple match hash");
    is(bless([], 'ObjectFoo'), $simple, "simple match array");

    is(bless([qw/x y/], 'ObjectFoo'), $array, "array match");
    is(bless([qw/x y z/], 'ObjectFoo'), $array, "array match");

    is(bless([qw/x y/], 'ObjectFoo'), $closed_array, "closed array");

    is(bless({x => 1, y => 2}, 'ObjectFoo'), $hash, "hash match");
    is(bless({x => 1, y => 2, z => 3}, 'ObjectFoo'), $hash, "hash match");

    is(bless({x => 1, y => 2}, 'ObjectFoo'), $closed_hash, "closed hash");

    is(bless({}, 'ObjectFoo'), $meta, "meta match");

    is(bless({x => 1, y => 2, z => 3}, 'ObjectFoo'), $mix, "mix");

    my $events = intercept {
        is({}, $empty);
        is(undef, $empty);
        is(1, $empty);
        is('ARRAY', $empty);

        is(bless({}, 'ObjectBar'), $simple, "simple match hash");
        is(bless([], 'ObjectBar'), $simple, "simple match array");

        is(bless([qw/a y/], 'ObjectFoo'), $array, "array match");
        is(bless([qw/a y z/], 'ObjectFoo'), $array, "array match");

        is(bless([qw/x y z/], 'ObjectFoo'), $closed_array, "closed array");

        is(bless({x => 2, y => 2}, 'ObjectFoo'), $hash, "hash match");
        is(bless({x => 2, y => 2, z => 3}, 'ObjectFoo'), $hash, "hash match");

        is(bless({x => 1, y => 2, z => 3}, 'ObjectFoo'), $closed_hash, "closed hash");

        is(bless({}, 'ObjectBar'), $meta, "meta match");
        is(bless([], 'ObjectFoo'), $meta, "meta match");

        is(bless({}, 'ObjectFoo'), $mix, "mix");
        is(bless([], 'ObjectFoo'), $mix, "mix");
        is(bless({x => 1, y => 2, z => 3}, 'ObjectBar'), $mix, "mix");
    };

    @$events = grep {$_->isa('Test2::Event::Fail')} @$events;
    is(@$events, 17, "17 fail events");

};

subtest event => sub {
    like(
        dies { event 0 => {} },
        qr/type is required/,
        "Must specify event type"
    );

    my $one = event Ok => {};
    is($one->meta->items->[0]->[1], 'Test2::Event::Ok', "Event type check");

    $one = event '+Foo::Event::Diag' => {};
    is($one->meta->items->[0]->[1], 'Foo::Event::Diag', "Event type check with +");

    my $empty = event 'Ok';
    isa_ok($empty, 'Test2::Compare::Event');

    like(
        dies { event Ok => 'xxx' },
        qr/'xxx' is not a valid event specification/,
        "Invalid spec"
    );

    my $from_sub = event Ok => sub {
        call pass  => 1;
        field name => 'pass';
        etc;
    };

    my $from_hash = event Ok => sub { field pass => 1; field name => 'pass'; etc};

    my $from_build = array { event Ok => sub { field pass => 1; field name => 'pass'; etc } };

    my $pass = intercept { ok(1, 'pass') };
    my $fail = intercept { ok(0, 'fail') };
    my $diag = intercept { diag("hi") };

    is($pass->[0], $empty,      "empty matches any event of the type");
    is($fail->[0], $empty,      "empty on a failed event");
    is($pass->[0], $from_sub,   "builder worked");
    is($pass->[0], $from_hash,  "hash spec worked");
    is($pass,      $from_build, "worked in build");

    my $events = intercept {
        is($diag->[0], $empty);

        is($fail->[0], $from_sub,   "builder worked");
        is($fail->[0], $from_hash,  "hash spec worked");
        is($fail,      $from_build, "worked in build");
    };

    @$events = grep {$_->isa('Test2::Event::Fail')} @$events;
    is(@$events, 4, "4 fail events");

    like(
        dies { event Ok => {}; 1 },
        qr/No current build!/,
        "Need a build!"
    );
};

subtest sets => sub {
    subtest check_set => sub {
        is(
            'foo',
            check_set(sub { check 'foo'; check match qr/fo/; check match qr/oo/ }),
            "matches everything in set"
        );

        is(
            'foo',
            check_set('foo', match qr/fo/, match qr/oo/),
            "matches everything in set"
        );

        like(
            intercept {
                is('fox', check_set(sub{ check match qr/fo/; check 'foo' }));
                is('fox', check_set(match qr/fo/, 'foo'));
            },
            array {
                filter_items { grep { !$_->isa('Test2::Event::Diag') } @_ };
                event Fail => {};
                event Fail => {};
                end;
            },
            "Failed cause not all checks passed"
        );
    };

    subtest in_set => sub {
        is(
            'foo',
            in_set(sub { check 'x'; check 'y'; check 'foo' }),
            "Item is in set"
        );
        is(
            'foo',
            in_set(qw/x y foo/),
            "Item is in set"
        );

        like(
            intercept {
                is('fox', in_set(sub{ check 'x'; check 'foo' }));
                is('fox', in_set('x', 'foo'));
            },
            array {
                filter_items { grep { !$_->isa('Test2::Event::Diag') } @_ };
                event Fail => {};
                event Fail => {};
                end;
            },
            "Failed cause not all checks passed"
        );
    };

    subtest not_in_set => sub {
        is(
            'foo',
            not_in_set(sub { check 'x'; check 'y'; check 'z' }),
            "Item is not in set"
        );
        is(
            'foo',
            not_in_set(qw/x y z/),
            "Item is not in set"
        );

        like(
            intercept {
                is('fox', not_in_set(sub{ check 'x'; check 'fox' }));
                is('fox', not_in_set('x', 'fox'));
            },
            array {
                filter_items { grep { !$_->isa('Test2::Event::Diag') } @_ };
                event Fail => {};
                event Fail => {};
                end;
            },
            "Failed cause not all checks passed"
        );

    };
};

subtest regex => sub {
    is(qr/abc/, qr/abc/, "same regex");

    my $events = intercept {
        is(qr/abc/i, qr/abc/, "Wrong flags");
        is(qr/abc/, qr/abcd/, "wrong pattern");
        is(qr/abc/, exact_ref(qr/abc/), "not an exact match");
    };

    @$events = grep {$_->isa('Test2::Event::Fail')} @$events;
    is(@$events, 3, "3 fail events");
};

subtest isnt => sub {
    isnt('a', 'b', "a is not b");
    isnt({}, [], "has is not array");
    isnt(0, 1, "0 is not 1");

    my $events = intercept {
        isnt([], []);
        isnt('a', 'a');
        isnt(1, 1);
        isnt({}, {});
    };

    @$events = grep {$_->isa('Test2::Event::Ok')} @$events;
    is(@$events, 4, "4 events");
    ok(!$_->{pass}, "Event was a failure") for @$events
};

subtest unlike => sub {
    unlike('a', 'b', "a is not b");
    unlike({}, [], "has is not array");
    unlike(0, 1, "0 is not 1");
    unlike('aaa', qr/bbb/, "aaa does not match /bbb/");

    my $events = intercept {
        unlike([], []);
        unlike('a', 'a');
        unlike(1, 1);
        unlike({}, {});
        unlike( 'foo', qr/o/ );
    };

    @$events = grep {$_->isa('Test2::Event::Ok')} @$events;
    is(@$events, 5, "5 events");
    ok(!$_->{pass}, "Event was a failure") for @$events
};

subtest all_items_on_array => sub {
    like(
        [qw/a aa aaa/],
        array {
            all_items match qr/^a+$/;
            item 'a';
            item 'aa';
        },
        "All items match regex"
    );

    my @lines;
    my $array = [qw/a aa aaa/];
    my $regx = qr/^b+$/;
    my $events = intercept {
        is(
            $array,
            array {
                all_items match $regx;  push @lines => __LINE__;
                item 'b';               push @lines => __LINE__;
                item 'aa';              push @lines => __LINE__;
                end;
            },
            "items do not all match, and diag reflects all issues, and in order"
        );
    };
    like(
        $events,
        array {
            fail_table(
                header => [qw/PATH GOT OP CHECK LNs/],
                rows   => [
                    ['', "$array", '', "<ARRAY>", ($lines[0] - 1) . ", " . ($lines[-1] + 2)],
                    ['[0]', 'a',   '=~',      "$regx",              $lines[0]],
                    ['[0]', 'a',   'eq',      'b',                $lines[1]],
                    ['[1]', 'aa',  '=~',      "$regx",              $lines[0]],
                    ['[2]', 'aaa', '=~',      "$regx",              $lines[0]],
                    ['[2]', 'aaa', '!exists', '<DOES NOT EXIST>', ''],
                ],
            );
        },
        "items do not all match, and diag reflects all issues, and in order"
    );
};

subtest all_items_on_bag => sub {
    like(
        [qw/a aa aaa/],
        bag {
            all_items match qr/^a+$/;
            item 'a';
            item 'aa';
        },
        "All items match regex"
    );

    my @lines;
    my $array = [qw/a aa aaa/];
    my $regx = qr/^b+$/;
    my $events = intercept {
        is(
            $array,
            bag {
                all_items match $regx;  push @lines => __LINE__;
                item 'b';               push @lines => __LINE__;
                item 'aa';              push @lines => __LINE__;
                end;
            },
            "items do not all match, and diag reflects all issues, and in order"
        );
    };

    like(
        $events,
        array {
            fail_table(
                header => [qw/PATH GOT OP CHECK LNs/],
                rows   => [
                    ['', "$array", '', "<BAG>", ($lines[0] - 1) . ", " . ($lines[-1] + 2)],
                    ['[*]', '<DOES NOT EXIST>', '',   'b',   $lines[1]],
                    ['[0]', 'a',                '=~', "$regx", $lines[0]],
                    ['[1]', 'aa',               '=~', "$regx", $lines[0]],
                    ['[2]', 'aaa',              '=~', "$regx", $lines[0]],
                ],
            );
        },
        "items do not all match, and diag reflects all issues, and in order"
    );
};

subtest all_keys_and_vals => sub {
    is(
        {a => 'a', 'aa' => 'aa', 'aaa' => 'aaa'},
        hash {
            all_values match qr/^a+$/;
            all_keys match qr/^a+$/;
            field a   => 'a';
            field aa  => 'aa';
            field aaa => 'aaa';
        },
        "All items match regex"
    );

    my @lines;
    my $hash = {a => 'a', 'aa' => 'aa', 'aaa' => 'aaa'};
    my $regx = qr/^b+$/;
    my $events = intercept {
        is(
            $hash,
            hash {
                all_keys match $regx;   push @lines => __LINE__;
                all_vals match $regx;   push @lines => __LINE__;
                field aa => 'aa';       push @lines => __LINE__;
                field b  => 'b';        push @lines => __LINE__;
                end;
            },
            "items do not all match, and diag reflects all issues, and in order"
        );
    };
    like(
        $events,
        array {
            fail_table(
                header => [qw/PATH GOT OP CHECK LNs/],
                rows   => [
                    ['',            "$hash",            '',        '<HASH>',           join(', ', $lines[0] - 1, $lines[-1] + 2)],
                    ['{aa} <KEY>',  'aa',               '=~',      "$regx",            $lines[0]],
                    ['{aa}',        'aa',               '=~',      "$regx",            $lines[1]],
                    ['{b}',         '<DOES NOT EXIST>', '',        'b',                $lines[3]],
                    ['{a} <KEY>',   'a',                '=~',      "$regx",            $lines[0]],
                    ['{a}',         'a',                '=~',      "$regx",            $lines[1]],
                    ['{a}',         'a',                '!exists', '<DOES NOT EXIST>', '',],
                    ['{aaa} <KEY>', 'aaa',              '=~',      "$regx",            $lines[0]],
                    ['{aaa}',       'aaa',              '=~',      "$regx",            $lines[1]],
                    ['{aaa}',       'aaa',              '!exists', '<DOES NOT EXIST>', ''],
                ],
            );
        },
        "items do not all match, and diag reflects all issues, and in order"
    );
};

{
    package Local::MockDumper;
    use Data::Dumper ();
    no warnings 'once';
    our @ISA = 'Data::Dumper';
    sub Dump {
        my $self = shift;
        our @args = @_;
        our $deparse = $Data::Dumper::Deparse;
        return $self->SUPER::Dump(@_);
    }
}

subtest 'T2_AUTO_DUMP and T2_AUTO_DEPARSE' => sub {

    subtest 'Trivial example where tests pass' => sub {
        local @Local::MockDumper::args = 'NOT CALLED';
        local $Local::MockDumper::deparse = 'NOT CALLED';
        my $events = intercept {
            local $ENV{T2_AUTO_DUMP} = 'Local::MockDumper';
            local $ENV{T2_AUTO_DEPARSE} = 0;
            is( [], [], 'ok' );
        };
        is(
            $events,
            array {
                event Ok => sub {};
                end;
            },
            'MockDumper not called because test passed',
        );
    };

    subtest 'Trivial example where test fails but autodump is not in use' => sub {
        local @Local::MockDumper::args = 'NOT CALLED';
        local $Local::MockDumper::deparse = 'NOT CALLED';
        my $events = intercept {
            local $ENV{T2_AUTO_DUMP} = 0;
            local $ENV{T2_AUTO_DEPARSE} = 0;
            is( {}, [], 'ok' );
        };
        is(
            $events,
            array {
                event Fail => sub {};
                end;
            },
            'MockDumper not called because autodump not enabled',
        );
        is(
            \@Local::MockDumper::args,
            ['NOT CALLED'],
            'MockDumper did not get any arguments'
        );
        is(
            $Local::MockDumper::deparse,
            'NOT CALLED',
            '$Deparse was not altered'
        );
    };

    subtest 'Simple example where test fails and gets autodumped' => sub {
        local @Local::MockDumper::args = 'NOT CALLED';
        local $Local::MockDumper::deparse = 'NOT CALLED';
        my $events = intercept {
            local $ENV{T2_AUTO_DUMP} = 'Local::MockDumper';
            local $ENV{T2_AUTO_DEPARSE} = 0;
            is( {}, [], 'ok' );
        };
        is(
            $events,
            array {
                event Fail => sub {};
                event Diag => sub {
                    call message => match qr/\$GOT/;
                };
                end;
            },
            'MockDumper called because test failed',
        );
        is(
            \@Local::MockDumper::args,
            [[{}], ['GOT']],
            'MockDumper was passed the correct arguments'
        );
        is(
            $Local::MockDumper::deparse,
            F(),
            '$Deparse was false'
        );
    };

    subtest 'Simple example where test fails and gets autodumped' => sub {
        local @Local::MockDumper::args = 'NOT CALLED';
        local $Local::MockDumper::deparse = 'NOT CALLED';
        my $events = intercept {
            local $ENV{T2_AUTO_DUMP} = 'Local::MockDumper';
            local $ENV{T2_AUTO_DEPARSE} = 1;
            is( sub { "XYZ" }, [], 'ok' );
        };
        is(
            $events,
            array {
                event Fail => sub {};
                event Diag => sub {
                    call message => match qr/\$GOT/;
                    call message => match qr/XYZ/;
                };
                end;
            },
            'MockDumper called because test failed',
        );
        is(
            $Local::MockDumper::deparse,
            T(),
            '$Deparse was true'
        );
    };
};

done_testing;