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/korminas/dms.korminas.id/seeddms60x/pear/vendor/seeddms/core/tests/
Upload File :
Current File : /home/korminas/dms.korminas.id/seeddms60x/pear/vendor/seeddms/core/tests/DmsTest.php
<?php
/**
 * Implementation of the dms tests
 *
 * PHP version 7
 *
 * @category  SeedDMS
 * @package   Tests
 * @author    Uwe Steinmann <uwe@steinmann.cx>
 * @copyright 2021 Uwe Steinmann
 * @license   http://opensource.org/licenses/gpl-2.0.php GNU General Public License
 * @version   @package_version@
 * @link      https://www.seeddms.org
 */

use PHPUnit\Framework\SeedDmsTest;

/**
 * DMS test class
 *
 * @category  SeedDMS
 * @package   Tests
 * @author    Uwe Steinmann <uwe@steinmann.cx>
 * @copyright 2021 Uwe Steinmann
 * @license   http://opensource.org/licenses/gpl-2.0.php GNU General Public License
 * @version   Release: @package_version@
 * @link      https://www.seeddms.org
 */
class DmsTest extends SeedDmsTest
{

    /**
     * Create a real sqlite database in memory
     *
     * @return void
     */
    protected function setUp(): void
    {
        self::$dbh = self::createInMemoryDatabase();
        self::$contentdir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'phpunit-'.time();
        mkdir(self::$contentdir);
        //      echo "Creating temp content dir: ".self::$contentdir."\n";
        self::$dms = new SeedDMS_Core_DMS(self::$dbh, self::$contentdir);
        self::$dbversion = self::$dms->getDBVersion();
    }

    /**
     * Clean up at tear down
     *
     * @return void
     */
    protected function tearDown(): void
    {
        self::$dbh = null;
        //      echo "\nRemoving temp. content dir: ".self::$contentdir."\n";
        exec('rm -rf '.self::$contentdir);
    }

    /**
     * Create a mock admin role object (only used for SeedDMS 6)
     *
     * @return SeedDMS_Core_User
     */
    protected function getAdminRole()
    {
        $role = new SeedDMS_Core_Role(1, 'admin', SeedDMS_Core_Role::role_admin);
        return $role;
    }

    /**
     * Test checkIfEqual()
     *
     * @return void
     */
    public function testCheckIfEqual()
    {
        $user1 = new SeedDMS_Core_User(1, 'user 1', '', '', '', '', '', '', 1);
        $group1 = new SeedDMS_Core_Group(1, 'group 1', '');
        $group1n = new SeedDMS_Core_Group(1, 'group 1n', '');
        $group1c = clone $group1;
        $group2 = new SeedDMS_Core_Group(2, 'group 1', '');
        $dms = new SeedDMS_Core_DMS(null, '');
        $this->assertFalse($dms->checkIfEqual($group1, $user1)); // different classes
        $this->assertFalse($dms->checkIfEqual($group1, $group2)); // different id
        $this->assertTrue($dms->checkIfEqual($group1, $group1c)); // a clone is always equal
        $this->assertTrue($dms->checkIfEqual($group1, $group1n)); // different instances but same id is sufficient to be equal
    } /* }}} */

    /**
     * Test checkDate()
     *
     * @return void
     */
    public function testCheckDate()
    {
        $dms = new SeedDMS_Core_DMS(null, '');
        $this->assertTrue($dms->checkDate('2020-02-28 10:12:34'));
        $this->assertTrue($dms->checkDate('2020-02-29 10:12:34')); // a leap year
        $this->assertFalse($dms->checkDate('2020-02-30 10:12:34')); // feb has never 30 days
        $this->assertFalse($dms->checkDate('2021-02-29 10:12:34')); // not a leap year
        $this->assertFalse($dms->checkDate('2020-02-28 24:12:34')); // hour is out of range
        $this->assertFalse($dms->checkDate('2020-02-28 23:60:34')); // minute is out of range
        $this->assertFalse($dms->checkDate('2020-02-28 23:59:60')); // second is out of range
        $this->assertFalse($dms->checkDate('2020-02-28 23:59:')); // second is missing
        $this->assertTrue($dms->checkDate('2020-02-28', 'Y-m-d')); // just checking the date
        $this->assertFalse($dms->checkDate('28.2.2020', 'd.m.Y')); // month must be 01-12
        $this->assertTrue($dms->checkDate('28.2.2020', 'd.n.Y')); // month must be 1-12
        $this->assertFalse($dms->checkDate('28.02.2020', 'd.n.Y')); // month must be 1-12
    } /* }}} */

    /**
     * Test getClassname()
     *
     * @return void
     */
    public function testGetClassName()
    {
        /* Do not mess up the global instance self::$dms, but create my own */
        $dms = new SeedDMS_Core_DMS(null, '');
        $this->assertEquals('SeedDMS_Core_Folder', $dms->getClassname('folder'));
        $this->assertEquals('SeedDMS_Core_Document', $dms->getClassname('document'));
        $this->assertEquals('SeedDMS_Core_DocumentContent', $dms->getClassname('documentcontent'));
        $this->assertEquals('SeedDMS_Core_User', $dms->getClassname('user'));
        $this->assertEquals('SeedDMS_Core_Group', $dms->getClassname('group'));
        $this->assertFalse($dms->getClassname('foo'));
    }

    /**
     * Test setClassname()
     *
     * @return void
     */
    public function testSetClassName()
    {
        /* Do not mess up the global instance self::$dms, but create my own */
        $dms = new SeedDMS_Core_DMS(null, '');
        $this->assertEquals('SeedDMS_Core_Folder', $dms->setClassname('folder', 'MyNewFolderClass'));
        $this->assertEquals('MyNewFolderClass', $dms->getClassname('folder'));
        $this->assertEquals('MyNewFolderClass', $dms->setClassname('folder', 'MySuperNewFolderClass'));
        $this->assertFalse($dms->setClassname('foo', 'MyNewFolderClass'));
    }

    /**
     * Test addCallback()
     *
     * @return void
     */
    public function testAddCallback()
    {
        /* Do not mess up the global instance self::$dms, but create my own */
        $dms = new SeedDMS_Core_DMS(null, '');
        /* Add a closure as a callback is just fine */
        $this->assertTrue(
            $dms->addCallback(
                'onPostSomething', function () {
                }
            )
        );
        /* An empty callback will make addCallback() fail */
        $this->assertFalse(
            $dms->addCallback(
                '', function () {
                }
            )
        );
        /* Passing a class method is ok */
        $this->assertTrue($dms->addCallback('onPostSomething', [$this, 'testAddCallback']));
        /* Passing a none existing class method makes addCallback() fail */
        $this->assertFalse($dms->addCallback('onPostSomething', [$this, 'thisMethodDoesNotExist']));
    }

    /**
     * Test for hasCallback
     *
     * @return void
     */
    public function testHasCallback()
    {
        /* Do not mess up the global instance self::$dms, but create my own */
        $dms = new SeedDMS_Core_DMS(null, '');
        /* Add a closure as a callback is just fine */
        $this->assertTrue(
            $dms->addCallback(
                'onPostSomething', function () {
                }
            )
        );
        $this->assertTrue($dms->hasCallback('onPostSomething'));
        $this->assertFalse($dms->hasCallback('thisOneDoesNotExist'));
    }

    /**
     * Test for getDecorators
     *
     * @return void
     */
    public function testGetDecorators()
    {
        /* Do not mess up the global instance self::$dms, but create my own */
        $dms = new SeedDMS_Core_DMS(null, '');
        $this->assertFalse($dms->getDecorators('folder'));
    }

    /**
     * Test for addDecorator
     *
     * @return void
     */
    public function testaddDecorator()
    {
        /* Do not mess up the global instance self::$dms, but create my own */
        $dms = new SeedDMS_Core_DMS(null, '');
        $this->assertTrue($dms->addDecorator('folder', 'MyNewDecorator'));
        $decorators = $dms->getDecorators('folder');
        $this->assertIsArray($decorators);
        $this->assertCount(1, $decorators);
    }

