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`Mini Shell

HOME


Mini Shell 1.0
DIR:/opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/test/cxx/IOTools/
Upload File :
Current File : //opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/test/cxx/IOTools/IOUtilsTest.cpp
#include <TestSupport.h>
#include <IOTools/IOUtils.h>
#include <SystemTools/SystemTime.h>
#include <oxt/system_calls.hpp>
#include <boost/bind/bind.hpp>
#include <sys/types.h>
#include <cerrno>
#include <string>

using namespace Passenger;
using namespace std;
using namespace boost;
using namespace oxt;

namespace tut {
	static ssize_t writevResult;
	static int writevErrno;
	static int writevCalled;
	static string writevData;

	static ssize_t writev_mock(int fildes, const struct iovec *iov, int iovcnt) {
		if (writevResult >= 0) {
			string data;
			for (int i = 0; i < iovcnt && data.size() < (size_t) writevResult; i++) {
				data.append(
					(const char *) iov[i].iov_base,
					iov[i].iov_len);
			}
			data.resize(writevResult);
			writevData.append(data);
		}
		writevCalled++;
		errno = writevErrno;
		return writevResult;
	}

	struct IOTools_IOUtilsTest: public TestBase {
		string restBuffer;

		IOTools_IOUtilsTest() {
			writevResult = 0;
			writevErrno = 0;
			writevCalled = 0;
			writevData.clear();
			setWritevFunction(writev_mock);
		}

		~IOTools_IOUtilsTest() {
			setWritevFunction(NULL);
		}

		Pipe createNonBlockingPipe() {
			Pipe p = createPipe(__FILE__, __LINE__);
			setNonBlocking(p.second);
			return p;
		}

		static void writeDataAfterSomeTime(int fd, unsigned int sleepTimeInUsec) {
			try {
				syscalls::usleep(sleepTimeInUsec);
				syscalls::write(fd, "hi", 2);
			} catch (const boost::thread_interrupted &) {
				// Do nothing.
			}
		}

		static void writeDataSlowly(int fd, unsigned int bytesToWrite, unsigned int bytesPerSec) {
			try {
				for (unsigned i = 0; i < bytesToWrite && !boost::this_thread::interruption_requested(); i++) {
					syscalls::write(fd, "x", 1);
					syscalls::usleep(1000000 / bytesPerSec);
				}
			} catch (const boost::thread_interrupted &) {
				// Do nothing.
			}
		}

		static void readDataAfterSomeTime(int fd, unsigned int sleepTimeInUsec) {
			try {
				char buf[1024 * 8];
				syscalls::usleep(sleepTimeInUsec);
				syscalls::read(fd, buf, sizeof(buf));
			} catch (const boost::thread_interrupted &) {
				// Do nothing.
			}
		}

		static void readDataSlowly(int fd, int bytesToRead, int bytesPerSec) {
			try {
				unsigned long long start = SystemTime::getUsec();
				unsigned long long deadline = start +
					(bytesToRead * 1000000.0 / bytesPerSec);
				int alreadyRead = 0;

				while (alreadyRead < bytesToRead && !boost::this_thread::interruption_requested()) {
					unsigned long long elapsed = SystemTime::getUsec();
					double progress = (elapsed - start) / (double) (deadline - start);
					int shouldHaveRead = progress * bytesToRead;
					int shouldNowRead = shouldHaveRead - alreadyRead;

					if (shouldNowRead > 0) {
						char *buf = new char[shouldNowRead];
						ssize_t ret = syscalls::read(fd, buf, shouldNowRead);
						int e = errno;
						delete[] buf;
						if (ret == -1) {
							throw SystemException("read error", e);
						} else if (ret == 0) {
							break;
						}
						alreadyRead += ret;
					}
					syscalls::usleep(1000);
				}
			} catch (const boost::thread_interrupted &) {
				// Do nothing.
			}
		}
	};

	DEFINE_TEST_GROUP_WITH_LIMIT(IOTools_IOUtilsTest, 100);

	/***** Test gatheredWrite() with empty input rest buffer *****/

	TEST_METHOD(1) {
		// Test complete write of a single data buffer.
		StaticString data = "hello world";
		writevResult = data.size();
		ensure_equals(gatheredWrite(0, &data, 1, restBuffer), writevResult);
		ensure_equals(writevData, "hello world");
		ensure(restBuffer.empty());
	}

	TEST_METHOD(2) {
		// Test complete write of multiple data buffers.
		StaticString data[] = { "hello ", "world", "!!!!!!" };
		writevResult = strlen("hello world!!!!!!");
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "hello world!!!!!!");
		ensure(restBuffer.empty());
	}

	TEST_METHOD(3) {
		// Test partial write of a single data buffer.
		StaticString data = "hello world";
		writevResult = 3;
		ensure_equals(gatheredWrite(0, &data, 1, restBuffer), writevResult);
		ensure_equals(writevData, "hel");
		ensure_equals(restBuffer, "lo world");
	}

	TEST_METHOD(4) {
		// Test partial write of multiple data buffers:
		// first buffer is partially written.
		StaticString data[] = { "hello ", "world", "!!!!!!" };
		writevResult = 2;
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "he");
		ensure_equals(restBuffer, "llo world!!!!!!");
	}

	TEST_METHOD(5) {
		// Test partial write of multiple data buffers:
		// first buffer is completely written.
		StaticString data[] = { "hello ", "world", "!!!!!!" };
		writevResult = 6;
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "hello ");
		ensure_equals(restBuffer, "world!!!!!!");
	}

	TEST_METHOD(6) {
		// Test partial write of multiple data buffers:
		// non-first buffer is partially written.
		StaticString data[] = { "hello ", "world", "!!!!!!" };
		writevResult = 8;
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "hello wo");
		ensure_equals(restBuffer, "rld!!!!!!");
	}

	TEST_METHOD(7) {
		// Test partial write of multiple data buffers:
		// non-first buffer is completely written.
		StaticString data[] = { "hello ", "world", "!!!!!!" };
		writevResult = 11;
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "hello world");
		ensure_equals(restBuffer, "!!!!!!");
	}

	TEST_METHOD(8) {
		// Test failed write of a single data buffer: blocking error.
		StaticString data = "hello world";
		writevResult = -1;
		writevErrno = EAGAIN;
		ensure_equals(gatheredWrite(0, &data, 1, restBuffer), 0);
		ensure_equals(restBuffer, "hello world");
	}

	TEST_METHOD(9) {
		// Test failed write of a single data buffer: other error.
		StaticString data = "hello world";
		writevResult = -1;
		writevErrno = EBADF;
		ssize_t ret = gatheredWrite(0, &data, 1, restBuffer);
		int e = errno;
		ensure_equals(ret, -1);
		ensure_equals(e, EBADF);
		ensure_equals("Rest buffer remains untouched", restBuffer, "");
	}

	TEST_METHOD(10) {
		// Test failed write of multiple data buffers: blocking error.
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = -1;
		writevErrno = EAGAIN;
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), 0);
		ensure_equals(restBuffer, "hello world!!!");
	}

	TEST_METHOD(11) {
		// Test failed write of multiple data buffers: other error.
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = -1;
		writevErrno = EBADF;
		ssize_t ret = gatheredWrite(0, data, 3, restBuffer);
		int e = errno;
		ensure_equals(ret, -1);
		ensure_equals(e, EBADF);
		ensure_equals("Rest buffer remains untouched", restBuffer, "");
	}

	TEST_METHOD(12) {
		// Test writing nothing.
		StaticString data[] = { "", "", "" };
		ssize_t ret = gatheredWrite(0, data, 3, restBuffer);
		int e = errno;
		ensure_equals(ret, 0);
		ensure_equals(e, 0);
		ensure_equals(writevCalled, 0);
		ensure_equals(restBuffer, "");
	}

	TEST_METHOD(13) {
		// Test writing multiple buffers where some are empty.
		StaticString data[] = { "hello ", "", "world" };
		writevResult = strlen("hello world");
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "hello world");
		ensure_equals(restBuffer, "");
	}

	/***** Test gatheredWrite() with non-empty input rest buffer *****/

	TEST_METHOD(15) {
		// Test complete write with a single data buffer.
		restBuffer = "oh ";
		StaticString data = "hello world";
		writevResult = restBuffer.size() + data.size();
		ensure_equals(gatheredWrite(0, &data, 1, restBuffer), writevResult);
		ensure_equals(writevData, "oh hello world");
		ensure(restBuffer.empty());
	}

	TEST_METHOD(16) {
		// Test complete write with multiple data buffers.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = strlen("oh hello world!!!");
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "oh hello world!!!");
		ensure(restBuffer.empty());
	}

	TEST_METHOD(17) {
		// Test partial write of a single data buffer.
		StaticString data = "hello world";
		writevResult = 3;
		ensure_equals(gatheredWrite(0, &data, 1, restBuffer), writevResult);
		ensure_equals(writevData, "hel");
		ensure_equals(restBuffer, "lo world");
	}

	TEST_METHOD(18) {
		// Test partial write of multiple data buffers:
		// rest buffer is partially written.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = 2;
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "oh");
		ensure_equals(restBuffer, " hello world!!!");
	}

	TEST_METHOD(19) {
		// Test partial write of multiple data buffers:
		// rest buffer is completely written.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = strlen("oh ");
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "oh ");
		ensure_equals(restBuffer, "hello world!!!");
	}

	TEST_METHOD(20) {
		// Test partial write of multiple data buffers:
		// first buffer is partially written.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = strlen("oh h");
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "oh h");
		ensure_equals(restBuffer, "ello world!!!");
	}

	TEST_METHOD(21) {
		// Test partial write of multiple data buffers:
		// first buffer is completely written.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = strlen("oh hello ");
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "oh hello ");
		ensure_equals(restBuffer, "world!!!");
	}

	TEST_METHOD(22) {
		// Test partial write of multiple data buffers:
		// non-first buffer is partially written.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = strlen("oh hello wo");
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "oh hello wo");
		ensure_equals(restBuffer, "rld!!!");
	}

	TEST_METHOD(23) {
		// Test partial write of multiple data buffers:
		// non-first buffer is completely written.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = strlen("oh hello world");
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "oh hello world");
		ensure_equals(restBuffer, "!!!");
	}

	TEST_METHOD(24) {
		// Test failed write of a single data buffer: blocking error.
		restBuffer = "oh ";
		StaticString data = "hello world";
		writevResult = -1;
		writevErrno = EAGAIN;
		ensure_equals(gatheredWrite(0, &data, 1, restBuffer), 0);
		ensure_equals(restBuffer, "oh hello world");
	}

	TEST_METHOD(25) {
		// Test failed write of a single data buffer: other error.
		restBuffer = "oh ";
		StaticString data = "hello world";
		writevResult = -1;
		writevErrno = EBADF;
		ssize_t ret = gatheredWrite(0, &data, 1, restBuffer);
		int e = errno;
		ensure_equals(ret, -1);
		ensure_equals(e, EBADF);
		ensure_equals("Rest buffer remains untouched", restBuffer, "oh ");
	}

	TEST_METHOD(26) {
		// Test failed write of multiple data buffers: blocking error.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = -1;
		writevErrno = EAGAIN;
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), 0);
		ensure_equals(restBuffer, "oh hello world!!!");
	}

	TEST_METHOD(27) {
		// Test failed write of multiple data buffers: other error.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "world", "!!!" };
		writevResult = -1;
		writevErrno = EBADF;
		ssize_t ret = gatheredWrite(0, data, 3, restBuffer);
		int e = errno;
		ensure_equals(ret, -1);
		ensure_equals(e, EBADF);
		ensure_equals("Rest buffer remains untouched", restBuffer, "oh ");
	}

	TEST_METHOD(28) {
		// Test writing multiple buffers that are all empty.
		restBuffer = "oh ";
		StaticString data[] = { "", "", "" };
		writevResult = 3;
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "oh ");
		ensure_equals(restBuffer, "");
	}

	TEST_METHOD(29) {
		// Test writing multiple buffers where one is empty.
		restBuffer = "oh ";
		StaticString data[] = { "hello ", "", "world" };
		writevResult = strlen("oh hello world");
		ensure_equals(gatheredWrite(0, data, 3, restBuffer), writevResult);
		ensure_equals(writevData, "oh hello world");
		ensure_equals(restBuffer, "");
	}


	/***** Test gatheredWrite() blocking version *****/

	TEST_METHOD(35) {
		// It doesn't call writev() if requested to send 0 bytes.
		StaticString data[2] = { "", "" };
		gatheredWrite(0, data, 2);
		ensure_equals(writevCalled, 0);
	}

	TEST_METHOD(36) {
		// Test sending all data in a single writev() call.
		StaticString data[] = { "hello", "my", "world" };
		writevResult = strlen("hellomyworld");
		gatheredWrite(0, data, 3);
		ensure_equals(writevData, "hellomyworld");
		ensure_equals(writevCalled, 1);
	}

	TEST_METHOD(42) {
		// Test writing byte-by-byte.
		StaticString data[] = { "hello", "my", "world", "!!" };
		writevResult = 1;
		gatheredWrite(0, data, 4);
		ensure_equals(writevCalled, (int) strlen("hellomyworld!!"));
		ensure_equals(writevData, "hellomyworld!!");
	}

	TEST_METHOD(43) {
		// Test writev() writing in chunks of 2 bytes.
		StaticString data[] = { "hello", "my", "world", "!!" };
		writevResult = 2;
		gatheredWrite(0, data, 4);
		ensure_equals(writevCalled, (int) strlen("hellomyworld!!") / 2);
		ensure_equals(writevData, "hellomyworld!!");
	}

	static ssize_t writev_mock_44(int fildes, const struct iovec *iov, int iovcnt) {
		if (writevCalled == 3) {
			// Have the last call return 2 instead of 4.
			writevResult = 2;
		}
		return writev_mock(fildes, iov, iovcnt);
	}

	TEST_METHOD(44) {
		// Test writev() writing in chunks of 4 bytes.
		setWritevFunction(writev_mock_44);
		StaticString data[] = { "hello", "my", "world", "!!" };
		writevResult = 4;
		gatheredWrite(0, data, 4);
		ensure_equals(writevCalled, 4);
		ensure_equals(writevData, "hellomyworld!!");
	}

	TEST_METHOD(45) {
		// Test writev() timeout support.
		setWritevFunction(NULL);
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long startTime = SystemTime::getUsec();
		unsigned long long timeout = 30000;
		char data1[1024], data2[1024];
		StaticString data[] = {
			StaticString(data1, sizeof(data1) - 1),
			StaticString(data2, sizeof(data2) - 1)
		};
		memset(data1, 'x', sizeof(data1));
		memset(data2, 'y', sizeof(data2));

		try {
			for (int i = 0; i < 1024; i++) {
				gatheredWrite(p[1], data, 2, &timeout);
			}
			fail("TimeoutException expected");
		} catch (const TimeoutException &) {
			unsigned long long elapsed = SystemTime::getUsec() - startTime;
			ensure("At least 29 msec have passed", elapsed >= 29000);
			ensure("At most 95 msec have passed", elapsed <= 95000);
			ensure(timeout <= 2000);
		}
	}

	/***** Test waitUntilReadable() *****/

	TEST_METHOD(50) {
		// waitUntilReadable() waits for the specified timeout if no data is readable.
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long timeout = 25000;
		ensure("No data is available", !waitUntilReadable(p.first, &timeout));
		ensure("The passed time is deducted from the timeout", timeout < 5000);
	}

	TEST_METHOD(51) {
		// waitUntilReadable() waits for less than the specified timeout if data
		// is not available immediately but still available before the timeout.
		Pipe p = createPipe(__FILE__, __LINE__);
		TempThread thr(boost::bind(&writeDataAfterSomeTime, p.second, 35000));

		unsigned long long timeout = 1000000;
		ensure("Data is available", waitUntilReadable(p.first, &timeout));
		ensure("At least 35 msec passed.", timeout <= 1000000 - 35000);
		ensure("At most 70 msec passed.", timeout >= 1000000 - 70000);  // depends on system scheduler though
	}

	TEST_METHOD(52) {
		// waitUntilReadable() returns immediately if timeout is 0.
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long timeout = 0;
		ensure("No data is available", !waitUntilReadable(p.first, &timeout));
		ensure_equals("Timeout is not modified", timeout, 0u);

		write(p.second, "hi", 2);
		ensure("Data is available", waitUntilReadable(p.first, &timeout));
		ensure_equals("Timeout is not modified", timeout, 0u);
	}

	TEST_METHOD(53) {
		// waitUntilReadable() returns immediately if there's data immediately available.
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long timeout = 100000;
		write(p.second, "hi", 2);
		ensure("Data is available", waitUntilReadable(p.first, &timeout));
		ensure("Timeout is not modified", timeout >= 100000 - 5000);
	}

	/***** Test readExact() *****/

	TEST_METHOD(54) {
		// readExact() throws TimeoutException if no data is received within the timeout.
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long timeout = 50000;
		char buf;
		try {
			readExact(p.first, &buf, 1, &timeout);
			fail("No TimeoutException thrown.");
		} catch (const TimeoutException &) {
			ensure("The passed time is deducted from timeout", timeout < 5000);
		}
	}

	TEST_METHOD(55) {
		// readExact() throws TimeoutException if not enough data is received within the timeout.
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long timeout = 20000;
		char buf[100];

		TempThread thr(boost::bind(&writeDataSlowly, p.second, sizeof(buf), 1));

		try {
			readExact(p.first, &buf, sizeof(buf), &timeout);
			fail("No TimeoutException thrown.");
		} catch (const TimeoutException &) {
			ensure("The passed time is deducted from timeout", timeout < 5000);
		}
	}

	TEST_METHOD(56) {
		// readExact() throws TimeoutException if timeout is 0 and no data is immediately available.
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long timeout = 0;
		char buf;
		try {
			readExact(p.first, &buf, 1, &timeout);
			fail("No TimeoutException thrown.");
		} catch (const TimeoutException &) {
			ensure_equals("Timeout unchanged", timeout, 0u);
		}
	}

	TEST_METHOD(57) {
		// readExact() throws TimeoutException if timeout is 0 and not enough data is
		// immediately available.
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long timeout = 0;
		write(p.second, "hi", 2);
		try {
			char buf[100];
			readExact(p.first, &buf, sizeof(buf), &timeout);
			fail("No TimeoutException thrown.");
		} catch (const TimeoutException &) {
			ensure_equals("Timeout is unchanged", timeout, 0u);
		}
	}

	TEST_METHOD(58) {
		// readExact() deducts the amount of time spent on waiting from the timeout variable.
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long timeout = 100000;
		char buf[3];

		// Spawn a thread that writes 100 bytes per second, i.e. each byte takes 10 msec.
		TempThread thr(boost::bind(&writeDataSlowly, p.second, 1000, 100));

		// We read 3 bytes.
		ensure_equals(readExact(p.first, &buf, sizeof(buf), &timeout), 3u);
		ensure("Should have taken at least 20 msec", timeout <= 100000 - 20000);
        #if defined(__FreeBSD__) || defined(BOOST_OS_MACOS)
			// Stupid timer resolution on FreeBSD...
			ensure("Should have taken at most 95 msec", timeout >= 100000 - 95000);
		#else
			ensure("Should have taken at most 50 msec", timeout >= 100000 - 40000);
		#endif
	}

	TEST_METHOD(59) {
		// readExact() does not wait and does not modify the timeout variable if there's
		// immediately enough data available.
		Pipe p = createPipe(__FILE__, __LINE__);
		unsigned long long timeout = 100000;
		char buf[2];

		write(p.second, "hi", 2);
		ensure_equals(readExact(p.first, &buf, 2, &timeout), 2u);
		ensure("Timeout not modified", timeout >= 95000);
	}

	/***** Test waitUntilWritable() *****/

	TEST_METHOD(60) {
		// waitUntilWritable() waits for the specified timeout if no data is writable.
		Pipe p = createNonBlockingPipe();
		writeUntilFull(p.second);
		unsigned long long timeout = 25000;
		ensure("Socket did not become writable", !waitUntilWritable(p.second, &timeout));
		ensure("The passed time is deducted from the timeout", timeout < 5000);
	}

	TEST_METHOD(61) {
		// waitUntilWritable() waits for less than the specified timeout if the fd
		// is not immediately writable but still writable before the timeout.
		Pipe p = createNonBlockingPipe();
		writeUntilFull(p.second);
		TempThread thr(boost::bind(&readDataAfterSomeTime, p.first, 35000));

		unsigned long long timeout = 1000000;
		ensure("Socket became writable", waitUntilWritable(p.second, &timeout));
		ensure("At least 35 msec passed.", timeout <= 1000000 - 35000);
		ensure("At most 70 msec passed.", timeout >= 1000000 - 70000);  // depends on system scheduler though
	}

	TEST_METHOD(62) {
		// waitUntilWritable() returns immediately if timeout is 0.
		Pipe p = createNonBlockingPipe();
		writeUntilFull(p.second);
		unsigned long long timeout = 0;
		ensure("Socket is not writable", !waitUntilWritable(p.second, &timeout));
		ensure_equals("Timeout is not modified", timeout, 0u);

		char buf[1024 * 8];
		read(p.first, buf, sizeof(buf));
		ensure("Socket became writable", waitUntilWritable(p.second, &timeout));
		ensure_equals("Timeout is not modified", timeout, 0u);
	}

	TEST_METHOD(63) {
		// waitUntilWritable() returns immediately if the fd is immediately writable.
		Pipe p = createNonBlockingPipe();
		writeUntilFull(p.second);
		unsigned long long timeout = 100000;
		char buf[1024 * 8];
		read(p.first, buf, sizeof(buf));
		ensure("Socket became writable", waitUntilWritable(p.second, &timeout));
		ensure("Timeout is not modified", timeout >= 100000 - 5000);
	}

	/***** Test readExact() *****/

	TEST_METHOD(64) {
		// writeExact() throws TimeoutException if fd does not become writable within the timeout.
		Pipe p = createNonBlockingPipe();
		writeUntilFull(p.second);
		unsigned long long timeout = 50000;
		try {
			writeExact(p.second, "x", 1, &timeout);
			fail("No TimeoutException thrown.");
		} catch (const TimeoutException &) {
			ensure("The passed time is deducted from timeout", timeout < 5000);
		}
	}

	TEST_METHOD(65) {
		// writeExact() throws TimeoutException if not enough data is written within the timeout.
		Pipe p = createNonBlockingPipe();
		writeUntilFull(p.second);
		unsigned long long timeout = 20000;
		char buf[1024 * 3];

		TempThread thr(boost::bind(&readDataSlowly, p.first, sizeof(buf), 512));

		try {
			writeExact(p.second, "x", 1, &timeout);
			fail("No TimeoutException thrown.");
		} catch (const TimeoutException &) {
			ensure("The passed time is deducted from timeout", timeout < 5000);
		}
	}

	TEST_METHOD(66) {
		// writeExact() throws TimeoutException if timeout is 0 and the fd is not immediately writable.
		Pipe p = createNonBlockingPipe();
		writeUntilFull(p.second);
		unsigned long long timeout = 0;
		try {
			writeExact(p.second, "x", 1, &timeout);
			fail("No TimeoutException thrown.");
		} catch (const TimeoutException &) {
			ensure_equals("Timeout unchanged", timeout, 0u);
		}
	}

	TEST_METHOD(67) {
		// writeExact() throws TimeoutException if timeout is 0 not enough data could be written immediately.
		Pipe p = createNonBlockingPipe();
		writeUntilFull(p.second);
		unsigned long long timeout = 0;

		char buf[1024];
		read(p.first, buf, sizeof(buf));

		char buf2[1024 * 8];
		memset(buf2, 0, sizeof(buf2));

		try {
			writeExact(p.second, buf2, sizeof(buf2), &timeout);
			fail("No TimeoutException thrown.");
		} catch (const TimeoutException &) {
			ensure_equals("Timeout is unchanged", timeout, 0u);
		}
	}

	TEST_METHOD(68) {
		// readExact() deducts the amount of time spent on waiting from the timeout variable.
		Pipe p = createNonBlockingPipe();
		unsigned long long timeout = 100000;

		// Spawn a thread that reads 200000 bytes in 35 msec.
		TempThread thr(boost::bind(&readDataSlowly, p.first, 5714286, 5714286));

		// We write 200000 bytes.
		char buf[200000];
		memset(buf, 0, sizeof(buf));
		writeExact(p.second, &buf, sizeof(buf), &timeout);
		ensure("Should have taken at least 20 msec", timeout <= 100000 - 20000);
		ensure("Should have taken at most 95 msec", timeout >= 100000 - 95000);
	}

	TEST_METHOD(69) {
		// writeExact() does not wait and does not modify the timeout variable if
		// all data can be written immediately.
		Pipe p = createNonBlockingPipe();
		unsigned long long timeout = 100000;
		char buf[1024];
		memset(buf, 0, sizeof(buf));
		writeExact(p.second, buf, sizeof(buf), &timeout);
		ensure("Timeout not modified", timeout >= 95000);
	}

	/***** Test getSocketAddressType() *****/

	TEST_METHOD(70) {
		ensure_equals(getSocketAddressType(""), SAT_UNKNOWN);
		ensure_equals(getSocketAddressType("/foo.socket"), SAT_UNKNOWN);
		ensure_equals(getSocketAddressType("unix:"), SAT_UNKNOWN);
		ensure_equals(getSocketAddressType("unix:/"), SAT_UNIX);
		ensure_equals(getSocketAddressType("unix:/foo.socket"), SAT_UNIX);
		ensure_equals(getSocketAddressType("tcp:"), SAT_UNKNOWN);
		ensure_equals(getSocketAddressType("tcp://"), SAT_UNKNOWN);
		// Doesn't check whether it contains port
		ensure_equals(getSocketAddressType("tcp://127.0.0.1"), SAT_TCP);
		ensure_equals(getSocketAddressType("tcp://127.0.0.1:80"), SAT_TCP);
	}

	TEST_METHOD(71) {
		ensure_equals(parseUnixSocketAddress("unix:/foo.socket"), "/foo.socket");
		try {
			parseUnixSocketAddress("unix:");
			fail("ArgumentException expected");
		} catch (const ArgumentException &e) {
			// Pass.
		}
	}

	TEST_METHOD(72) {
		string host;
		unsigned short port;

		parseTcpSocketAddress("tcp://127.0.0.1:80", host, port);
		ensure_equals(host, "127.0.0.1");
		ensure_equals(port, 80);

		parseTcpSocketAddress("tcp://[::1]:80", host, port);
		ensure_equals(host, "::1");
		ensure_equals(port, 80);

		try {
			parseTcpSocketAddress("tcp://", host, port);
			fail("ArgumentException expected (1)");
		} catch (const ArgumentException &e) {
			// Pass.
		}

		try {
			parseTcpSocketAddress("tcp://127.0.0.1", host, port);
			fail("ArgumentException expected (2)");
		} catch (const ArgumentException &e) {
			// Pass.
		}

		try {
			parseTcpSocketAddress("tcp://127.0.0.1:", host, port);
			fail("ArgumentException expected (3)");
		} catch (const ArgumentException &e) {
			// Pass.
		}

		try {
			parseTcpSocketAddress("tcp://[::1]", host, port);
			fail("ArgumentException expected (4)");
		} catch (const ArgumentException &e) {
			// Pass.
		}

		try {
			parseTcpSocketAddress("tcp://[::1]:", host, port);
			fail("ArgumentException expected (5)");
		} catch (const ArgumentException &e) {
			// Pass.
		}
	}

	/***** Test readFileDescriptor() and writeFileDescriptor() *****/

	TEST_METHOD(80) {
		// Test whether it works.
		SocketPair sockets = createUnixSocketPair(__FILE__, __LINE__);
		Pipe pipes = createPipe(__FILE__, __LINE__);
		writeFileDescriptor(sockets[0], pipes[1]);
		FileDescriptor fd(readFileDescriptor(sockets[1]), __FILE__, __LINE__);
		writeExact(fd, "hello");
		char buf[6];
		ensure_equals(readExact(pipes[0], buf, 5), 5u);
		buf[5] = '\0';
		ensure_equals(StaticString(buf), "hello");
	}

	TEST_METHOD(81) {
		// Test whether timeout works.
		SocketPair sockets = createUnixSocketPair(__FILE__, __LINE__);
		Pipe pipes = createPipe(__FILE__, __LINE__);

		unsigned long long timeout = 30000;
		unsigned long long startTime = SystemTime::getUsec();
		try {
			FileDescriptor fd(readFileDescriptor(sockets[0], &timeout),
				__FILE__, __LINE__);
			fail("TimeoutException expected");
		} catch (const TimeoutException &) {
			unsigned long long elapsed = SystemTime::getUsec() - startTime;
			ensure("readFileDescriptor() timed out after at least 29 msec",
				elapsed >= 29000);
			ensure("readFileDescriptor() timed out after at most 95 msec",
				elapsed <= 95000);
			ensure(timeout <= 2000);
		}

		writeUntilFull(sockets[0]);

		startTime = SystemTime::getUsec();
		timeout = 30000;
		try {
			writeFileDescriptor(sockets[0], pipes[0], &timeout);
			fail("TimeoutException expected");
		} catch (const TimeoutException &) {
			unsigned long long elapsed = SystemTime::getUsec() - startTime;
			ensure("writeFileDescriptor() timed out after 30 msec",
				elapsed >= 29000 && elapsed <= 95000);
			ensure(timeout <= 2000);
		}
	}


	/***** Test readAll() *****/

	TEST_METHOD(85) {
		set_test_name("readAll() with unlimited maxSize");
		Pipe p = createPipe(__FILE__, __LINE__);
		writeExact(p[1], "hello world");
		p[1].close();
		pair<string, bool> result = readAll(p[0],
			std::numeric_limits<size_t>::max());
		ensure_equals(result.first, "hello world");
		ensure(result.second);
	}

	TEST_METHOD(86) {
		set_test_name("readAll() with size smaller than actual data");
		Pipe p = createPipe(__FILE__, __LINE__);
		writeExact(p[1], "hello world");
		p[1].close();
		pair<string, bool> result = readAll(p[0], 5);
		ensure_equals(result.first, "hello");
		ensure(!result.second);
	}
}