From d5522c6fb3c7affc827cf2b509dadab833a237a4 Mon Sep 17 00:00:00 2001 From: Wendell Jones Date: Sun, 22 Feb 2026 09:38:16 -0500 Subject: [PATCH] Improve code clarity and test documentation Refactored ImageProcessor to use explicit 'this.' member access for consistency and readability. Enhanced test files with XML documentation, explicit types, modern C# syntax, and clearer Moq setups. Enabled XML doc generation for test project. Updated assembly info and cache files as a result of build changes. No functional or behavioral changes. --- .../netstandard2.0/Jellyfin.CodeAnalysis.dll | Bin 8704 -> 8704 bytes .../netstandard2.0/Jellyfin.CodeAnalysis.pdb | Bin 10192 -> 10220 bytes .../Jellyfin.CodeAnalysis.AssemblyInfo.cs | 3 +- ...yfin.CodeAnalysis.AssemblyInfoInputs.cache | 2 +- ...odeAnalysis.csproj.AssemblyReference.cache | Bin 63428 -> 79822 bytes .../netstandard2.0/Jellyfin.CodeAnalysis.dll | Bin 8704 -> 8704 bytes .../netstandard2.0/Jellyfin.CodeAnalysis.pdb | Bin 10192 -> 10220 bytes src/Jellyfin.Drawing/ImageProcessor.cs | 74 +++--- .../BaseItemManagerTests.cs | 51 ++-- .../DirectoryServiceTests.cs | 220 ++++++++++-------- .../Entities/BaseItemTests.cs | 90 ++++--- .../Jellyfin.Controller.Tests.csproj | 1 + 12 files changed, 252 insertions(+), 189 deletions(-) diff --git a/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll b/src/Jellyfin.CodeAnalysis/bin/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll index a40ec0229eedc7dd8863edb86859bbf741dd9799..5f6f2076e72fe2cf0530b46beb8b6a0029b56986 100644 GIT binary patch delta 232 zcmZp0X>gg)!J_@K;Mm5V7*PQ+9^O`u-1%+|>07?t`OlrP`G@EpCUp}FQ!`5wBlASl z*0QKh|8`(+VhXf7R zCDnd460RqpRq84`iKWQHUlZO&i}WE%qIO&C%c41g?iAO@*V0gg)!E#1-b^FGi7*T;3vn8)MH8(hHNKT2AVc%`A`G@EpCiPSc3v**rGh+)= zv&0k&L*wKmlO%I9OVcES#Kc4k(_~{Kb0f<{lgYOw*0NMyuU$2{M>0U*lEbRZsiI50 zRtFb)x2!G6p8Q6#SOF^dN*gK&Qk^Qy`grl&<|$LcEkZWeOWkDgO=YkELURUV22%zz zAZY=n6B$x~EJGkanIVb61c=RnvX(%(BnAV9L@)%YOa`hj0?HWyb^!PwY>Sa3Itq001LGY;R%!004$KQ`taZC`F`uPJ9?e$h9Sx_P~*lt|1X4 z0RY=00RZ+R0RX8a000000RY4#00000000000RYUCUjfrA#Um#G1OR9QCjbQir3F?1 z0|55`b^rqa?g0P+1^|U5AOQvdyCfh12LQgaT>^;$e;a$JgR+CLGw7E&9aHT7|MB@9 zbrCeJTo;W1B=qXyj;tL! zc53Te+Bmdh;d*Y>C_*Oxn)Z)H+%r8RGG)|n2)aWVc2^?`w!lm zdbL=t>sf;fqp_JUs#Q&8)l~ILH>Rn&<#I7=*4i9j_H*!UGIF}EKC)Ok9q#{~-M{A# z9fyA~zx+=R?-JVF-Dd5{Q|RN245f)qZk3B9|5C00i#F(qhA4| LeF3AQlh!8r|48|w delta 545 zcmV++0^a@XPtZ@0a3HuO001LGY;R%!007cJs%e!KrAn()aZ7})bZdFneX5a=t|9ay z0RX-u0RY(}0RW67000000RX2Y00000000000RXR)UjfrAs3Ru;1OQ6|CjbQihy_*v z0|55`b^rqa?g0P+1^{RzAOQvdo+Kav2LPe7T>^;$e`r==Ymjpenm7`9mRO%vk4m;_ z7I@`VjjsEh7YAw9Oo3Ys1ONc7lTAwlF%X9Dh5m=3Cq=qzZMR)N5Nf5OAc%?{#KR;z zyB)|TlFVB6-%F|#iy!pR$tja}o_81~Y1-dubUSGZXV{4AS7gbfP;tIW#&}$C0PPBb zB?edve?YZ>AkLX2O4st)0&PVB#DT=hk_|zPEof{40bA|7CoQ08f$!`*peQ7IyYDN?$Mps+DO^ zehQN5*W1k1Z)n@8h-cLZ?e%WRn6_k_%v?cJe~YFK9D4h&TLW#$RpT*czhN&)HP!Z* zIU9N+A2uO_ZI0i$36qlJ_6CiwvXn-=XQ diff --git a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfo.cs b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfo.cs index 06971691..e7bcaae5 100644 --- a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfo.cs +++ b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfo.cs @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -13,7 +14,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("Jellyfin.CodeAnalysis")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+e8873563856ad813cb4b7695b0aaa85c32729a4c")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+48569427a5cba735184e017148b7c71f665279bc")] [assembly: System.Reflection.AssemblyProductAttribute("Jellyfin.CodeAnalysis")] [assembly: System.Reflection.AssemblyTitleAttribute("Jellyfin.CodeAnalysis")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfoInputs.cache b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfoInputs.cache index 802bf3a3..fea0801d 100644 --- a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfoInputs.cache +++ b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.AssemblyInfoInputs.cache @@ -1 +1 @@ -4aa28b28b5f36d3ba59b76bc7e3a9a39544dcee89f6b8e3632f4df17d7b042d4 +5afb18d45c1a1f35abd23adbc2ff716c2f51ec4673ea08b8765ec2e818a59a28 diff --git a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.csproj.AssemblyReference.cache b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.csproj.AssemblyReference.cache index 4c5b9dad125aa15daf88e64fe764ad598803c2cc..1fd0093cd50c1774e41b9fd1e906e0d9df4ad3e1 100644 GIT binary patch literal 79822 zcmds=50n(enZRch1VKRrBT+#xhJ=VSJM1p7ATgT-h46oO0WnLkXQpSF-I?y$o}OJ6 zjS$8EiTIYFCyCF^Gm2+U%q3@%Gcl)6;){ogPmR9ANMbZbqF#(I@tKfAud1f2ySk^k zyLQu6*~OCuj|)eecxAKRh<;SAr_0p(=7`-)|XYI+|k#iYihY8p;bCnv!kSB zx|L4wXH7NBrlMsPBbzAX(}rU7cg#)HCF(oUm3$#f{v7;uhoR=kze;2ag?JqNL$Nnf z>&D#o!q|8`KA!l<_zCc5#20D{{v6){ei^kBd;@-ucjfX0bzw4@Y+0B@(k83YCacmW zv9w9zqp`F}ByAE&Oa2`EbrMKR{uPpT5d4F&^Q-^(SHZU@K@q{9Ticpbu~AT z2M=v)|60Q%-#cs3)Yz+wK6v=MZ#TuvQD@BC|JtF$JGP8^X5w`{>+c`9^?})M9iQ~f z4Wk<6 z{FOtm|0z@V)Zn?z*RH?&?03$8diI%59-jQ#z0LItr;R@R;yoNNS(VQidRfnziH&)!er{r|kuT=W ze6L!jQFE4m^Een4^mU^3J7NZW?}n(KBSikfF*7yh*<%|I9yt8RdlI`In0Vm$slPvZ zyzA}VH~j6y-omvj?;M!^okef#JN&}Sk006h+`P#%Pq=NoanWCQ?%i?lH+`q=esWCT zn%PI^P8fJ|^xMBZI`gr6-#PkjwqxZfdmjJRouAyCp7Ve@XWFqB7n_^)3txZt>MuMr z@!;)?XPtBN=`HHi8O6u;G_1P(xjl%fZ(qD+$D|j=EsSsW*T_K(0m6b+RH`{-jl4-U4r_*coWhARdELl+YL5Mo=o<{AA#r(Xfku~#e zsC~S=7!qW&R_ofOs-_zGj5GZ?IMHmD)59h!*tZgFvmE&(wOLoxLY8opa`RRnmC34z zFO>bt;JzrQJi~uJNRh}Gb zWxb%%kegsDjGEZ9Y;eZ5D8jrsG7m!cQmW*~I`?BGk*SL=SIaSXwnQ-%kfbdZb&ZA% z&Ycm>7!8wv+!-O1q-JQng%6<#iBN>IUzwlPS&~;eHN9-+Gbr5;)=V=du_Wm@UFTqJ zX&r2f6dYz=$=@RR>m#3i+7k50Nz_29KdQ8uE(WzFYP!-%vsqIqI-|xmV!@$hpIF2k zJ>Quv@ zzZ=5HR?d0U_E3~rYv>uZOr1#2@^8-Qo$;*g@fS`~)HeHTL?RZUx5jayle7eFCa79$ z2mTs0WW)=d^d7cx!^LFuWdQ*TopkvmWeqQM(v>1{t4n}#vS@07z7!WTt+s=TvW-R_ zWW^A4EAyb*46L)$rq@qV-Z`J{Hi^O0>`j8FSs!U7<+8{=9&Sh@n|1|-745oSpia89 zumUx<`3sI*1&0-m9`c11pQphF$Hk3SWKjjjLJ!i8Bcs=*R}A`miwiw`y4aWnn>hi6 z9zFs}YT0n1hmTfnzif~b?$Pur8O(}xv z+t!L^=8M$e^dp!pcT*dz;1q8~09bCpB&F(d`eSw@72PHQj*i%+1w9RmY!$dKCDEc3 zRJccz>gi)g%%_XZSa6BA07uM6KuKA{j+l>DZssB@^6utm#@vcfcBV|R-Y!=|8?Rs! zR_1TQTw+NI6)v}R>EcEyI`h>lilwF7K;jJUTBh2sb7@#5oIW;T!3OMV(S$h?N(x&# zAZ?jtw7ec;%)zwi@ovp zmw=UR+A!k99(oT(iy>gKhb|xEu;RrP`iGFi3l4H%T3lfm-YfV`3P2Ca8+o#2g_f_e z-@@RO;a2{J-jZ|>@-J0^=Surwl6XXzrQzs*f`<-YcS{2bDcJvXHDr9(1^AyXu@LF< z@w3t9hZqYIC00wra3ToD=-E9KOAK)8j9+0Cj-GwG*mwooBmvR0kARYbhNEX6t=z~( zwv53s;&CeyoN2}pk6#}fx?p!yK*ZxGp`_H|h{sPYH+F136@#VYSk3O%WTRqcw$dw9 za5X!%gAH7;l@n0SP8Cm5+Hf^HRVO!Uky$v7t7t%tWkfG z8mdyHO@V}aPwiu4H4@x=s)UkSD#E>|s^!KmGWVXxA{2bvFUjD}O zkYz#|NzqwNs6b*8Vd_-lH>n{^mTtofUsS*8OhQAjx@xy&#HW}4BuCXkzR3<3A$ir| zgcZk(JknsT0!|e#(2rol8F^PjdwN5WAy`3yzoY+MhrSEQ$h*Xn)G*lyzpj5umoUZHwMh7C9LNz?#m!Mv4l{PGPIsB_HETsAQ6htvF2Dl42NN(nqH?lI=6QRG((Rp%YCytGvk%XNm zY6sga1^em(oF}SylJbR}C#p^)YI6ALgc`v)bP8%thY^XIBi=s`YK~5vP~%wC35yiq z;j3kkU5AMXnnA-wo!+)KV8MZ)fTB*XWRkLli#omPxUq^X{Ns4>B&k6auvKVV1C=j) z@uY7j8?@j_Q^3WOz9LFW9KLwcS1&huk)19r#G+M?)n~J4)wVWhBgmo=TFAF*SZmR$ z>bS9r%%WY*Zvh&gy9$r~0=q_yHr43O!+CQDuYAj-n?83OJ%C1sY+rs4ZdEiFi7BFtoPEKtUe-*dJk za;}^;AY7na+nNz10R_snvPo*6aDj5ILY(m8cv3mmVVR<3eU4YaCzX4e+VfzrpD*B~ za*tq=QiZGkJlc>*MVJudSSx`QSgwJ4vhAmTr1(zh0%5isFm;$P*T)zt%Q$O zBytf>k~ea^q|HYYd;vqq-iwsS;q;PgeLC?ew($#&J#P~j1cVDMDXr#^M~4JB!U}wz zc@XQOkkyrAU%p*Dg9s!?fu)*e*JK5sQ$+;Iq8`ady!WRZ=2@?V_U| z$tCM`7Yt|j@?43vJPx<BR{>j)_3Ly$ftK zQ1V5pXNVJlo~HKX8*K0dBmzBxNeUNE1bVa~k&5un1&+~&qkz$0GWAYFDQ)dfG#5H` zu%UA+oiRMihV@0z!N}tuAAN+0Dk+9|mJL&noow?L zOrn5U)>lMH3B;urYRRavTK^sLXZEg!eSui&1H5bhEX00#>yDT-T} zMu8KL!l!5_ghIoGk}6KELGTpq^krmHL?BFO(h*fsDubtJM?Fql?&7$hM<21v8ta-` zRKv{Y@)>aJ2sKK%Fz{9Negc9N0v6hZ29OTq+S+NkJ#S%wGFeaQT;C67MuC z`mq}^8Z({$X{WYGl7fU!E3x$;(E-kVWbAOf=+c%wv8Gow3h1^=nytbYUDDdyLYb#rF4R0?Lr zP#0@z#RRv#&6%;bk}l*kE7bmWy<625rx^<6IPRAqG(kf}n=SEv32$2)v*0Y4fc+9) z$t1;#V$IN?xUq^X_a(#;s}9XtU8m;pYaKDCy^Yr?AZmnPIC^v+@GR63bEK0LF`Q%d zzAVG#0uek?X>XDs$r@a;*^#DYJ! zwl$|>qu{F$kBxcu*v5kg4*&6<#I6S>9yosL?~fkudVBW`e><_aaP7)F2c~~#(Hr{? zzwq+oNA^88Z}Q9&ZX0i0^w*txcO3jp-)Xy_9MiXE_R+Z$2HqU~_HU2QeC*zLj=r1i zSb55x$G>&wCpV|(JfO~*cI?H)=4SoE*WbPR3lB{^c>Cg6=iGdHi#l~i@v%J(t1f?T zPkbzp>Dw1?*)i#baSP+P*pdJXYU5!lsu_{vfvFpmLPc$_l;~G!;saBiRyIh%v!H+j zQyrO@jnj(j4<6dq{jSgjIzH){A3nHf|AY_rKYGu3g|4s6AGh-P6W^b*tXuohd7G}gZ^5P0wfB0S9{8qm zQS1lD)ECeB`74KB|5K*!sljubuU&ul+3%eH^z1XAJUscedzT|hFc5XJCZA<}3!B>1-Z$ko9`_|Q`nqqN| z4i(&EP(4(TIKm3q7^mLW~z_> zB2JBHl7fXxwrccoqZM6dl;eUR(qXM)Zlz6octOx^WU~}(q691m+9FBHP#gKW!sqX1 zCo;3t!`Un$bOL>+v%H!*t`;Ls{enyrMVCPsC`gqm*zEtfIU%-%17gK;MmGxiG|eiF z#Xq$1frA9UaCGO6=sG##gGE7do>r9t{R+}Z=nKW*-{0P`;iC<&+!SAd+q;LNjwy39 zf4k+ z4l6!<#Q%dhjdz;Et7qAd7Tr*3Z{K+0=Zs_6#qk9sq+uMa)kGIg!?Ky*uux81JE^J= z<6x-#2Ls9&ZVQ)J#pW~w9N&y3im3#>8Sv+fgCXF}u%!(j5&UMrE}Vvi zpqN>F#DZ@pMyv!JvEVBr;}nT&?R`III77|gzAF6YO?X==Wl+ai;|+eyIDBAJZ$Vv{ zOeR|vCfAq2>6FR7F5nlJlL@WTshY`>lId1D!Jjp7k-G`bD_4wc0z@)~V)Q4$8e5`1 znXcpuS@P%LuakzFOFF_JS>>|`s~io6g9w8)$ZM8IDi5+nNr1LG}O4@i250vhL+>R*=ZlZ% zPfa|&>DFJo)cD(#OEcXVW5oqG4uU;VlJ zQx}|m>4Q(G7rghx*wLH+73Hc@|FvMlgY#B5#_{sLSDj&CRi8@d>K8Q5Q?m8*8r1qm z=;?Z^M!NVJ_I5+j%1Q>>3F>x&$(Btd+cDx~@Hg3|pGP&~tRzd<+0~ z*}#t(2T6d-hGiXuU`rLmVV4bPFdRe}TsDp||HizQ)%&O~HIDhMCXA>Ei1|sG<--NX z{FWA+kl|=m;KFf0AP9cUh>8HKf@KYN>+xF*dJJbs7z{nfzzeFmGOzW}#svpnxDDgr z2nf8eM2vGX4!m$TPQ%2x3<)@c#1$Qs_lPV*ay4cgI6-AdF3}iA@bi{e1xL`;pVLr& zKFlNTQVRu88=)o2+3t?Hb#ogNDR91Mssm)3I*9BO$S!q!4mWMfb~~@x?7PkHoc61+ z@p$|cvO)a!V`8y!z>zrvdNbBnZKZUE)%PXkOgeHVft=nf7%2vn6D{e-;>*atcOJL% zSu6|aS_OO_`f}H+hc22I^BF@g>p3%#&J+?#xgQ*z25*haDd4i+j(H%bS4Vs1tL$!{ z1>KrqH+1_I>gEi>!%y7y@ZQ645T*t8h@XUqf*cX>y}R0heZf3Xtt3*5Hbj9!BDDsg zfFVxs$l4omMW9j+aOk11u*R}aBD6Hi86a@*t_m)@FZ7r5&|CizM{Tlcd^8+D;)`Ba!(5gXs7Dg%5eynB95Z1fE1R;3{-_U`#2$M#6@|?H}U8{9WL3dsUWfV%f3^wjpQ*#~Q3{|knBX}xZfx0yl-5l(`{Eb_0 z{_qH#NzZZKw%QJHXwIg9|KacOi*DYS*J*=vN>+6WHgB~eN^0Z?=4y3vkgGnEsBGOW zq31h$2WYElmJ;xnOd$^n8m-0IA>g+RegOQX1%1HE>guio;=Z5mwLqNZ1(DvB5y?Hw z=R32hJOn!Fa!bl-7u%@tBKF!L6I*tL-8pbG<`8Ig#i|K-t)@fjy5-kfq@L$}Cbiud zDZORbl-8;_1VU@&m6Xn0_(+UYGP}Utn8PO1eX%ApnXsE+GNGEoCev1P5c(cc`II4K zLd|%Q`IW!ZW){IoQQ*9L!yGoAtMDh#tmh|!-&wmaBdB{LGNHEC!=}}iTvB7&%{VZ; zxcz(QdJ~*;K5S&sv9)&I#|e)@=6cwT5!9&WdZ^~G8MW2?r?aR~GhSqNge@B{>HyPa>;~?|1kdG0_B&VssHg~``_7L{P*N_w@lgjlRLLR z`jh5&7eDsDFD(4jQzu`1VCjxCKfP|t4J*Dj;gr9;^y^nYY@K=6!0MCF-qyPJx(hDo zZod23_Xc`@{nmy_zwSKcq5r<-uD@ii{M)I=AHDj>)YgW*3n%~Xcb!-M=;f<=e)pTR z-rqj&{;^-*aW|^XdVK1)ANr3?yZ6OgJ!&|Nph02@tuv|Af^?mdOE)w&Eyy(~&>8X8 zWL+MLNPijNkw{l^IZz4R(U1TMaw;L!cAu@ba{#&O)mt(rB0zAthSkJgEySGA`A9SK z;Sw~71f}9pE9fA6E+KB($Xd<7H5%5lbl`x8Gyy=u&&_06z6d?8wOoCc8NEU|U zu~;#cbV2QC@>{*I7Fk<}UdwSW2b|7ld!BgzWt8d*>JUE}4j%DE$B6l?)*zLVNTmR% z{8bu+5{4i)vd(_Og~wE#9N^F+VF8Zipw{q<+^pfr=9NxOFPr%cs0?$y*DFRw^F zI9lR#NI2iOq0SC}&o6u5TD1KbLqEo)TlVYQ7!>tiz-17ad0HG}o@(h>ZNWHCUNOXZvMOchG)YLwV!}oiENfj4(!nCq zNwUC*g@$+W^n$5UXKH;1NM@xW9x6C6bhi;_xUW2^y| zaNriMa-ssZ+~lCU1+KOU2nq4dHMkEO_6Mst)&A>Ie}}$v58h>&wON+o4(ZD1bPX`4 zTG=!PeizUxY=h$9%Itlyga+Fgr&*Y0OsM!Cdsrh>f_t?)7KB8jD8p#q zHVNx#*1~=coj1?l^|6MPZP#y<{d-#hUkzO-YDt$CdBFzG54AN{6$|zM> z>bkG3_TfA9p~n(cU>bU1vt>D4V^mJ`sp-&Y)HOWi1m0!_p@}{5<{efHiZ5)gZOv!| znJ;Yi)g(0Btd)(~(v7UR0iXU^tB`{ivvFfdw1u9pM-B>HnnqNmf@WPLyS)&NXzF}v zwDK&o~Ygz^p>8M86n$u+_4d-&@ zV9)e4ZQMzl=B}DO+Sm9dGDTKV3~&K6b+)uDf52r<9pmhMzu)(J?~C`x-F=?-`Sm`} z=Xu_qVN2)mgr*>g@-;gNVmC=9%?BrwDDajbW>_2&+8CWB5RBN8@QPyLk_NAaS+Qvx zRd3SZfh`Ww<6`ho{A6K;BQ~c%5In75rDK+m;15ZQ1%iqr3JfGqg;9)y_@&SK=FcWs zaMigG?1?tWPhBfA?U^d&4gN8u)j3T#!WW#G9QCczus!ohjzX6;OwZ1jG@D#A1%gsf z68Li_VM?xzOX=0HKCe{h;G>yt3B6g6ClD=?0?Ryh49&3%DVBPk;)umRIzLgILFFz5 z!$so@tzg}vBuR&r?MyM(L2pSvKMO3$#@l5s17ToEuCT%T<&y-0TlET-ER$M+{uOg0 z=NdX!nqK-=4RSfl_0DtY95r-l`21?qXP`#IeQV72drLGNduc+%AEJAmSwBiEc1Jkz zvK?N77vUFe9W+%zj&*jHwGKL9g=*@yVC_?ZN$Gen-WH$)mtBL$g%g#Vz5~l zd0&c)Gj?QfZ)J^Lc<93^2Eww&3nB_u?vf^fa^H&GABmE(vN@n-cQh{iI9phOJE%bJ zCz;T{CnO3;2LQuO30#d8No{t(f{r+N8}3Ea(7#urh)&j_15+?>f06Ky-+ekyAew^} zpZ-ix1zCJ-Ybg{uSai5tAU(gfmK0du8pGxo!=GElDOMaYM}ZN8_2>8(l6Q0mi-k7Z z2iW$NoL%wp<_k_ho{V5us&964q=bM(=!Cpx6je`R9w&@ z>F8Y8cUIyi4tDaPz=p0~$)3{OH#Cpfu=Phl7LAGQu((^nw4Wu8=tFV7*N*S>#Bv`j zzw^B*l1Ek_=Y?oPVl3>nzsie`P1dymJDeLFi*#9^9dc0~K zh=Vt-nhTP3rPQOq@;@FJ4%v>ma?RYP44wQlo|{qx+iogQcjJ0Q8UFeEUjeq=l=5OE zJ#pJy)6CV*VQDs@Jrs^uV%1%9^DxEP_sk5uB`#kBF56l zNgYy%cnx&f0pCR{NmMt+67ed!RC<9+k@9ofT05zbWVU4TCG@sf)SN`ZcQbvWT`HAd zm(*A()XG${Qj#%KUqTwWV-~=r?w>{)4Gon(`~6&*5>EX(i!3srajoL%gzq&2*X0nI zNtAG^mP;O^i<+KKo{40D>Zw^o9%J?@=6;{x+g?Dd>MQQ?0S?a{j|V(tj+BsZO(EIx EKavnI82|tP diff --git a/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll b/src/Jellyfin.CodeAnalysis/obj/Debug/netstandard2.0/Jellyfin.CodeAnalysis.dll index a40ec0229eedc7dd8863edb86859bbf741dd9799..5f6f2076e72fe2cf0530b46beb8b6a0029b56986 100644 GIT binary patch delta 232 zcmZp0X>gg)!J_@K;Mm5V7*PQ+9^O`u-1%+|>07?t`OlrP`G@EpCUp}FQ!`5wBlASl z*0QKh|8`(+VhXf7R zCDnd460RqpRq84`iKWQHUlZO&i}WE%qIO&C%c41g?iAO@*V0gg)!E#1-b^FGi7*T;3vn8)MH8(hHNKT2AVc%`A`G@EpCiPSc3v**rGh+)= zv&0k&L*wKmlO%I9OVcES#Kc4k(_~{Kb0f<{lgYOw*0NMyuU$2{M>0U*lEbRZsiI50 zRtFb)x2!G6p8Q6#SOF^dN*gK&Qk^Qy`grl&<|$LcEkZWeOWkDgO=YkELURUV22%zz zAZY=n6B$x~EJGkanIVb61c=RnvX(%(BnAV9L@)%YOa`hj0?HWyb^!PwY>Sa3Itq001LGY;R%!004$KQ`taZC`F`uPJ9?e$h9Sx_P~*lt|1X4 z0RY=00RZ+R0RX8a000000RY4#00000000000RYUCUjfrA#Um#G1OR9QCjbQir3F?1 z0|55`b^rqa?g0P+1^|U5AOQvdyCfh12LQgaT>^;$e;a$JgR+CLGw7E&9aHT7|MB@9 zbrCeJTo;W1B=qXyj;tL! zc53Te+Bmdh;d*Y>C_*Oxn)Z)H+%r8RGG)|n2)aWVc2^?`w!lm zdbL=t>sf;fqp_JUs#Q&8)l~ILH>Rn&<#I7=*4i9j_H*!UGIF}EKC)Ok9q#{~-M{A# z9fyA~zx+=R?-JVF-Dd5{Q|RN245f)qZk3B9|5C00i#F(qhA4| LeF3AQlh!8r|48|w delta 545 zcmV++0^a@XPtZ@0a3HuO001LGY;R%!007cJs%e!KrAn()aZ7})bZdFneX5a=t|9ay z0RX-u0RY(}0RW67000000RX2Y00000000000RXR)UjfrAs3Ru;1OQ6|CjbQihy_*v z0|55`b^rqa?g0P+1^{RzAOQvdo+Kav2LPe7T>^;$e`r==Ymjpenm7`9mRO%vk4m;_ z7I@`VjjsEh7YAw9Oo3Ys1ONc7lTAwlF%X9Dh5m=3Cq=qzZMR)N5Nf5OAc%?{#KR;z zyB)|TlFVB6-%F|#iy!pR$tja}o_81~Y1-dubUSGZXV{4AS7gbfP;tIW#&}$C0PPBb zB?edve?YZ>AkLX2O4st)0&PVB#DT=hk_|zPEof{40bA|7CoQ08f$!`*peQ7IyYDN?$Mps+DO^ zehQN5*W1k1Z)n@8h-cLZ?e%WRn6_k_%v?cJe~YFK9D4h&TLW#$RpT*czhN&)HP!Z* zIU9N+A2uO_ZI0i$36qlJ_6CiwvXn-=XQ diff --git a/src/Jellyfin.Drawing/ImageProcessor.cs b/src/Jellyfin.Drawing/ImageProcessor.cs index a84f0034..12450cb0 100644 --- a/src/Jellyfin.Drawing/ImageProcessor.cs +++ b/src/Jellyfin.Drawing/ImageProcessor.cs @@ -64,10 +64,10 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable IImageEncoder imageEncoder, IServerConfigurationManager config) { - _logger = logger; - _fileSystem = fileSystem; - _imageEncoder = imageEncoder; - _appPaths = appPaths; + this._logger = logger; + this._fileSystem = fileSystem; + this._imageEncoder = imageEncoder; + this._appPaths = appPaths; var semaphoreCount = config.Configuration.ParallelImageEncodingLimit; if (semaphoreCount < 1) @@ -75,10 +75,10 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable semaphoreCount = Environment.ProcessorCount; } - _parallelEncodingLimit = new(semaphoreCount); + this._parallelEncodingLimit = new(semaphoreCount); } - private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images"); + private string ResizedImageCachePath => Path.Combine(this._appPaths.ImageCachePath, "resized-images"); /// public IReadOnlyCollection SupportedInputFormats => @@ -113,11 +113,11 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable }; /// - public bool SupportsImageCollageCreation => _imageEncoder.SupportsImageCollageCreation; + public bool SupportsImageCollageCreation => this._imageEncoder.SupportsImageCollageCreation; /// public IReadOnlyCollection GetSupportedImageOutputFormats() - => _imageEncoder.SupportedOutputFormats; + => this._imageEncoder.SupportedOutputFormats; /// public async Task<(string Path, string? MimeType, DateTime DateModified)> ProcessImage(ImageProcessingOptions options) @@ -134,12 +134,12 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable } var mimeType = MimeTypes.GetMimeType(originalImagePath); - if (!_imageEncoder.SupportsImageEncoding) + if (!this._imageEncoder.SupportsImageEncoding) { return (originalImagePath, mimeType, dateModified); } - var supportedImageInfo = await GetSupportedImage(originalImagePath, dateModified).ConfigureAwait(false); + var supportedImageInfo = await this.GetSupportedImage(originalImagePath, dateModified).ConfigureAwait(false); originalImagePath = supportedImageInfo.Path; // Original file doesn't exist, or original file is gif. @@ -179,8 +179,8 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable int quality = options.Quality; - ImageFormat outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency); - string cacheFilePath = GetCacheFilePath( + ImageFormat outputFormat = this.GetOutputFormat(options.SupportedOutputFormats, requiresTransparency); + string cacheFilePath = this.GetCacheFilePath( originalImagePath, options.Width, options.Height, @@ -204,9 +204,9 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable string resultPath; // Limit number of parallel (more precisely: concurrent) image encodings to prevent a high memory usage - using (await _parallelEncodingLimit.LockAsync().ConfigureAwait(false)) + using (await this._parallelEncodingLimit.LockAsync().ConfigureAwait(false)) { - resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat); + resultPath = this._imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat); } if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase)) @@ -215,19 +215,19 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable } } - return (cacheFilePath, outputFormat.GetMimeType(), _fileSystem.GetLastWriteTimeUtc(cacheFilePath)); + return (cacheFilePath, outputFormat.GetMimeType(), this._fileSystem.GetLastWriteTimeUtc(cacheFilePath)); } catch (Exception ex) { // If it fails for whatever reason, return the original image - _logger.LogError(ex, "Error encoding image"); + this._logger.LogError(ex, "Error encoding image"); return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); } } private ImageFormat GetOutputFormat(IReadOnlyCollection clientSupportedFormats, bool requiresTransparency) { - var serverFormats = GetSupportedImageOutputFormats(); + var serverFormats = this.GetSupportedImageOutputFormats(); // Client doesn't care about format, so start with webp if supported if (serverFormats.Contains(ImageFormat.Webp) && clientSupportedFormats.Contains(ImageFormat.Webp)) @@ -354,7 +354,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable filename.Append(",v="); filename.Append(Version); - return GetCachePath(ResizedImageCachePath, filename.ToString(), format.GetExtension()); + return this.GetCachePath(this.ResizedImageCachePath, filename.ToString(), format.GetExtension()); } /// @@ -369,9 +369,9 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable } string path = info.Path; - _logger.LogDebug("Getting image size for item {ItemType} {Path}", item.GetType().Name, path); + this._logger.LogDebug("Getting image size for item {ItemType} {Path}", item.GetType().Name, path); - ImageDimensions size = GetImageDimensions(path); + ImageDimensions size = this.GetImageDimensions(path); info.Width = size.Width; info.Height = size.Height; @@ -380,13 +380,13 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable /// public ImageDimensions GetImageDimensions(string path) - => _imageEncoder.GetImageSize(path); + => this._imageEncoder.GetImageSize(path); /// public string GetImageBlurHash(string path) { - var size = GetImageDimensions(path); - return GetImageBlurHash(path, size); + var size = this.GetImageDimensions(path); + return this.GetImageBlurHash(path, size); } /// @@ -406,7 +406,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable int xComp = Math.Min((int)xCompF + 1, 9); int yComp = Math.Min((int)yCompF + 1, 9); - return _imageEncoder.GetImageBlurHash(xComp, yComp, path); + return this._imageEncoder.GetImageBlurHash(xComp, yComp, path); } /// @@ -415,11 +415,11 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable /// public string GetImageCacheTag(BaseItem item, ItemImageInfo image) - => GetImageCacheTag(item.Path, image.DateModified); + => this.GetImageCacheTag(item.Path, image.DateModified); /// public string GetImageCacheTag(BaseItemDto item, ItemImageInfo image) - => GetImageCacheTag(item.Path, image.DateModified); + => this.GetImageCacheTag(item.Path, image.DateModified); /// public string? GetImageCacheTag(BaseItemDto item, ChapterInfo chapter) @@ -429,7 +429,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable return null; } - return GetImageCacheTag(item.Path, chapter.ImageDateModified); + return this.GetImageCacheTag(item.Path, chapter.ImageDateModified); } /// @@ -440,7 +440,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable return null; } - return GetImageCacheTag(item, new ItemImageInfo + return this.GetImageCacheTag(item, new ItemImageInfo { Path = chapter.ImagePath, Type = ImageType.Chapter, @@ -456,7 +456,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable return null; } - return GetImageCacheTag(user.ProfileImage.Path, user.ProfileImage.LastModified); + return this.GetImageCacheTag(user.ProfileImage.Path, user.ProfileImage.LastModified); } private Task<(string Path, DateTime DateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified) @@ -494,7 +494,7 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable var filename = uniqueName.GetMD5() + fileExtension; - return GetCachePath(path, filename); + return this.GetCachePath(path, filename); } /// @@ -528,28 +528,28 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable /// public void CreateImageCollage(ImageCollageOptions options, string? libraryName) { - _logger.LogDebug("Creating image collage and saving to {Path}", options.OutputPath); + this._logger.LogDebug("Creating image collage and saving to {Path}", options.OutputPath); - _imageEncoder.CreateImageCollage(options, libraryName); + this._imageEncoder.CreateImageCollage(options, libraryName); - _logger.LogDebug("Completed creation of image collage and saved to {Path}", options.OutputPath); + this._logger.LogDebug("Completed creation of image collage and saved to {Path}", options.OutputPath); } /// public void Dispose() { - if (_disposed) + if (this._disposed) { return; } - if (_imageEncoder is IDisposable disposable) + if (this._imageEncoder is IDisposable disposable) { disposable.Dispose(); } - _parallelEncodingLimit?.Dispose(); + this._parallelEncodingLimit?.Dispose(); - _disposed = true; + this._disposed = true; } } diff --git a/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs b/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs index 0e1e1c63..97b1610a 100644 --- a/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs +++ b/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs @@ -13,8 +13,17 @@ namespace Jellyfin.Controller.Tests using Moq; using Xunit; + /// + /// Tests for . + /// public class BaseItemManagerTests { + /// + /// Tests that IsMetadataFetcherEnabled checks library and server configuration options. + /// + /// The type of item to test. + /// The name of the metadata fetcher. + /// The expected result. [Theory] [InlineData(typeof(Book), "LibraryEnabled", true)] [InlineData(typeof(Book), "LibraryDisabled", false)] @@ -24,30 +33,36 @@ namespace Jellyfin.Controller.Tests { BaseItem item = (BaseItem)Activator.CreateInstance(itemType)!; - var libraryTypeOptions = itemType == typeof(Book) + TypeOptions? libraryTypeOptions = itemType == typeof(Book) ? new TypeOptions { Type = "Book", - MetadataFetchers = new[] { "LibraryEnabled" } + MetadataFetchers = ["LibraryEnabled"], } : null; - var serverConfiguration = new ServerConfiguration(); - foreach (var typeConfig in serverConfiguration.MetadataOptions) + ServerConfiguration serverConfiguration = new(); + foreach (MetadataOptions typeConfig in serverConfiguration.MetadataOptions) { - typeConfig.DisabledMetadataFetchers = new[] { "ServerDisabled" }; + typeConfig.DisabledMetadataFetchers = ["ServerDisabled"]; } - var serverConfigurationManager = new Mock(); - serverConfigurationManager.Setup(scm => scm.Configuration) + Mock serverConfigurationManager = new(); + _ = serverConfigurationManager.Setup(scm => scm.Configuration) .Returns(serverConfiguration); - var baseItemManager = new BaseItemManager(serverConfigurationManager.Object); - var actual = baseItemManager.IsMetadataFetcherEnabled(item, libraryTypeOptions, fetcherName); + BaseItemManager baseItemManager = new(serverConfigurationManager.Object); + bool actual = baseItemManager.IsMetadataFetcherEnabled(item, libraryTypeOptions, fetcherName); Assert.Equal(expected, actual); } + /// + /// Tests that IsImageFetcherEnabled checks library and server configuration options. + /// + /// The type of item to test. + /// The name of the image fetcher. + /// The expected result. [Theory] [InlineData(typeof(Book), "LibraryEnabled", true)] [InlineData(typeof(Book), "LibraryDisabled", false)] @@ -57,26 +72,26 @@ namespace Jellyfin.Controller.Tests { BaseItem item = (BaseItem)Activator.CreateInstance(itemType)!; - var libraryTypeOptions = itemType == typeof(Book) + TypeOptions? libraryTypeOptions = itemType == typeof(Book) ? new TypeOptions { Type = "Book", - ImageFetchers = new[] { "LibraryEnabled" } + ImageFetchers = ["LibraryEnabled"], } : null; - var serverConfiguration = new ServerConfiguration(); - foreach (var typeConfig in serverConfiguration.MetadataOptions) + ServerConfiguration serverConfiguration = new(); + foreach (MetadataOptions typeConfig in serverConfiguration.MetadataOptions) { - typeConfig.DisabledImageFetchers = new[] { "ServerDisabled" }; + typeConfig.DisabledImageFetchers = ["ServerDisabled"]; } - var serverConfigurationManager = new Mock(); - serverConfigurationManager.Setup(scm => scm.Configuration) + Mock serverConfigurationManager = new(); + _ = serverConfigurationManager.Setup(scm => scm.Configuration) .Returns(serverConfiguration); - var baseItemManager = new BaseItemManager(serverConfigurationManager.Object); - var actual = baseItemManager.IsImageFetcherEnabled(item, libraryTypeOptions, fetcherName); + BaseItemManager baseItemManager = new(serverConfigurationManager.Object); + bool actual = baseItemManager.IsImageFetcherEnabled(item, libraryTypeOptions, fetcherName); Assert.Equal(expected, actual); } diff --git a/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs b/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs index 319dcec2..a11859d3 100644 --- a/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs +++ b/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs @@ -4,124 +4,140 @@ namespace Jellyfin.Controller.Tests { + using System.Collections.Generic; using System.Linq; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using Moq; using Xunit; + /// + /// Tests for . + /// public class DirectoryServiceTests { private const string LowerCasePath = "/music/someartist"; private const string UpperCasePath = "/music/SOMEARTIST"; - private static readonly FileSystemMetadata[] _lowerCaseFileSystemMetadata = - { + private static readonly FileSystemMetadata[] LowerCaseFileSystemMetadata = + [ new() { FullName = LowerCasePath + "/Artwork", - IsDirectory = true + IsDirectory = true, }, new() { FullName = LowerCasePath + "/Some Other Folder", - IsDirectory = true + IsDirectory = true, }, new() { FullName = LowerCasePath + "/Song 2.mp3", - IsDirectory = false + IsDirectory = false, }, new() { FullName = LowerCasePath + "/Song 3.mp3", - IsDirectory = false - } - }; + IsDirectory = false, + }, + ]; - private static readonly FileSystemMetadata[] _upperCaseFileSystemMetadata = - { + private static readonly FileSystemMetadata[] UpperCaseFileSystemMetadata = + [ new() { FullName = UpperCasePath + "/Lyrics", - IsDirectory = true + IsDirectory = true, }, new() { FullName = UpperCasePath + "/Song 1.mp3", - IsDirectory = false - } - }; + IsDirectory = false, + }, + ]; + /// + /// Tests that GetFileSystemEntries caches entries for paths with different casing. + /// [Fact] public void GetFileSystemEntries_GivenPathsWithDifferentCasing_CachesAll() { - var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(_upperCaseFileSystemMetadata); - fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(_lowerCaseFileSystemMetadata); - var directoryService = new DirectoryService(fileSystemMock.Object); + Mock fileSystemMock = new(); + _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(UpperCaseFileSystemMetadata); + _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(LowerCaseFileSystemMetadata); + DirectoryService directoryService = new(fileSystemMock.Object); - var upperCaseResult = directoryService.GetFileSystemEntries(UpperCasePath); - var lowerCaseResult = directoryService.GetFileSystemEntries(LowerCasePath); + FileSystemMetadata[] upperCaseResult = directoryService.GetFileSystemEntries(UpperCasePath); + FileSystemMetadata[] lowerCaseResult = directoryService.GetFileSystemEntries(LowerCasePath); - Assert.Equal(_upperCaseFileSystemMetadata, upperCaseResult); - Assert.Equal(_lowerCaseFileSystemMetadata, lowerCaseResult); + Assert.Equal(UpperCaseFileSystemMetadata, upperCaseResult); + Assert.Equal(LowerCaseFileSystemMetadata, lowerCaseResult); } + /// + /// Tests that GetFiles returns correct files for paths with different casing. + /// [Fact] public void GetFiles_GivenPathsWithDifferentCasing_ReturnsCorrectFiles() { - var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(_upperCaseFileSystemMetadata); - fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(_lowerCaseFileSystemMetadata); - var directoryService = new DirectoryService(fileSystemMock.Object); + Mock fileSystemMock = new(); + _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(UpperCaseFileSystemMetadata); + _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(LowerCaseFileSystemMetadata); + DirectoryService directoryService = new(fileSystemMock.Object); - var upperCaseResult = directoryService.GetFiles(UpperCasePath); - var lowerCaseResult = directoryService.GetFiles(LowerCasePath); + List upperCaseResult = directoryService.GetFiles(UpperCasePath); + List lowerCaseResult = directoryService.GetFiles(LowerCasePath); - Assert.Equal(_upperCaseFileSystemMetadata.Where(f => !f.IsDirectory), upperCaseResult); - Assert.Equal(_lowerCaseFileSystemMetadata.Where(f => !f.IsDirectory), lowerCaseResult); + Assert.Equal(UpperCaseFileSystemMetadata.Where(f => !f.IsDirectory), upperCaseResult); + Assert.Equal(LowerCaseFileSystemMetadata.Where(f => !f.IsDirectory), lowerCaseResult); } + /// + /// Tests that GetDirectories returns correct directories for paths with different casing. + /// [Fact] public void GetDirectories_GivenPathsWithDifferentCasing_ReturnsCorrectDirectories() { - var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(_upperCaseFileSystemMetadata); - fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(_lowerCaseFileSystemMetadata); - var directoryService = new DirectoryService(fileSystemMock.Object); + Mock fileSystemMock = new(); + _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(UpperCaseFileSystemMetadata); + _ = fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(LowerCaseFileSystemMetadata); + DirectoryService directoryService = new(fileSystemMock.Object); - var upperCaseResult = directoryService.GetDirectories(UpperCasePath); - var lowerCaseResult = directoryService.GetDirectories(LowerCasePath); + List upperCaseResult = directoryService.GetDirectories(UpperCasePath); + List lowerCaseResult = directoryService.GetDirectories(LowerCasePath); - Assert.Equal(_upperCaseFileSystemMetadata.Where(f => f.IsDirectory), upperCaseResult); - Assert.Equal(_lowerCaseFileSystemMetadata.Where(f => f.IsDirectory), lowerCaseResult); + Assert.Equal(UpperCaseFileSystemMetadata.Where(f => f.IsDirectory), upperCaseResult); + Assert.Equal(LowerCaseFileSystemMetadata.Where(f => f.IsDirectory), lowerCaseResult); } + /// + /// Tests that GetFile returns correct file for paths with different casing. + /// [Fact] public void GetFile_GivenFilePathsWithDifferentCasing_ReturnsCorrectFile() { const string lowerCasePath = "/music/someartist/song 1.mp3"; - var lowerCaseFileSystemMetadata = new FileSystemMetadata + FileSystemMetadata lowerCaseFileSystemMetadata = new() { FullName = lowerCasePath, - Exists = true + Exists = true, }; const string upperCasePath = "/music/SOMEARTIST/SONG 1.mp3"; - var upperCaseFileSystemMetadata = new FileSystemMetadata + FileSystemMetadata upperCaseFileSystemMetadata = new() { FullName = upperCasePath, - Exists = false + Exists = false, }; - var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata); - fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata); - var directoryService = new DirectoryService(fileSystemMock.Object); + Mock fileSystemMock = new(); + _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata); + _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata); + DirectoryService directoryService = new(fileSystemMock.Object); - var lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath); - var lowerCaseFileResult = directoryService.GetFile(lowerCasePath); - var upperCaseDirResult = directoryService.GetDirectory(upperCasePath); - var upperCaseFileResult = directoryService.GetFile(upperCasePath); + FileSystemMetadata? lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath); + FileSystemMetadata? lowerCaseFileResult = directoryService.GetFile(lowerCasePath); + FileSystemMetadata? upperCaseDirResult = directoryService.GetDirectory(upperCasePath); + FileSystemMetadata? upperCaseFileResult = directoryService.GetFile(upperCasePath); Assert.Null(lowerCaseDirResult); Assert.Equal(lowerCaseFileSystemMetadata, lowerCaseFileResult); @@ -129,32 +145,35 @@ namespace Jellyfin.Controller.Tests Assert.Null(upperCaseFileResult); } + /// + /// Tests that GetDirectory returns correct directory for paths with different casing. + /// [Fact] public void GetDirectory_GivenFilePathsWithDifferentCasing_ReturnsCorrectDirectory() { const string lowerCasePath = "/music/someartist/Lyrics"; - var lowerCaseFileSystemMetadata = new FileSystemMetadata + FileSystemMetadata lowerCaseFileSystemMetadata = new() { FullName = lowerCasePath, IsDirectory = true, - Exists = true + Exists = true, }; const string upperCasePath = "/music/SOMEARTIST/LYRICS"; - var upperCaseFileSystemMetadata = new FileSystemMetadata + FileSystemMetadata upperCaseFileSystemMetadata = new() { FullName = upperCasePath, IsDirectory = true, - Exists = false + Exists = false, }; - var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata); - fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata); - var directoryService = new DirectoryService(fileSystemMock.Object); + Mock fileSystemMock = new(); + _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata); + _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata); + DirectoryService directoryService = new(fileSystemMock.Object); - var lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath); - var lowerCaseFileResult = directoryService.GetFile(lowerCasePath); - var upperCaseDirResult = directoryService.GetDirectory(upperCasePath); - var upperCaseFileResult = directoryService.GetFile(upperCasePath); + FileSystemMetadata? lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath); + FileSystemMetadata? lowerCaseFileResult = directoryService.GetFile(lowerCasePath); + FileSystemMetadata? upperCaseDirResult = directoryService.GetDirectory(upperCasePath); + FileSystemMetadata? upperCaseFileResult = directoryService.GetFile(upperCasePath); Assert.Equal(lowerCaseFileSystemMetadata, lowerCaseDirResult); Assert.Null(lowerCaseFileResult); @@ -162,92 +181,101 @@ namespace Jellyfin.Controller.Tests Assert.Null(upperCaseFileResult); } + /// + /// Tests that GetFile returns cached file when the path is already cached. + /// [Fact] public void GetFile_GivenCachedPath_ReturnsCachedFile() { const string path = "/music/someartist/song 1.mp3"; - var cachedFileSystemMetadata = new FileSystemMetadata + FileSystemMetadata cachedFileSystemMetadata = new() { FullName = path, - Exists = true + Exists = true, }; - var newFileSystemMetadata = new FileSystemMetadata + FileSystemMetadata newFileSystemMetadata = new() { FullName = "/music/SOMEARTIST/song 1.mp3", - Exists = true + Exists = true, }; - var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(cachedFileSystemMetadata); - var directoryService = new DirectoryService(fileSystemMock.Object); + Mock fileSystemMock = new(); + _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(cachedFileSystemMetadata); + DirectoryService directoryService = new(fileSystemMock.Object); - var result = directoryService.GetFile(path); - fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(newFileSystemMetadata); - var secondResult = directoryService.GetFile(path); + FileSystemMetadata? result = directoryService.GetFile(path); + _ = fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(newFileSystemMetadata); + FileSystemMetadata? secondResult = directoryService.GetFile(path); Assert.Equivalent(cachedFileSystemMetadata, result); Assert.Equivalent(cachedFileSystemMetadata, secondResult); } + /// + /// Tests that GetFilePaths returns only cached paths when clear is not called. + /// [Fact] public void GetFilePaths_GivenCachedFilePathWithoutClear_ReturnsOnlyCachedPaths() { const string path = "/music/someartist"; - var cachedPaths = new[] - { + string[] cachedPaths = + [ "/music/someartist/song 1.mp3", "/music/someartist/song 2.mp3", "/music/someartist/song 3.mp3", "/music/someartist/song 4.mp3", - }; - var newPaths = new[] - { + ]; + string[] newPaths = + [ "/music/someartist/song 5.mp3", "/music/someartist/song 6.mp3", "/music/someartist/song 7.mp3", "/music/someartist/song 8.mp3", - }; + ]; - var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths); - var directoryService = new DirectoryService(fileSystemMock.Object); + Mock fileSystemMock = new(); + _ = fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths); + DirectoryService directoryService = new(fileSystemMock.Object); - var result = directoryService.GetFilePaths(path); - fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths); - var secondResult = directoryService.GetFilePaths(path); + IReadOnlyList result = directoryService.GetFilePaths(path); + _ = fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths); + IReadOnlyList secondResult = directoryService.GetFilePaths(path); Assert.Equal(cachedPaths, result); Assert.Equal(cachedPaths, secondResult); } + /// + /// Tests that GetFilePaths returns new paths when clear is called. + /// [Fact] public void GetFilePaths_GivenCachedFilePathWithClear_ReturnsNewPaths() { const string path = "/music/someartist"; - var cachedPaths = new[] - { + string[] cachedPaths = + [ "/music/someartist/song 1.mp3", "/music/someartist/song 2.mp3", "/music/someartist/song 3.mp3", "/music/someartist/song 4.mp3", - }; - var newPaths = new[] - { + ]; + string[] newPaths = + [ "/music/someartist/song 5.mp3", "/music/someartist/song 6.mp3", "/music/someartist/song 7.mp3", "/music/someartist/song 8.mp3", - }; + ]; - var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths); - var directoryService = new DirectoryService(fileSystemMock.Object); + Mock fileSystemMock = new(); + _ = fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(cachedPaths); + DirectoryService directoryService = new(fileSystemMock.Object); - var result = directoryService.GetFilePaths(path); - fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths); - var secondResult = directoryService.GetFilePaths(path, true); + IReadOnlyList result = directoryService.GetFilePaths(path); + _ = fileSystemMock.Setup(f => f.GetFilePaths(It.Is(x => x == path), false)).Returns(newPaths); + IReadOnlyList secondResult = directoryService.GetFilePaths(path, true); Assert.Equal(cachedPaths, result); Assert.Equal(newPaths, secondResult); diff --git a/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs b/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs index 8cb83f17..9e530e79 100644 --- a/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs +++ b/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs @@ -2,49 +2,67 @@ // Copyright (c) PlaceholderCompany. All rights reserved. // -namespace Jellyfin.Controller.Tests.Entities; - -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.MediaInfo; -using Moq; -using Xunit; - -public class BaseItemTests +namespace Jellyfin.Controller.Tests.Entities { - [Theory] - [InlineData("", "")] - [InlineData("1", "0000000001")] - [InlineData("t", "t")] - [InlineData("test", "test")] - [InlineData("test1", "test0000000001")] - [InlineData("1test 2", "0000000001test 0000000002")] - public void BaseItem_ModifySortChunks_Valid(string input, string expected) - => Assert.Equal(expected, BaseItem.ModifySortChunks(input)); + using MediaBrowser.Controller.Entities; + using MediaBrowser.Controller.Library; + using MediaBrowser.Model.MediaInfo; + using Moq; + using Xunit; - [Theory] - [InlineData("/Movies/Ted/Ted.mp4", "/Movies/Ted/Ted - Unrated Edition.mp4", "Ted", "Unrated Edition")] - [InlineData("/Movies/Deadpool 2 (2018)/Deadpool 2 (2018).mkv", "/Movies/Deadpool 2 (2018)/Deadpool 2 (2018) - Super Duper Cut.mkv", "Deadpool 2 (2018)", "Super Duper Cut")] - public void GetMediaSourceName_Valid(string primaryPath, string altPath, string name, string altName) + /// + /// Tests for . + /// + public class BaseItemTests { - var mediaSourceManager = new Mock(); - mediaSourceManager.Setup(x => x.GetPathProtocol(It.IsAny())) - .Returns((string x) => MediaProtocol.File); - BaseItem.MediaSourceManager = mediaSourceManager.Object; - - var video = new Video() + /// + /// Tests that ModifySortChunks correctly modifies sort chunks. + /// + /// The input string. + /// The expected output string. + [Theory] + [InlineData("", "")] + [InlineData("1", "0000000001")] + [InlineData("t", "t")] + [InlineData("test", "test")] + [InlineData("test1", "test0000000001")] + [InlineData("1test 2", "0000000001test 0000000002")] + public void BaseItem_ModifySortChunks_Valid(string input, string expected) { - Path = primaryPath - }; + Assert.Equal(expected, BaseItem.ModifySortChunks(input)); + } - var videoAlt = new Video() + /// + /// Tests that GetMediaSourceName returns the correct name for media sources. + /// + /// The primary path. + /// The alternate path. + /// The expected name for the primary path. + /// The expected name for the alternate path. + [Theory] + [InlineData("/Movies/Ted/Ted.mp4", "/Movies/Ted/Ted - Unrated Edition.mp4", "Ted", "Unrated Edition")] + [InlineData("/Movies/Deadpool 2 (2018)/Deadpool 2 (2018).mkv", "/Movies/Deadpool 2 (2018)/Deadpool 2 (2018) - Super Duper Cut.mkv", "Deadpool 2 (2018)", "Super Duper Cut")] + public void GetMediaSourceName_Valid(string primaryPath, string altPath, string name, string altName) { - Path = altPath, - }; + Mock mediaSourceManager = new(); + _ = mediaSourceManager.Setup(x => x.GetPathProtocol(It.IsAny())) + .Returns((string x) => MediaProtocol.File); + BaseItem.MediaSourceManager = mediaSourceManager.Object; - video.LocalAlternateVersions = [videoAlt.Path]; + Video video = new() + { + Path = primaryPath, + }; - Assert.Equal(name, video.GetMediaSourceName(video)); - Assert.Equal(altName, video.GetMediaSourceName(videoAlt)); + Video videoAlt = new() + { + Path = altPath, + }; + + video.LocalAlternateVersions = [videoAlt.Path]; + + Assert.Equal(name, video.GetMediaSourceName(video)); + Assert.Equal(altName, video.GetMediaSourceName(videoAlt)); + } } } diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj index c81c0a04..ee30ed70 100644 --- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj +++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj @@ -4,6 +4,7 @@ {462584F7-5023-4019-9EAC-B98CA458C0A0} net11.0 + true