    /**
     * Test getDb()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDb()
    {
        $this->assertEquals(self::$dbh, self::$dms->getDb());
    }

    /**
     * Test getDBVersion()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDbVersion()
    {
        $version = self::$dms->getDBVersion();
        $this->assertCount(4, $version);
        $this->assertGreaterThanOrEqual(5, $version['major']);
        $this->assertGreaterThanOrEqual(0, $version['minor']);
    }

    /**
     * Test getDBVersionFailMissingTable()
     *
     * This method checks if getDBVersion() returns false if the table
     * list of the database does not contain the table 'tblVersion'
     *
     * @return void
     */
    public function testGetDbVersionFailMissingTable()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('TableList')
            ->willReturn(['tblFolders', 'tblDocuments']);
        $dms = new SeedDMS_Core_DMS($db, '');
        $version = $dms->getDBVersion();
        $this->assertFalse($version);
    }

    /**
     * Test getDBVersionSqlFail()
     *
     * This method checks if getDBVersion() returns false if the sql
     * for selecting the records in table 'tblVersion' fail
     *
     * @return void
     */
    public function testGetDbVersionSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblVersion` ORDER BY `major`,`minor`,`subminor` LIMIT 1")
            ->willReturn(false);
        $db->expects($this->once())
            ->method('TableList')
            ->willReturn(['tblVersion', 'tblFolders', 'tblDocuments']);
        $dms = new SeedDMS_Core_DMS($db, '');
        $version = $dms->getDBVersion();
        $this->assertFalse($version);
    }

    /**
     * Test getDBVersionNoRecord()
     *
     * This method checks if getDBVersion() returns false a table 'tblVersion'
     * exists but has no record
     *
     * @return void
     */
    public function testGetDbVersionNoRecord()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblVersion` ORDER BY `major`,`minor`,`subminor` LIMIT 1")
            ->willReturn(array());
        $db->expects($this->once())
            ->method('TableList')
            ->willReturn(['tblVersion', 'tblFolders', 'tblDocuments']);
        $dms = new SeedDMS_Core_DMS($db, '');
        $version = $dms->getDBVersion();
        $this->assertFalse($version);
    }

    /**
     * Test checkVersion()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testCheckVersion()
    {
        $this->assertTrue(self::$dms->checkVersion());
    }

    /**
     * Test checkVersionFail()
     *
     * This method checks if checkVersion() returns false if the version
     * in table 'tblVersion' does not match the version in the class variable
     * $version. To make this method independant of version changes, the
     * current version is taken from SeedDMS_Core_DMS::version and modified
     * in order to differ from the version stored in the database.
     *
     * @return void
     */
    public function testcheckVersionFail()
    {
        $verstr = (new SeedDMS_Core_DMS(null, ''))->version;
        $verarr = explode('.', $verstr);
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblVersion` ORDER BY `major`,`minor`,`subminor` LIMIT 1")
            ->willReturn([['major'=>$verarr[0], 'minor'=>$verarr[1]+1]]);
        $db->expects($this->once())
            ->method('TableList')
            ->willReturn(['tblVersion', 'tblFolders', 'tblDocuments']);
        $dms = new SeedDMS_Core_DMS($db, '');
        $version = $dms->checkVersion();
        $this->assertFalse($version);
    }

    /**
     * Test checkVersionSqlFail()
     *
     * This method checks if checkVersion() returns false if the sql
     * for selecting the records in table 'tblVersion' fail
     *
     * @return void
     */
    public function testcheckVersionSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblVersion` ORDER BY `major`,`minor`,`subminor` LIMIT 1")
            ->willReturn(false);
        $db->expects($this->once())
            ->method('TableList')
            ->willReturn(['tblVersion', 'tblFolders', 'tblDocuments']);
        $dms = new SeedDMS_Core_DMS($db, '');
        $version = $dms->checkVersion();
        $this->assertFalse($version);
    }

    /**
     * Test checkVersionFailMissingTable()
     *
     * This method checks if checkVersion() returns false if the table
     * list of the database does not contain the table 'tblVersion'
     *
     * @return void
     */
    public function testCheckVersionFailMissingTable()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('TableList')
            ->willReturn(['tblFolders', 'tblDocuments']);
        $dms = new SeedDMS_Core_DMS($db, '');
        $version = $dms->checkVersion();
        $this->assertTrue($version); // A missing table tblVersion returns true!
    }

    /**
     * Test checkVersionNoRecord()
     *
     * This method checks if checkVersion() returns false a table 'tblVersion'
     * exists but has no record
     *
     * @return void
     */
    public function testCheckVersionNoRecord()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblVersion` ORDER BY `major`,`minor`,`subminor` LIMIT 1")
            ->willReturn(array());
        $db->expects($this->once())
            ->method('TableList')
            ->willReturn(['tblVersion', 'tblFolders', 'tblDocuments']);
        $dms = new SeedDMS_Core_DMS($db, '');
        $version = $dms->checkVersion();
        $this->assertFalse($version);
    }

    /**
     * Test setRootFolderID()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testSetRootFolderID()
    {
        /* Setting the same root folder is ok */
        $oldid = self::$dms->setRootFolderID(1);
        $this->assertEquals(1, $oldid);
        /* Setting a none existing root folder id will not change the root folder */
        $oldid = self::$dms->setRootFolderID(2);
        $this->assertFalse($oldid);
        /* Make sure the old root folder is still set */
        $rootfolder = self::$dms->getRootFolder();
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $rootfolder);
        $this->assertEquals(1, $rootfolder->getId());
    }

    /**
     * Test getRootFolder()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetRootFolder()
    {
        $rootfolder = self::$dms->getRootFolder();
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $rootfolder);
        $this->assertEquals(1, $rootfolder->getId());
    }

    /**
     * Test setUser()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testSetUser()
    {
        $user = self::$dms->getUser(1);
        $olduser = self::$dms->setUser($user); // returns null because there is no old user
        $this->assertNull($olduser);
        $olduser = self::$dms->setUser($user); // second call will return the user set before
        $this->assertIsObject($olduser);
        $olduser = self::$dms->setUser(null); // old user is still an object
        $this->assertIsObject($olduser);
        $olduser = self::$dms->setUser(8); // invalid user
        $this->assertFalse($olduser);
    }

    /**
     * Test getLoggedInUser()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetLoggedInUser()
    {
        $olduser = self::$dms->getLoggedInUser(); // initially this is set to null
        $this->assertNull($olduser);
        $user = self::$dms->getUser(1);
        self::$dms->setUser($user);
        $olduser = self::$dms->getLoggedInUser();
        $this->assertEquals($olduser->getId(), $user->getId());
    }

    /**
     * Test getDocument()
     *
     * As there is currently no document, getDocument() must return null.
     * If false was returned it would indicated an sql error.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocument()
    {
        $document = self::$dms->getDocument(1);
        $this->assertNull($document);
    }

    /**
     * Test getDocumentsByUser()
     *
     * As there is currently no document, getDocumentsByUser() must return
     * an empty array.
     * If false was returned it would indicated an sql error.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentsByUser()
    {
        $documents = self::$dms->getDocumentsByUser(self::$dms->getUser(1));
        $this->assertIsArray($documents);
        $this->assertCount(0, $documents);
    }

    /**
     * Test getDocumentsLockedByUser()
     *
     * As there is currently no document, getDocumentsLockedByUser() must return
     * an empty array.
     * If false was returned it would indicated an sql error.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentsLockedByUser()
    {
        $documents = self::$dms->getDocumentsLockedByUser(self::$dms->getUser(1));
        $this->assertIsArray($documents);
        $this->assertCount(0, $documents);
    }

    /**
     * Test makeTimeStamp()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testMakeTimeStamp()
    {
        /* Assert correct date */
        $this->assertEquals(0, self::$dms->makeTimeStamp(1, 0, 0, 1970, 1, 1));
        $this->assertEquals(68166000, self::$dms->makeTimeStamp(0, 0, 0, 1972, 2, 29));
        /* Assert incorrect dates */
        $this->assertFalse(self::$dms->makeTimeStamp(0, 0, 0, 1970, 13, 1), 'Incorrect month not recognized');
        $this->assertFalse(self::$dms->makeTimeStamp(0, 0, 0, 1970, 1, 32), 'Incorrect day in january not recognized');
        $this->assertFalse(self::$dms->makeTimeStamp(0, 0, 0, 1970, 4, 31), 'Incorrect day in april not recognized');
        $this->assertFalse(self::$dms->makeTimeStamp(0, 0, 0, 1970, 2, 29), 'Incorrect day in february not recognized');
        $this->assertFalse(self::$dms->makeTimeStamp(24, 0, 0, 1970, 1, 1), 'Incorrect hour not recognized');
        $this->assertFalse(self::$dms->makeTimeStamp(0, 60, 0, 1970, 1, 1), 'Incorrect minute not recognized');
        $this->assertFalse(self::$dms->makeTimeStamp(0, 0, 60, 1970, 1, 1), 'Incorrect second not recognized');
    }

    /**
     * Test search()
     *
     * Just search the root folder in different ways. Because the initial database
     * does not have any documents, this method will test various ways to
     * find the root folder 'DMS' with id=1
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testSearchRootFolder()
    {
        /* searching for folders/documents in any field */
        $result = self::$dms->search(
            array(
                'query'=>'DMS'
            )
        );
        $this->assertEquals(1, $result['totalFolders']);
        $this->assertCount(1, $result['folders']);
        $this->assertEquals(0, $result['totalDocs']);
        $this->assertCount(0, $result['docs']);

        /* searching for folders in any field */
        $result = self::$dms->search(
            array(
                'query'=>'DMS',
                'mode'=>0x2
            )
        );
        $this->assertEquals(1, $result['totalFolders']);
        $this->assertCount(1, $result['folders']);
        $this->assertEquals(0, $result['totalDocs']);
        $this->assertCount(0, $result['docs']);

        /* searching for documents in any field will not return any folders*/
        $result = self::$dms->search(
            array(
                'query'=>'DMS',
                'mode'=>0x1
            )
        );
        $this->assertEquals(0, $result['totalFolders']);
        $this->assertCount(0, $result['folders']);
        $this->assertEquals(0, $result['totalDocs']);
        $this->assertCount(0, $result['docs']);

        /* searching for folders with a bogus name may not return any folders */
        $result = self::$dms->search(
            array(
                'query'=>'foo',
                'mode'=>0x2
            )
        );
        $this->assertEquals(0, $result['totalFolders']);
        $this->assertCount(0, $result['folders']);

        /* searching for folders by its id */
        $result = self::$dms->search(
            array(
                'query'=>'1',
                'mode'=>0x2
            )
        );
        $this->assertEquals(1, $result['totalFolders']);
        $this->assertCount(1, $result['folders']);

        /* searching for folders by an unknown id */
        $result = self::$dms->search(
            array(
                'query'=>'2',
                'mode'=>0x2
            )
        );
        $this->assertEquals(0, $result['totalFolders']);
        $this->assertCount(0, $result['folders']);

        /* searching for folders with two terms ANDed, but only one matches */
        $result = self::$dms->search(
            array(
                'query'=>'DMS foo',
                'mode'=>0x2,
                'logicalmode'=>'AND',
            )
        );
        $this->assertEquals(0, $result['totalFolders']);
        $this->assertCount(0, $result['folders']);

        /* searching for folders with two terms ORed, but only one matches */
        $result = self::$dms->search(
            array(
                'query'=>'DMS foo',
                'mode'=>0x2,
                'logicalmode'=>'OR',
            )
        );
        $this->assertEquals(1, $result['totalFolders']);
        $this->assertCount(1, $result['folders']);

        /* searching for folders with two terms ANDed, both match, but in different fields (name and id) */
        $result = self::$dms->search(
            array(
                'query'=>'DMS 1',
                'mode'=>0x2,
                'logicalmode'=>'AND',
            )
        );
        $this->assertEquals(1, $result['totalFolders']);
        $this->assertCount(1, $result['folders']);

        /* searching for folders with two terms ANDed, both match, but in different fields (name and id). But only one field is searched. */
        $result = self::$dms->search(
            array(
                'query'=>'DMS 1',
                'mode'=>0x2,
                'logicalmode'=>'AND',
                'searchin'=>array(2,3), // name, comment
            )
        );
        $this->assertEquals(0, $result['totalFolders']);
        $this->assertCount(0, $result['folders']);

        /* searching for folders below a start folder will not find the folder 'DMS'
         * anymore, because the start folder itself will not be found.
         */
        $result = self::$dms->search(
            array(
                'query'=>'DMS',
                'mode'=>0x2,
                'startFolder'=>self::$dms->getRootFolder()
            )
        );
        $this->assertEquals(0, $result['totalFolders']);
        $this->assertCount(0, $result['folders']);

        /* Restrict search to the owner of the folder 'DMS'
         */
        $result = self::$dms->search(
            array(
                'query'=>'DMS',
                'mode'=>0x2,
                'owner'=>self::$dms->getUser(1)
            )
        );
        $this->assertEquals(1, $result['totalFolders']);
        $this->assertCount(1, $result['folders']);

        /* Restrict search to user who does not own a document
         */
        $result = self::$dms->search(
            array(
                'query'=>'DMS',
                'mode'=>0x2,
                'owner'=>self::$dms->getUser(2)
            )
        );
        $this->assertEquals(0, $result['totalFolders']);
        $this->assertCount(0, $result['folders']);

        /* Restrict search to a list of owners (in this case all users)
         */
        $result = self::$dms->search(
            array(
                'query'=>'DMS',
                'mode'=>0x2,
                'owner'=>self::$dms->getAllUsers()
            )
        );
        $this->assertEquals(1, $result['totalFolders']);
        $this->assertCount(1, $result['folders']);

    }

    /**
     * Test getFolder()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetFolder()
    {
        $folder = self::$dms->getFolder(1);
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $folder);
        $this->assertEquals(1, $folder->getId());
    }

    /**
     * Test getFolderByName()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetFolderByName()
    {
        $folder = self::$dms->getFolderByName('DMS');
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $folder);
        $this->assertEquals(1, $folder->getId());
        $folder = self::$dms->getFolderByName('FOO');
        $this->assertNull($folder);
    }

    /**
     * Test checkFolders()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testCheckFolders()
    {
        $errors = self::$dms->checkFolders();
        $this->assertIsArray($errors);
        $this->assertCount(0, $errors);
    }

    /**
     * Test checkFoldersSqlFail()
     *
     * This test catches the case when the sql statement for getting all
     * folders fails.
     *
     * @return void
     */
    public function testCheckFoldersSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblFolders`")
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->checkFolders());
    }

    /**
     * Test checkFoldersFailNoParent()
     *
     * This test catches the case when a folder's parent is not present
     *
     * @return void
     */
    public function testCheckFoldersFailNoParent()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblFolders`")
            ->willReturn(
                array(
                array('id'=>1, 'name'=>'DMS', 'parent'=>0, 'folderList'=>''),
                array('id'=>5, 'name'=>'Subfolder', 'parent'=>3, 'folderList'=>':1:'),
                )
            );
        $dms = new SeedDMS_Core_DMS($db, '');
        $errors = $dms->checkFolders();
        $this->assertIsArray($errors);
        $this->assertCount(1, $errors); // there should be 1 error
        $this->assertArrayHasKey(5, $errors); // folder with id=5 has the wrong parent
        $this->assertEquals('Missing parent', $errors[5]['msg']);
    }

    /**
     * Test checkFoldersFailWrongFolderList()
     *
     * This test catches the case when a folder's parent is not present
     *
     * @return void
     */
    public function testCheckFoldersFailWrongFolderList()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblFolders`")
            ->willReturn(
                array(
                array('id'=>1, 'name'=>'DMS', 'parent'=>0, 'folderList'=>''),
                array('id'=>5, 'name'=>'Subfolder', 'parent'=>1, 'folderList'=>':1:2:'),
                )
            );
        $dms = new SeedDMS_Core_DMS($db, '');
        $errors = $dms->checkFolders();
        $this->assertIsArray($errors);
        $this->assertCount(1, $errors); // there should be 1 error
        $this->assertArrayHasKey(5, $errors); // folder with id=5 has the wrong parent
        $this->assertStringContainsString('Wrong folder list', $errors[5]['msg']);
    }

    /**
    /**
     * Test checkDocuments()
     *
     * The intitial database does not have any documents which makes this
     * test less usefull.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testCheckDocuments()
    {
        $errors = self::$dms->checkDocuments();
        $this->assertIsArray($errors);
        $this->assertCount(0, $errors);
    }

    /**
     * Test checkDocumentsSqlFoldersFail()
     *
     * This test catches the case when the sql statement for getting all
     * folders fails.
     *
     * @return void
     */
    public function testCheckDocumentsSqlFoldersFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblFolders`")
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->checkDocuments());
    }

    /**
     * Test checkDocumentsSqlDocumentsFail()
     *
     * This test catches the case when the sql statement for getting all
     * documents fails, after getting all folders succeeded.
     *
     * @return void
     */
    public function testCheckDocumentsSqlDocumentsFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->exactly(2))
            ->method('getResultArray')
            ->will(
                $this->returnValueMap(
                    array(
                        array("SELECT * FROM `tblFolders`", true, array(
                            array('id'=>1, 'name'=>'DMS', 'parent'=>0, 'folderList'=>'')
                        )),
                        array("SELECT * FROM `tblDocuments`", true, false)
                    )
                )
            );
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->checkDocuments());
    }

    /**
     * Test checkDocumentsFailNoParent()
     *
     * This test catches the case when a documents's parent is not present
     *
     * @return void
     */
    public function testCheckDocumentsFailNoParent()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->exactly(2))
            ->method('getResultArray')
            ->will(
                $this->returnValueMap(
                    array(
                        array("SELECT * FROM `tblFolders`", true, array(
                            array('id'=>1, 'name'=>'DMS', 'parent'=>0, 'folderList'=>''),
                            array('id'=>5, 'name'=>'Subfolder', 'parent'=>1, 'folderList'=>':1:'),
                        )),
                        array("SELECT * FROM `tblDocuments`", true, array(
                            array('id'=>1, 'name'=>'Document 1', 'folder'=>1, 'folderList'=>':1:'),
                            array('id'=>2, 'name'=>'Document 2', 'folder'=>2, 'folderList'=>':1:5:'),
                        ))
                    )
                )
            );
        $dms = new SeedDMS_Core_DMS($db, '');
        $errors = $dms->checkDocuments();
        $this->assertIsArray($errors);
        $this->assertCount(1, $errors); // there should be 1 error
        $this->assertArrayHasKey(2, $errors); // document with id=2 has the wrong parent
        $this->assertEquals('Missing parent', $errors[2]['msg']);
    }

    /**
     * Test checkDocumentsFailWrongFolderList()
     *
     * This test catches the case when a documents's parent is not present
     *
     * @return void
     */
    public function testCheckDocumentsFailWrongFolderList()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->exactly(2))
            ->method('getResultArray')
            ->will(
                $this->returnValueMap(
                    array(
                        array("SELECT * FROM `tblFolders`", true, array(
                            array('id'=>1, 'name'=>'DMS', 'parent'=>0, 'folderList'=>''),
                            array('id'=>5, 'name'=>'Subfolder', 'parent'=>1, 'folderList'=>':1:'),
                        )),
                        array("SELECT * FROM `tblDocuments`", true, array(
                            array('id'=>1, 'name'=>'Document 1', 'folder'=>1, 'folderList'=>':1:'),
                            array('id'=>2, 'name'=>'Document 2', 'folder'=>5, 'folderList'=>':1:2:'),
                        ))
                    )
                )
            );
        $dms = new SeedDMS_Core_DMS($db, '');
        $errors = $dms->checkDocuments();
        $this->assertIsArray($errors);
        $this->assertCount(1, $errors); // there should be 1 error
        $this->assertArrayHasKey(2, $errors); // document with id=2 has the wrong parent
        $this->assertStringContainsString('Wrong folder list', $errors[2]['msg']);
    }

    /**
     * Test getUser()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetUser()
    {
        $user = self::$dms->getUser(1);
        $this->assertInstanceOf(SeedDMS_Core_User::class, $user);
        $this->assertEquals(1, $user->getId());
    }

    /**
     * Test getUserByLogin()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetUserByLogin()
    {
        $user = self::$dms->getUserByLogin('admin');
        $this->assertInstanceOf(SeedDMS_Core_User::class, $user);
        $this->assertEquals('admin', $user->getLogin());
    }

    /**
     * Test getUserByEmail()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetUserByEmail()
    {
        $user = self::$dms->getUserByEmail('info@seeddms.org');
        $this->assertInstanceOf(SeedDMS_Core_User::class, $user);
        $this->assertEquals('admin', $user->getLogin());
    }

    /**
     * Test getAllUsers()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetAllUsers()
    {
        $users = self::$dms->getAllUsers();
        $this->assertIsArray($users);
        $this->assertCount(2, $users);
    }

    /**
     * Test addUser()
     *
     * Add a new user and retrieve it afterwards. Also check if the number
     * of users has increased by one. Add a user with the same name a
     * second time and check if it returns false.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddUser()
    {
        /* Adding a new user */
        $user = self::$dms->addUser('new user', 'pwd', 'Full Name', 'newuser@seeddms.org', 'en_GB', 'bootstrap', 'with comment');
        $this->assertIsObject($user);
        $this->assertEquals('new user', $user->getLogin());
        $this->assertEquals('with comment', $user->getComment());

        /* Adding a user with the same login must fail */
        $user = self::$dms->addUser('new user', 'pwd', 'Full Name', 'newuser@seeddms.org', 'en_GB', 'bootstrap', 'with comment');
        $this->assertFalse($user);

        /* There should be 3 users now */
        $users = self::$dms->getAllUsers();
        $this->assertIsArray($users);
        $this->assertCount(3, $users);

        /* Check if setting the password expiration to 'now' works */
        $now = date('Y-m-d H:i:s');
        $user = self::$dms->addUser('new user pwdexpiration 1', 'pwd', 'Full Name', 'newuser@seeddms.org', 'en_GB', 'bootstrap', 'with comment', '', false, false, 'now');
        $this->assertEquals($now, $user->getPwdExpiration());
        $now = date('Y-m-d H:i:s');
        $user = self::$dms->addUser('new user pwdexpiration 2', 'pwd', 'Full Name', 'newuser@seeddms.org', 'en_GB', 'bootstrap', 'with comment', '', false, false, $now);
        $this->assertEquals($now, $user->getPwdExpiration());
    }

    /**
     * Test addUserWithPostAddHook()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddUserWithPostAddHook()
    {
        /* Add the 'onPostAddUser' callback */
        $ret = 0;
        $callback = function ($param, $user) use (&$ret) {
            $ret = 1; 
        };
        self::$dms->addCallback('onPostAddUser', $callback, 1);
        /* Adding a new user */
        $user = self::$dms->addUser('new user', 'pwd', 'Full Name', 'newuser@seeddms.org', 'en_GB', 'bootstrap', 'with comment');
        $this->assertIsObject($user);
        $this->assertEquals('new user', $user->getLogin());
        $this->assertEquals(1, $ret);
    }

    /**
     * Test addUser() with sql failure
     *
     * @return void
     */
    public function testAddUserSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResult')
            ->with($this->stringContains("INSERT INTO `tblUsers`"))
            ->willReturn(false);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblUsers` WHERE `login` = ")
            ->willReturn([]);
        $dms = new SeedDMS_Core_DMS($db, '');
        if(self::$dbversion['major'] < 6)
            $role = 1;
        else
            $role = $this->getAdminRole();
        $user = $dms->addUser('new user', 'pwd', 'Full Name', 'newuser@seeddms.org', 'en_GB', 'bootstrap', 'with comment', $role);
        $this->assertFalse($user);
    }

    /**
     * Test getGroup()
     *
     * Get a group by its id
     *
     * @return void
     */
    public function testGetGroup()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblGroups` WHERE `id` = 1")
            ->willReturn([['id'=>1, 'name'=>'foo', 'comment'=>'']]);
        $dms = new SeedDMS_Core_DMS($db, '');
        $group = $dms->getGroup(1);
        $this->assertIsObject($group);
        $this->assertEquals(1, $group->getId());
    }

    /**
     * Test getGroupByName()
     *
     * Get a group by its name
     *
     * qstr must be mocked because it is used in the sql statement to quote
     * the name.
     *
     * @return void
     */
    public function testGetGroupByName()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblGroups` WHERE `name` = 'foo'")
            ->willReturn([['id'=>1, 'name'=>'foo', 'comment'=>'']]);
        $db->expects($this->once())
            ->method('qstr')
            ->will(
                $this->returnCallback(
                    function ($a) {
                        return "'".$a."'";
                    }
                )
            );
        $dms = new SeedDMS_Core_DMS($db, '');
        $group = $dms->getGroupByName('foo');
        $this->assertIsObject($group);
        $this->assertEquals('foo', $group->getName());
    }

    /**
     * Test getAllGroups()
     *
     * The intitial database does not have any groups
     *
     * @return void
     */
    public function testGetAllGroups()
    {
        $groups = self::$dms->getAllGroups();
        $this->assertIsArray($groups);
        $this->assertCount(0, $groups);
    }

    /**
     * Test addGroup()
     *
     * Add a new group and retrieve it afterwards. Also check if the number
     * of groups has increased by one. Add a group with the same name a
     * second time and check if it returns false.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddGroup()
    {
        /* Adding a new group */
        $group = self::$dms->addGroup('new group', 'with comment');
        $this->assertIsObject($group);
        $this->assertEquals('new group', $group->getName());
        /* Adding a group with the same name must fail */
        $group = self::$dms->addGroup('new group', 'with comment');
        $this->assertFalse($group);
        /* There should be one group now */
        $groups = self::$dms->getAllGroups();
        $this->assertIsArray($groups);
        $this->assertCount(1, $groups);
    }

    /**
     * Test addGroupWithPostAddHook()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddGroupWithPostAddHook()
    {
        /* Add the 'onPostAddGroup' callback */
        $ret = 0;
        $callback = function ($param, $group) use (&$ret) {
            $ret = 1; 
        };
        self::$dms->addCallback('onPostAddGroup', $callback, 1);
        /* Adding a new group */
        $group = self::$dms->addGroup('new group', 'with comment');
        $this->assertIsObject($group);
        $this->assertEquals('new group', $group->getName());
        $this->assertEquals(1, $ret);
    }

    /**
     * Test addGroup() with sql failure
     *
     * @return void
     */
    public function testAddGroupSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResult')
            ->with($this->stringContains("INSERT INTO `tblGroups`"))
            ->willReturn(false);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblGroups` WHERE `name` = ")
            ->willReturn([]);
        $dms = new SeedDMS_Core_DMS($db, '');
        $group = $dms->addGroup('new group', 'with comment');
        $this->assertFalse($group);
    }

    /**
     * Test getAllKeywordCategories()
     *
     * The intitial database does not have any keyword categories
     *
     * @return void
     */
    public function testGetAllKeywordCategories()
    {
        $cats = self::$dms->getAllKeywordCategories();
        $this->assertIsArray($cats);
        $this->assertCount(0, $cats);
        /* Even passing bogus ids is handled propperly */
        $cats = self::$dms->getAllKeywordCategories(['kk', '0', 3, true]);
        $this->assertIsArray($cats);
        $this->assertCount(0, $cats);
    }

    /**
     * Test getAllUserKeywordCategories()
     *
     * Method getAllUserKeywordCategories() actually uses
     * getAllKeywordCategories()
     *
     * The intitial database does not have any keyword categories
     *
     * @return void
     */
    public function testGetAllUserKeywordCategories()
    {
        $cats = self::$dms->getAllUserKeywordCategories(1);
        $this->assertIsArray($cats);
        $this->assertCount(0, $cats);
        /* Passing a none existing user id will return an empty array */
        $cats = self::$dms->getAllUserKeywordCategories(3);
        $this->assertIsArray($cats);
        $this->assertCount(0, $cats);
        /* Passing an invalid user id will return false */
        $cats = self::$dms->getAllUserKeywordCategories(0);
        $this->assertFalse($cats);
    }

    /**
     * Test getAllKeywordCategories() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetAllKeywordCategoriesSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblKeywordCategories`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $cats = $dms->getAllKeywordCategories();
        $this->assertFalse($cats);
    }

    /**
     * Test addKeywordCategory()
     *
     * Add a new keyword category and retrieve it afterwards. Also check if the
     * number of keyword categories has increased by one. Add a keyword category
     * with the same name a second time and check if it returns false.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddKeywordCategory()
    {
        /* Adding a new keyword category */
        $cat = self::$dms->addKeywordCategory(1, 'new category');
        $this->assertIsObject($cat);
        $this->assertEquals('new category', $cat->getName());

        /* Adding a keyword category for the same user and with the same name must fail */
        $cat = self::$dms->addKeywordCategory(1, 'new category');
        $this->assertFalse($cat);

        /* Adding a keyword category with a non existing user id must fail */
        $cat = self::$dms->addKeywordCategory(0, 'new category');
        $this->assertFalse($cat);

        /* Adding a keyword category with an empty name must fail */
        $cat = self::$dms->addKeywordCategory(1, ' ');
        $this->assertFalse($cat);

        /* Adding a keyword category with a non existing user id must fail */
        //      $cat = self::$dms->addKeywordCategory(3, 'new category');
        //      $this->assertFalse($cat);

        /* There should be 1 keyword category now */
        $cats = self::$dms->getAllKeywordCategories();
        $this->assertIsArray($cats);
        $this->assertCount(1, $cats);
    }

    /**
     * Test addKeywordCategoryWithPostAddHook()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddKeywordCategoryWithPostAddHook()
    {
        /* Add the 'onPostAddKeywordCategory' callback */
        $ret = 0;
        $callback = function ($param, $cat) use (&$ret) {
            $ret = 1; 
        };
        self::$dms->addCallback('onPostAddKeywordCategory', $callback, 1);
        /* Adding a new keyword category */
        $cat = self::$dms->addKeywordCategory(1, 'new category');
        $this->assertIsObject($cat);
        $this->assertEquals('new category', $cat->getName());
        $this->assertEquals(1, $ret);
    }

    /**
     * Test addKeywordCategory() with sql failure
     *
     * @return void
     */
    public function testAddKeywordCategorySqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResult')
            ->with($this->stringContains("INSERT INTO `tblKeywordCategories`"))
            ->willReturn(false);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblKeywordCategories` WHERE `name` ="))
            ->willReturn([]);
        $dms = new SeedDMS_Core_DMS($db, '');
        $cat = $dms->addKeywordCategory(1, 'new category');
        $this->assertFalse($cat);
    }

    /**
     * Test getKeywordCategory()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetKeywordCategory()
    {
        $cat = self::$dms->addKeywordCategory(1, 'new category');
        $cat = self::$dms->getKeywordCategory(1);
        $this->assertInstanceOf(SeedDMS_Core_Keywordcategory::class, $cat);
        $this->assertEquals(1, $cat->getId());
        /* Return false if the id is invalid */
        $cat = self::$dms->getKeywordCategory(0);
        $this->assertFalse($cat);
        /* Return null if the keyword category with the id does not exist */
        $cat = self::$dms->getKeywordCategory(2);
        $this->assertNull($cat);
    }

    /**
     * Test getKeywordCategory() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetKeywordCategorySqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblKeywordCategories` WHERE `id` = 1")
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $cat = $dms->getKeywordCategory(1);
        $this->assertFalse($cat);
    }

    /**
     * Test getKeywordCategoryByName()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetKeywordCategoryByName()
    {
        $cat = self::$dms->addKeywordCategory(1, 'new category');
        $cat = self::$dms->getKeywordCategory(1);
        $this->assertInstanceOf(SeedDMS_Core_Keywordcategory::class, $cat);
        $this->assertEquals(1, $cat->getId());
        /* Return false if the user id is invalid */
        $cat = self::$dms->getKeywordCategoryByName('new category', 0);
        $this->assertFalse($cat);
        /* Return null if the keyword category with the passed name does not exist */
        $cat = self::$dms->getKeywordCategoryByName('foo', 1);
        $this->assertNull($cat);
        /* Return category if the keyword category with the passed name exists */
        $cat = self::$dms->getKeywordCategoryByName('new category', 1);
        $this->assertIsObject($cat);
        $this->assertInstanceOf(SeedDMS_Core_Keywordcategory::class, $cat);
    }

    /**
     * Test getKeywordCategoryByName() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetKeywordCategoryByNameSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblKeywordCategories` WHERE `name` ="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $cat = $dms->getKeywordCategoryByName('foo', 1);
        $this->assertFalse($cat);
    }

    /**
     * Test getDocumentCategories()
     *
     * The intitial database does not have any document categories
     *
     * @return void
     */
    public function testGetDocumentCategories()
    {
        $cats = self::$dms->getDocumentCategories();
        $this->assertIsArray($cats);
        $this->assertCount(0, $cats);
    }

    /**
     * Test getDocumentCategories() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentCategoriesNameSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblCategory`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $cats = $dms->getDocumentCategories();
        $this->assertFalse($cats);
    }

    /**
     * Test getDocumentCategory()
     *
     * The intitial database does not have any document categories
     *
     * @return void
     */
    public function testGetDocumentCategory()
    {
        /* Adding a new keyword category */
        $cat = self::$dms->addDocumentCategory('new category');
        $this->assertIsObject($cat);
        $this->assertEquals('new category', $cat->getName());

        $cat = self::$dms->getDocumentCategory($cat->getId());
        $this->assertIsObject($cat);

        /* Return false if the id is out of range */
        $cat = self::$dms->getDocumentCategory(0);
        $this->assertFalse($cat);

        /* Return null if the keyword category with the id does not exist */
        $cat = self::$dms->getDocumentCategory(2);
        $this->assertNull($cat);
    }

    /**
     * Test getDocumentCategory() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentCategorySqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with("SELECT * FROM `tblCategory` WHERE `id` = 1")
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $cat = $dms->getDocumentCategory(1);
        $this->assertFalse($cat);
    }

    /**
     * Test getDocumentCategoryByName()
     *
     * The intitial database does not have any document categories
     *
     * @return void
     */
    public function testGetDocumentCategoryByName()
    {
        /* Adding a new keyword category with leading and trailing spaces*/
        $cat = self::$dms->addDocumentCategory(' new category ');
        $this->assertIsObject($cat);
        $this->assertEquals('new category', $cat->getName());

        $cat = self::$dms->getDocumentCategoryByName($cat->getName());
        $this->assertIsObject($cat);

        $cat = self::$dms->getDocumentCategoryByName(' ');
        $this->assertFalse($cat);
    }

    /**
     * Test getDocumentCategoryByName() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentCategoryByNameSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblCategory` WHERE `name`="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $cat = $dms->getDocumentCategoryByName('foo');
        $this->assertFalse($cat);
    }

    /**
     * Test addDocumentCategory()
     *
     * Add a new keyword category and retrieve it afterwards. Also check if the
     * number of keyword categories has increased by one. Add a keyword category
     * with the same name a second time and check if it returns false.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddDocumentCategory()
    {
        /* Adding a new keyword category */
        $cat = self::$dms->addDocumentCategory('new category');
        $this->assertIsObject($cat);
        $this->assertEquals('new category', $cat->getName());

        /* Adding a document category with the same name must fail */
        $cat = self::$dms->addDocumentCategory('new category');
        $this->assertFalse($cat);

        /* Adding a document category with an empty name must fail */
        $cat = self::$dms->addDocumentCategory(' ');
        $this->assertFalse($cat);

        /* There should be 1 document category now */
        $cats = self::$dms->getDocumentCategories();
        $this->assertIsArray($cats);
        $this->assertCount(1, $cats);
    }

    /**
     * Test addDocumentCategoryWithPostAddHook()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddDocumentCategoryWithPostAddHook()
    {
        /* Add the 'onPostAddDocumentCategory' callback */
        $ret = 0;
        $callback = function ($param, $group) use (&$ret) {
            $ret = 1; 
        };
        self::$dms->addCallback('onPostAddDocumentCategory', $callback, 1);
        /* Adding a new group */
        $cat = self::$dms->addDocumentCategory('new category');
        $this->assertIsObject($cat);
        $this->assertEquals('new category', $cat->getName());
        $this->assertEquals(1, $ret);
    }

    /**
     * Test addDocumentCategory() with sql failure
     *
     * @return void
     */
    public function testAddDocumentCategorySqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResult')
            ->with($this->stringContains("INSERT INTO `tblCategory`"))
            ->willReturn(false);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblCategory` WHERE `name`="))
            ->willReturn([]);
        $dms = new SeedDMS_Core_DMS($db, '');
        $cat = $dms->addDocumentCategory('new category');
        $this->assertFalse($cat);
    }

    /**
     * Test getAttributeDefinition() with a none existing workflow
     *
     * The intitial database does not have any workflows
     *
     * @return void
     */
    public function testGetAttributeDefinitionNoExists()
    {
        $workflow = self::$dms->getAttributeDefinition(1);
        $this->assertNull($workflow);
        /* Passing an id not a numeric value returns false */
        $workflow = self::$dms->getAttributeDefinition('foo');
        $this->assertFalse($workflow);
        /* Passing an id out of range returns false */
        $workflow = self::$dms->getAttributeDefinition(0);
        $this->assertFalse($workflow);
    }

    /**
     * Test getAttributeDefinition() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetAttributeDefinitionSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblAttributeDefinitions` WHERE `id` ="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $attrdef = $dms->getAttributeDefinition(1);
        $this->assertFalse($attrdef);
    }

    /**
     * Test getAttributeDefinitionByName() with a none existing workflow
     *
     * The intitial database does not have any workflows
     *
     * @return void
     */
    public function testGetAttributeDefinitionByNameNoExists()
    {
        $workflow = self::$dms->getAttributeDefinitionByName('foo');
        $this->assertNull($workflow);
    }

    /**
     * Test getAttributeDefinitionByName() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetAttributeDefinitionByNameSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblAttributeDefinitions` WHERE `name` ="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $attrdef = $dms->getAttributeDefinitionByName('foo');
        $this->assertFalse($attrdef);
    }

    /**
     * Test getAllAttributeDefinitions()
     *
     * The intitial database does not have any attribute definitions
     *
     * @return void
     */
    public function testGetAllAttributeDefinitions()
    {
        $attrdefs = self::$dms->getAllAttributeDefinitions();
        $this->assertIsArray($attrdefs);
        $this->assertCount(0, $attrdefs);
    }

    /**
     * Test getAllAttributeDefinitions() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetAllAttributeDefinitionsSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblAttributeDefinitions`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $attrdef = $dms->getAllAttributeDefinitions();
        $this->assertFalse($attrdef);
    }

    /**
     * Test addAttributeDefinition()
     *
     * Add a new group and retrieve it afterwards. Also check if the number
     * of groups has increased by one. Add a group with the same name a
     * second time and check if it returns false.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddAttributeDefinition()
    {
        /* Adding a new attribute definition */
        $attrdef = self::$dms->addAttributeDefinition('new attribute definition', SeedDMS_Core_AttributeDefinition::objtype_folder, SeedDMS_Core_AttributeDefinition::type_int, false, 0, 0, '', '');
        $this->assertIsObject($attrdef);
        $this->assertEquals('new attribute definition', $attrdef->getName());
        /* Get the new attribute definition by its id */
        $newattrdef = self::$dms->getAttributeDefinition($attrdef->getId());
        $this->assertIsObject($newattrdef);
        $this->assertEquals($attrdef->getId(), $newattrdef->getId());
        /* Get the new attribute definition by its name */
        $newattrdef = self::$dms->getAttributeDefinitionByName('new attribute definition');
        $this->assertIsObject($newattrdef);
        $this->assertEquals($attrdef->getId(), $newattrdef->getId());
        /* Adding an attribute definition with the same name must fail */
        $attrdef = self::$dms->addAttributeDefinition('new attribute definition', SeedDMS_Core_AttributeDefinition::objtype_folder, SeedDMS_Core_AttributeDefinition::type_int, false, 0, 0, '', '');
        $this->assertFalse($attrdef);
        /* Adding an attribute definition with an empty name must fail */
        $attrdef = self::$dms->addAttributeDefinition(' ', SeedDMS_Core_AttributeDefinition::objtype_folder, SeedDMS_Core_AttributeDefinition::type_int, false, 0, 0, '', '');
        $this->assertFalse($attrdef);
        /* Adding an attribute definition with an invalid object type must fail */
        $attrdef = self::$dms->addAttributeDefinition('no object type', -1, SeedDMS_Core_AttributeDefinition::type_int, false, 0, 0, '', '');
        $this->assertFalse($attrdef);
        /* Adding an attribute definition without a type must fail */
        $attrdef = self::$dms->addAttributeDefinition('no type', SeedDMS_Core_AttributeDefinition::objtype_folder, 0, 0, '', '');
        $this->assertFalse($attrdef);
        /* There should be one attribute definition now */
        $attrdefs = self::$dms->getAllAttributeDefinitions();
        $this->assertIsArray($attrdefs);
        $this->assertCount(1, $attrdefs);
        /* There should be one attribute definition of object type folder now */
        $attrdefs = self::$dms->getAllAttributeDefinitions(SeedDMS_Core_AttributeDefinition::objtype_folder);
        $this->assertIsArray($attrdefs);
        $this->assertCount(1, $attrdefs);
        /* The object type can also be passed as an array */
        $attrdefs = self::$dms->getAllAttributeDefinitions([SeedDMS_Core_AttributeDefinition::objtype_folder]);
        $this->assertIsArray($attrdefs);
        $this->assertCount(1, $attrdefs);
        /* Adding more attribute definitions of different object type */
        $attrdef = self::$dms->addAttributeDefinition('new attribute definition all', SeedDMS_Core_AttributeDefinition::objtype_all, SeedDMS_Core_AttributeDefinition::type_int, false, 0, 0, '', '');
        $this->assertIsObject($attrdef);
        $this->assertEquals('new attribute definition all', $attrdef->getName());
        $attrdef = self::$dms->addAttributeDefinition('new attribute definition document', SeedDMS_Core_AttributeDefinition::objtype_all, SeedDMS_Core_AttributeDefinition::type_int, false, 0, 0, '', '');
        $this->assertIsObject($attrdef);
        $this->assertEquals('new attribute definition document', $attrdef->getName());
        $attrdef = self::$dms->addAttributeDefinition('new attribute definition documentcontent', SeedDMS_Core_AttributeDefinition::objtype_all, SeedDMS_Core_AttributeDefinition::type_int, false, 0, 0, '', '');
        $this->assertIsObject($attrdef);
        $this->assertEquals('new attribute definition documentcontent', $attrdef->getName());
        /* There should be four attribute definitions now */
        $attrdefs = self::$dms->getAllAttributeDefinitions();
        $this->assertIsArray($attrdefs);
        $this->assertCount(4, $attrdefs);
    }

    /**
     * Test getAllWorkflows()
     *
     * The intitial database does not have any workflows
     *
     * @return void
     */
    public function testGetAllWorkflows()
    {
        $workflows = self::$dms->getAllWorkflows();
        $this->assertIsArray($workflows);
        $this->assertCount(0, $workflows);
    }

    /**
     * Test getAllWorkflows() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetAllWorkflowsSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblWorkflows`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $workflows = $dms->getAllWorkflows();
        $this->assertFalse($workflows);
    }

    /**
     * Test getWorkflow() with a none existing workflow
     *
     * The intitial database does not have any workflows
     *
     * @return void
     */
    public function testGetWorkflowNoExists()
    {
        $workflow = self::$dms->getWorkflow(1);
        $this->assertNull($workflow);
        /* Passing an id not a numeric value returns false */
        $workflow = self::$dms->getWorkflow('foo');
        $this->assertFalse($workflow);
        /* Passing an id out of range returns false */
        $workflow = self::$dms->getWorkflow(0);
        $this->assertFalse($workflow);
    }

    /**
     * Test getWorkflow() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetWorkflowSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblWorkflows` WHERE `id`="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $workflow = $dms->getWorkflow(1);
        $this->assertFalse($workflow);
    }

    /**
     * Test getWorkflowByName() with a none existing workflow
     *
     * The intitial database does not have any workflows
     *
     * @return void
     */
    public function testGetWorkflowByNameNoExists()
    {
        $workflow = self::$dms->getWorkflowByName('foo');
        $this->assertNull($workflow);
    }

    /**
     * Test getWorkflowByName() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetWorkflowByNameSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblWorkflows` WHERE `name`="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $workflow = $dms->getWorkflowByName('foo');
        $this->assertFalse($workflow);
    }

    /**
     * Test addWorkflow()
     *
     * Add a new workflow and retrieve it afterwards. Also check if the number
     * of workflows has increased by one. Add a workflow with the same name a
     * second time and check if it returns false.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddWorkflow()
    {
        /* Adding a new workflow */
        $workflowstate = self::$dms->addWorkflowState('new workflow state', S_RELEASED);
        $workflow = self::$dms->addWorkflow('new workflow', $workflowstate);
        $this->assertIsObject($workflow);
        $this->assertEquals('new workflow', $workflow->getName());
        /* Adding a workflow with the same name must fail */
        $workflow = self::$dms->addWorkflow('new workflow', $workflowstate);
        $this->assertFalse($workflow);
        /* Adding a workflow with an empty name must fail */
        $workflow = self::$dms->addWorkflow(' ', $workflowstate);
        $this->assertFalse($workflow);
        /* There should be one workflow now */
        $workflows = self::$dms->getAllWorkflows();
        $this->assertIsArray($workflows);
        $this->assertCount(1, $workflows);
    }

    /**
     * Test getAllWorkflowStates()
     *
     * The intitial database does not have any workflow states
     *
     * @return void
     */
    public function testGetAllWorkflowStates()
    {
        $states = self::$dms->getAllWorkflowStates();
        $this->assertIsArray($states);
        $this->assertCount(0, $states);
    }

    /**
     * Test getAllWorkflowStates() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetAllWorkflowStatesSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblWorkflowStates`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $states = $dms->getAllWorkflowStates();
        $this->assertFalse($states);
    }

    /**
     * Test getWorkflowState() with a none existing workflow state
     *
     * The intitial database does not have any workflow states
     *
     * @return void
     */
    public function testGetWorkflowStateNoExists()
    {
        $workflowstate = self::$dms->getWorkflowState(1);
        $this->assertNull($workflowstate);
        /* Passing an id not a numeric value returns false */
        $workflowstate = self::$dms->getWorkflowState('foo');
        $this->assertFalse($workflowstate);
        /* Passing an id out of range returns false */
        $workflowstate = self::$dms->getWorkflowState(0);
        $this->assertFalse($workflowstate);
    }

    /**
     * Test getWorkflowState() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetWorkflowStateSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblWorkflowStates` WHERE `id` ="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $state = $dms->getWorkflowState(1);
        $this->assertFalse($state);
    }

    /**
     * Test getWorkflowStateByName() with a none existing workflow state
     *
     * The intitial database does not have any workflow states
     *
     * @return void
     */
    public function testGetWorkflowStateByNameNoExists()
    {
        $workflowstate = self::$dms->getWorkflowStateByName('foo');
        $this->assertNull($workflowstate);
    }

    /**
     * Test getWorkflowStateByName() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetWorkflowStateByNameSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblWorkflowStates` WHERE `name`="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $state = $dms->getWorkflowStateByName('foo');
        $this->assertFalse($state);
    }

    /**
     * Test addWorkflowState()
     *
     * Add a new workflow state and retrieve it afterwards. Also check if the number
     * of workflow states has increased by one. Add a workflow state with the same name a
     * second time and check if it returns false.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddWorkflowState()
    {
        /* Adding a new workflow state */
        $workflowstate = self::$dms->addWorkflowState('new workflow state', S_RELEASED);
        $this->assertIsObject($workflowstate);
        $this->assertEquals('new workflow state', $workflowstate->getName());
        /* Adding a workflow state with the same name must fail */
        $workflowstate = self::$dms->addWorkflowState('new workflow state', S_RELEASED);
        $this->assertFalse($workflowstate);
        /* Adding a workflow state with an empty name must fail */
        $workflowstate = self::$dms->addWorkflowState(' ', S_RELEASED);
        $this->assertFalse($workflowstate);
        /* There should be one workflow state now */
        $workflowstates = self::$dms->getAllWorkflowStates();
        $this->assertIsArray($workflowstates);
        $this->assertCount(1, $workflowstates);
    }

    /**
     * Test getAllWorkflowActions()
     *
     * The intitial database does not have any workflow actions
     *
     * @return void
     */
    public function testGetAllWorkflowActions()
    {
        $actions = self::$dms->getAllWorkflowActions();
        $this->assertIsArray($actions);
        $this->assertCount(0, $actions);
    }

    /**
     * Test getAllWorkflowActions() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetAllWorkflowActionsSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblWorkflowActions`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $actions = $dms->getAllWorkflowActions();
        $this->assertFalse($actions);
    }

    /**
     * Test getWorkflowAction() with a none existing workflow
     *
     * The intitial database does not have any workflow actions
     *
     * @return void
     */
    public function testGetWorkflowActionNoExists()
    {
        $workflowaction = self::$dms->getWorkflowAction(1);
        $this->assertNull($workflowaction);
        /* Passing an id not a numeric value returns false */
        $workflowaction = self::$dms->getWorkflowAction('foo');
        $this->assertFalse($workflowaction);
        /* Passing an id out of range returns false */
        $workflowaction = self::$dms->getWorkflowAction(0);
        $this->assertFalse($workflowaction);
    }

    /**
     * Test getWorkflowAction() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetWorkflowActionSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblWorkflowActions` WHERE `id` ="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $action = $dms->getWorkflowAction(1);
        $this->assertFalse($action);
    }

    /**
     * Test getWorkflowActionByName() with a none existing workflow action
     *
     * The intitial database does not have any workflow actions
     *
     * @return void
     */
    public function testGetWorkflowActionByNameNoExists()
    {
        $workflowaction = self::$dms->getWorkflowActionByName('foo');
        $this->assertNull($workflowaction);
    }

    /**
     * Test getWorkflowActionByName() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetWorkflowActionByNameSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblWorkflowActions` WHERE `name` ="))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $action = $dms->getWorkflowActionByName('foo');
        $this->assertFalse($action);
    }

    /**
     * Test addWorkflowAction()
     *
     * Add a new workflow state and retrieve it afterwards. Also check if the number
     * of workflow states has increased by one. Add a workflow state with the same name a
     * second time and check if it returns false.
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testAddWorkflowAction()
    {
        /* Adding a new workflow action */
        $workflowaction = self::$dms->addWorkflowAction('new workflow action', S_RELEASED);
        $this->assertIsObject($workflowaction);
        $this->assertEquals('new workflow action', $workflowaction->getName());
        /* Adding a workflow action with the same name must fail */
        $workflowaction = self::$dms->addWorkflowAction('new workflow action', S_RELEASED);
        $this->assertFalse($workflowaction);
        /* Adding a workflow action with an empty name must fail */
        $workflowaction = self::$dms->addWorkflowAction(' ', S_RELEASED);
        $this->assertFalse($workflowaction);
        /* There should be one workflow action now */
        $workflowactions = self::$dms->getAllWorkflowActions();
        $this->assertIsArray($workflowactions);
        $this->assertCount(1, $workflowactions);
    }

    /**
     * Test getStatisticalData()
     *
     * @return void
     */
    public function testGetStatisticalData()
    {
        /* There should one folder (root folder) */
        $data = self::$dms->getStatisticalData('foldersperuser');
        $this->assertIsArray($data);
        $this->assertEquals(1, $data[0]['total']);
        /* There should be no documents */
        foreach (array('docsperuser', 'docspermimetype', 'docspercategory', 'docspermonth', 'docsperstatus', 'docsaccumulated', 'sizeperuser') as $type) {
            $data = self::$dms->getStatisticalData($type);
            $this->assertIsArray($data);
            $this->assertCount(0, $data);
        }
        /* Passing an unknown name returns an empty array */
        $data = self::$dms->getStatisticalData('foo');
        $this->assertIsArray($data);
        $this->assertCount(0, $data);
    }

    /**
     * Test getStatisticalDataFail()
     *
     * Check if getStatisticalData() fails if the sql statements fail
     *
     * @return void
     */
    public function testGetStatisticalDataFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->any())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT "))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        foreach (array('foldersperuser', 'docsperuser', 'docspermimetype', 'docspercategory', 'docspermonth', 'docsperstatus', 'docsaccumulated', 'sizeperuser') as $type) {
            $data = $dms->getStatisticalData($type);
            $this->assertFalse($data);
        }
    }

    /**
     * Test createPasswordRequest() and checkPasswordRequest()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testCreateAndCheckAndDeletePasswordRequest()
    {
        $user = self::$dms->getUser(1);
        $hash = self::$dms->createPasswordRequest($user);
        $this->assertIsString($hash);
        $user = self::$dms->checkPasswordRequest($hash);
        $this->assertIsObject($user);
        $this->assertEquals(1, $user->getId());
        /* Check a non existing hash */
        $user = self::$dms->checkPasswordRequest('foo');
        $this->assertFalse($user);
        /* Delete the hash */
        $ret = self::$dms->deletePasswordRequest($hash);
        $this->assertTrue($ret);
        /* Checking the hash again must return false, because it was deleted */
        $user = self::$dms->checkPasswordRequest($hash);
        $this->assertFalse($user);
    }

    /**
     * Test method checkPasswordRequest() with sql failure
     *
     * @return void
     */
    public function testCheckPasswordRequestSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblUserPasswordRequest`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->checkPasswordRequest('foo'));
    }

    /**
     * Test method deletePasswordRequest() with sql failure
     *
     * @return void
     */
    public function testDeletePasswordRequestSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResult')
            ->with($this->stringContains("DELETE FROM `tblUserPasswordRequest`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->deletePasswordRequest('foo'));
    }

    /**
     * Test getTimeline()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetTimeline()
    {
        $timeline = self::$dms->getTimeline();
        $this->assertIsArray($timeline);
    }

    /**
     * Test getUnlinkedDocumentContent()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetUnlinkedDocumentContent()
    {
        $contents = self::$dms->getUnlinkedDocumentContent();
        $this->assertIsArray($contents);
        $this->assertCount(0, $contents);
    }

    /**
     * Test getNoFileSizeDocumentContent()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetNoFileSizeDocumentContent()
    {
        $rootfolder = self::$dms->getRootFolder();
        $user = self::$dms->getUser(1);
        $document = self::createDocument($rootfolder, $user, 'Document 1');
        $contents = self::$dms->getNoFileSizeDocumentContent();
        $this->assertIsArray($contents);
        $this->assertCount(0, $contents);
        /* Manipulate the file size right in the database */
        $dbh = self::$dms->getDB();
        $ret = $dbh->getResult("UPDATE `tblDocumentContent` SET `fileSize` = 0");
        $this->assertTrue($ret);
        $contents = self::$dms->getNoFileSizeDocumentContent();
        $this->assertIsArray($contents);
        $this->assertCount(1, $contents);
    }

    /**
     * Test getNoFileSizeDocumentContent()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetNoFileSizeDocumentContentSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblDocumentContent` WHERE `fileSize`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->getNoFileSizeDocumentContent());
    }

    /**
     * Test getNoChecksumDocumentContent()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetNoChecksumDocumentContent()
    {
        $rootfolder = self::$dms->getRootFolder();
        $user = self::$dms->getUser(1);
        $document = self::createDocument($rootfolder, $user, 'Document 1');
        $contents = self::$dms->getNoChecksumDocumentContent();
        $this->assertIsArray($contents);
        $this->assertCount(0, $contents);
        /* Manipulate the checksum right in the database */
        $dbh = self::$dms->getDB();
        $ret = $dbh->getResult("UPDATE `tblDocumentContent` SET `checksum` = null");
        $this->assertTrue($ret);
        $contents = self::$dms->getNoChecksumDocumentContent();
        $this->assertIsArray($contents);
        $this->assertCount(1, $contents);
    }

    /**
     * Test getNoChecksumDocumentContent()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetNoChecksumDocumentContentSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT * FROM `tblDocumentContent` WHERE `checksum`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->getNoChecksumDocumentContent());
    }

    /**
     * Test getDuplicateDocumentContent()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDuplicateDocumentContent()
    {
        $contents = self::$dms->getDuplicateDocumentContent();
        $this->assertIsArray($contents);
        $this->assertCount(0, $contents);
    }

    /**
     * Test getDuplicateDocumentContent()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDuplicateDocumentContentWithDuplicates()
    {
        $rootfolder = self::$dms->getRootFolder();
        $user = self::$dms->getUser(1);
        $document1 = self::createDocument($rootfolder, $user, 'Document 1');

        $filename = self::createTempFile(200);
        list($document2, $res) = $rootfolder->addDocument(
            'Documet 2', // name
            '', // comment
            null, // no expiration
            $user, // owner
            '', // keywords
            [], // categories
            $filename, // name of file
            'file1.txt', // original file name
            '.txt', // file type
            'text/plain', // mime type
            1.0 // sequence
        );
        list($document3, $res) = $rootfolder->addDocument(
            'Documet 3', // name
            '', // comment
            null, // no expiration
            $user, // owner
            '', // keywords
            [], // categories
            $filename, // name of file
            'file1.txt', // original file name
            '.txt', // file type
            'text/plain', // mime type
            1.0 // sequence
        );
        $this->assertTrue(SeedDMS_Core_File::removeFile($filename));

        $contents = self::$dms->getDuplicateDocumentContent();
        $this->assertIsArray($contents);
        $this->assertCount(1, $contents);
    }

    /**
     * Test method getDuplicateDocumentContent() with sql failure
     *
     * @return void
     */
    public function testGetDuplicateDocumentContentSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT a.*, b.`id` as dupid FROM `tblDocumentContent`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->getDuplicateDocumentContent());
    }

    /**
     * Test getNotificationsByUser()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetNotificationsByUser()
    {
        $user = self::$dms->getUser(1);
        $notifications = self::$dms->getNotificationsByUser($user, 0);
        $this->assertIsArray($notifications);
        $this->assertCount(0, $notifications);
        $notifications = self::$dms->getNotificationsByUser($user, 1);
        $this->assertIsArray($notifications);
        $this->assertCount(0, $notifications);
    }

    /**
     * Test getNotificationsByGroup()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetNotificationsByGroup()
    {
        $group = self::$dms->addGroup('new group', 'with comment');
        $this->assertIsObject($group);
        $notifications = self::$dms->getNotificationsByGroup($group, 0);
        $this->assertIsArray($notifications);
        $this->assertCount(0, $notifications);
        $notifications = self::$dms->getNotificationsByGroup($group, 1);
        $this->assertIsArray($notifications);
        $this->assertCount(0, $notifications);
    }

    /**
     * Test getDocumentsExpired()
     *
     * Check if getDocumentsExpired() fails if the parameters are wrong
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentsExpiredFail()
    {
        $documents = self::$dms->getDocumentsExpired(false);
        $this->assertFalse($documents);
        $documents = self::$dms->getDocumentsExpired('2021-04');
        $this->assertFalse($documents);
        $documents = self::$dms->getDocumentsExpired('2021-01-32');
        $this->assertFalse($documents);
        $documents = self::$dms->getDocumentsExpired('2021-01-31'); // valid date
        $this->assertIsArray($documents);
    }

    /**
     * Test method getDocumentsExpired() with sql failure
     *
     * @return void
     */
    public function testGetDocumentsExpiredSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('createTemporaryTable')
            ->with('ttstatid')
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->getDocumentsExpired(1));
    }

    /**
     * Test getDocumentByName()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentByName()
    {
        $rootfolder = self::$dms->getRootFolder();
        $user = self::$dms->getUser(1);
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $rootfolder);
        $subfolder = $rootfolder->addSubFolder('Subfolder 1', '', $user, 2.0);
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $subfolder);

        /* Add a new document */
        $filename = self::createTempFile(200);
        list($document, $res) = $subfolder->addDocument(
            'Document 1', // name
            '', // comment
            null, // no expiration
            $user, // owner
            '', // keywords
            [], // categories
            $filename, // name of file
            'file1.txt', // original file name
            '.txt', // file type
            'text/plain', // mime type
            1.0 // sequence
        );
        $this->assertIsObject($document);
        $this->assertTrue(SeedDMS_Core_File::removeFile($filename));
        /* Search without a parent folder restriction */
        $document = self::$dms->getDocumentByName('Document 1');
        $this->assertInstanceOf(SeedDMS_Core_Document::class, $document);
        /* Searching in the root folder will return no document */
        $document = self::$dms->getDocumentByName('Document 1', $rootfolder);
        $this->assertNull($document);
        /* Searching in the sub folder will return the document */
        $document = self::$dms->getDocumentByName('Document 1', $subfolder);
        $this->assertInstanceOf(SeedDMS_Core_Document::class, $document);
        /* Searching for an empty name returns false */
        $document = self::$dms->getDocumentByName('  ');
        $this->assertFalse($document);
    }

    /**
     * Test getDocumentByName() with sql failure
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentByNameSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('getResultArray')
            ->with($this->stringContains("SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lockUser`"))
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $document = $dms->getDocumentByName('foo');
        $this->assertFalse($document);
    }

    /**
     * Test getDocumentByOriginalFilename()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentByOriginalFilename()
    {
        $rootfolder = self::$dms->getRootFolder();
        $user = self::$dms->getUser(1);
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $rootfolder);
        $subfolder = $rootfolder->addSubFolder('Subfolder 1', '', $user, 2.0);
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $subfolder);

        /* Add a new document */
        $filename = self::createTempFile(200);
        list($document, $res) = $subfolder->addDocument(
            'Document 1', // name
            '', // comment
            null, // no expiration
            $user, // owner
            '', // keywords
            [], // categories
            $filename, // name of file
            'file1.txt', // original file name
            '.txt', // file type
            'text/plain', // mime type
            1.0 // sequence
        );
        $this->assertIsObject($document);
        $this->assertTrue(SeedDMS_Core_File::removeFile($filename));
        /* Search without a parent folder restriction */
        $document = self::$dms->getDocumentByOriginalFilename('file1.txt');
        $this->assertInstanceOf(SeedDMS_Core_Document::class, $document);
        /* Searching in the root folder will return no document */
        $document = self::$dms->getDocumentByOriginalFilename('file1.txt', $rootfolder);
        $this->assertNull($document);
        /* Searching in the sub folder will return the document */
        $document = self::$dms->getDocumentByOriginalFilename('file1.txt', $subfolder);
        $this->assertInstanceOf(SeedDMS_Core_Document::class, $document);
        /* Searching for an empty name returns false */
        $document = self::$dms->getDocumentByOriginalFilename('  ');
        $this->assertFalse($document);
    }

    /**
     * Test method getDocumentByOriginalFilename() with sql failure
     *
     * @return void
     */
    public function testGetDocumentByOriginalFilenameSqlFail()
    {
        $db = $this->createMock(SeedDMS_Core_DatabaseAccess::class);
        $db->expects($this->once())
            ->method('createTemporaryTable')
            ->with('ttcontentid')
            ->willReturn(false);
        $dms = new SeedDMS_Core_DMS($db, '');
        $this->assertFalse($dms->getDocumentByOriginalFilename(1));
    }

    /**
     * Test getDocumentList()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testGetDocumentList()
    {
        $rootfolder = self::$dms->getRootFolder();
        $user = self::$dms->getUser(1);
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $rootfolder);

        /* Add a new document */
        $filename = self::createTempFile(200);
        list($document, $res) = $rootfolder->addDocument(
            'Document 1', // name
            '', // comment
            null, // no expiration
            $user, // owner
            '', // keywords
            [], // categories
            $filename, // name of file
            'file1.txt', // original file name
            '.txt', // file type
            'text/plain', // mime type
            1.0 // sequence
        );
        $this->assertTrue(SeedDMS_Core_File::removeFile($filename));
        $this->assertIsObject($document);

        /* Add a second new document */
        $filename = self::createTempFile(200);
        list($document, $res) = $rootfolder->addDocument(
            'Document 2', // name
            '', // comment
            mktime(0, 0, 0), // expires today
            $user, // owner
            '', // keywords
            [], // categories
            $filename, // name of file
            'file2.txt', // original file name
            '.txt', // file type
            'text/plain', // mime type
            1.0 // sequence
        );
        $this->assertTrue(SeedDMS_Core_File::removeFile($filename));
        $this->assertIsObject($document);

        $documents = self::$dms->getDocumentList('MyDocs', $user);
        $this->assertIsArray($documents);
        $this->assertCount(2, $documents);
        /* All documents expiring from 1 year ago till today */
        $documents = self::$dms->getDocumentList('ExpiredOwner', $user);
        $this->assertIsArray($documents);
        $this->assertCount(1, $documents);
        /* All documents expiring today */
        $documents = self::$dms->getDocumentList('ExpiredOwner', $user, 0);
        $this->assertIsArray($documents);
        $this->assertCount(1, $documents);
        /* All documents expiring tomorrow */
        $documents = self::$dms->getDocumentList('ExpiredOwner', $user, date("Y-m-d", time()+86400));
        $this->assertIsArray($documents);
        $this->assertCount(1, $documents);
        /* Get unknown list */
        $documents = self::$dms->getDocumentList('foo', $user);
        $this->assertFalse($documents);
    }

    /**
     * Test search()
     *
     * This method uses a real in memory sqlite3 database.
     *
     * @return void
     */
    public function testSearch()
    {
        $rootfolder = self::$dms->getRootFolder();
        $user = self::$dms->getUser(1);
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $rootfolder);
        $subfolder = $rootfolder->addSubFolder('Subfolder 1', '', $user, 2.0);
        $this->assertInstanceOf(SeedDMS_Core_Folder::class, $subfolder);

        /* Add a new document to the subfolder*/
        $filename = self::createTempFile(200);
        list($document, $res) = $subfolder->addDocument(
            'Document 1', // name
            '', // comment
            null, // no expiration
            $user, // owner
            '', // keywords
            [], // categories
            $filename, // name of file
            'file1.txt', // original file name
            '.txt', // file type
            'text/plain', // mime type
            1.0 // sequence
        );
        $this->assertTrue(SeedDMS_Core_File::removeFile($filename));
        /* Add a new document to the root folder. All documents expire. The first
         * expires today, the second expires tomorrow, etc.
         */
        for ($i=2; $i<=30; $i++) {
            $filename = self::createTempFile(200);
            list($document, $res) = $rootfolder->addDocument(
                'Document '.$i, // name
                '', // comment
                mktime(0, 0, 0)+($i-2)*86400, // expires in $i-2 days
                $user, // owner
                '', // keywords
                [], // categories
                $filename, // name of file
                'file'.$i.'.txt', // original file name
                '.txt', // file type
                'text/plain', // mime type
                1.0+$i // sequence
            );
            $this->assertTrue(SeedDMS_Core_File::removeFile($filename));
        }
        $hits = self::$dms->search(['query'=>'Document']);
        $this->assertIsArray($hits);
        $this->assertCount(5, $hits);
        $this->assertEquals(30, $hits['totalDocs']);
        $this->assertCount(30, $hits['docs']);
        /* Limit number of documents to 10 */
        $hits = self::$dms->search(['query'=>'Document', 'limit'=>10]);
        $this->assertIsArray($hits);
        $this->assertCount(5, $hits);
        $this->assertEquals(30, $hits['totalDocs']);
        $this->assertCount(10, $hits['docs']);
        /* Same number of documents if startFolder is the root folder */
        $hits = self::$dms->search(['query'=>'Document', 'startFolder'=>$rootfolder]);
        $this->assertIsArray($hits);
        $this->assertCount(5, $hits);
        $this->assertEquals(30, $hits['totalDocs']);
        $this->assertCount(30, $hits['docs']);
        /* There is just one document below the sub folder */
        $hits = self::$dms->search(['query'=>'Document', 'startFolder'=>$subfolder]);
        $this->assertIsArray($hits);
        $this->assertCount(5, $hits);
        $this->assertEquals(1, $hits['totalDocs']);
        /* Get documents with a given expiration date in the future
         * All documents in subfolder, but not the one in the root folder
         */
        $expts = mktime(0, 0, 0);
        $expstart = [
            'year'=>date('Y', $expts),
            'month'=>date('m', $expts),
            'day'=>date('d', $expts),
            'hour'=>date('H', $expts),
            'minute'=>date('i', $expts),
            'second'=>date('s', $expts)
        ];
        $hits = self::$dms->search(['query'=>'Document', 'expirationstartdate'=>$expstart]);
        $this->assertIsArray($hits);
        $this->assertCount(5, $hits);
        $this->assertEquals(29, $hits['totalDocs']);
        /* Get documents with a given expiration date in the future, starting tomorrow
         * All documents in subfolder - 1
         */
        $expts = mktime(0, 0, 0)+86400;
        $expstart = [
            'year'=>date('Y', $expts),
            'month'=>date('m', $expts),
            'day'=>date('d', $expts),
            'hour'=>date('H', $expts),
            'minute'=>date('i', $expts),
            'second'=>date('s', $expts)
        ];
        $hits = self::$dms->search(['query'=>'Document', 'expirationstartdate'=>$expstart]);
        $this->assertIsArray($hits);
        $this->assertCount(5, $hits);
        $this->assertEquals(28, $hits['totalDocs']);
        /* Get documents expire today or tomorrow
         * 2 documents in subfolder 
         */
        $expts = mktime(0, 0, 0);
        $expstart = [
            'year'=>date('Y', $expts),
            'month'=>date('m', $expts),
            'day'=>date('d', $expts),
            'hour'=>date('H', $expts),
            'minute'=>date('i', $expts),
            'second'=>date('s', $expts)
        ];
        $expts += 1*86400;
        $expstop = [
            'year'=>date('Y', $expts),
            'month'=>date('m', $expts),
            'day'=>date('d', $expts),
            'hour'=>date('H', $expts),
            'minute'=>date('i', $expts),
            'second'=>date('s', $expts)
        ];
        $hits = self::$dms->search(['query'=>'Document', 'expirationstartdate'=>$expstart, 'expirationenddate'=>$expstop]);
        $this->assertIsArray($hits);
        $this->assertCount(5, $hits);
        $this->assertEquals(2, $hits['totalDocs']);
        /* Get documents expire before and tomorrow
         * 2 documents in subfolder 
         */
        $expts = mktime(0, 0, 0); // Start of today
        $expts += 1*86400; // Start of tomorrow
        $expstop = [
            'year'=>date('Y', $expts),
            'month'=>date('m', $expts),
            'day'=>date('d', $expts),
            'hour'=>date('H', $expts),
            'minute'=>date('i', $expts),
            'second'=>date('s', $expts)
        ];
        $hits = self::$dms->search(['query'=>'Document', 'expirationenddate'=>$expstop]);
        $this->assertIsArray($hits);
        $this->assertCount(5, $hits);
        $this->assertEquals(2, $hits['totalDocs']);
    }

}