From c322655cc682c6dd2ec8388c3cffa637d4182f14 Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 24 Sep 2014 13:16:29 +0100 Subject: [PATCH] add visual test for expressions function length() --- ...ons-length-512-512-1.0-grid-reference.json | 142 ++++++++ ...ons-length-512-512-2.0-grid-reference.json | 141 ++++++++ ...sions-length-512-512-1.0-agg-reference.png | Bin 0 -> 8357 bytes ...ons-length-512-512-1.0-cairo-reference.png | Bin 0 -> 8360 bytes ...sions-length-512-512-2.0-agg-reference.png | Bin 0 -> 10628 bytes ...ons-length-512-512-2.0-cairo-reference.png | Bin 0 -> 10308 bytes .../styles/functional-expressions-length.xml | 117 +++++++ tests/visual_tests/test.py | 321 +++++++++--------- 8 files changed, 561 insertions(+), 160 deletions(-) create mode 100644 tests/visual_tests/grids/functional-expressions-length-512-512-1.0-grid-reference.json create mode 100644 tests/visual_tests/grids/functional-expressions-length-512-512-2.0-grid-reference.json create mode 100644 tests/visual_tests/images/functional-expressions-length-512-512-1.0-agg-reference.png create mode 100644 tests/visual_tests/images/functional-expressions-length-512-512-1.0-cairo-reference.png create mode 100644 tests/visual_tests/images/functional-expressions-length-512-512-2.0-agg-reference.png create mode 100644 tests/visual_tests/images/functional-expressions-length-512-512-2.0-cairo-reference.png create mode 100644 tests/visual_tests/styles/functional-expressions-length.xml diff --git a/tests/visual_tests/grids/functional-expressions-length-512-512-1.0-grid-reference.json b/tests/visual_tests/grids/functional-expressions-length-512-512-1.0-grid-reference.json new file mode 100644 index 000000000..68bc7e3eb --- /dev/null +++ b/tests/visual_tests/grids/functional-expressions-length-512-512-1.0-grid-reference.json @@ -0,0 +1,142 @@ +{ + "keys": [ + "", + "1", + "5", + "4", + "2", + "6", + "3" + ], + "data": {}, + "grid": [ + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " ##### !! ", + " ##### !! $$$$ ", + " ###### !! $$$$ ", + " # ##### !! $$$$$$ ", + " # ## !! $$$ ", + " ### !! $$$$ ", + " ##### !! $$ ", + " ##### !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " %%%% %%%%!! ", + " %%%%%%% %%%%%%%% %%%%%%! ", + " %%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%% ", + " % %%%%%%%%%%%%%%%%%%%%%%%%%% %% ", + " %%% %%%%%%%%%%%%%%%%%%%%%%%%% %% ", + " %%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%% ", + " %%% !! %%%%%%%%%%% ", + " %%!! %%%%%%%%% ", + " % %% %%%%%%%%%%% ", + " !%%%% %%%%%%%%%%%% ", + " !! %%%%%%%% %% %%%%% ", + " !! %%%%%%% %% %% %% ", + " !! %% %% %% %% %% ", + " !! %% %% %% %% ", + " !! %% %% %% %% ", + " !! %% %% %% %% ", + " !! %%%%%%%%%%%%%%%%% ", + " !! %%%%%%%%%%%%%%%%%%%%% ", + " !! %%%%%%%%%%%%%%%%%%%%%%%%% ", + " !! %%%%%%%%%%%%%%%%%%%%%%%%% ", + " !! %%%%%%%%%%%%%%%%%%%%%%%%% ", + " !! %%%%%%%%%%%%%%%%%%%%%%%%% ", + " !! %%%%%%%%%%%%%%%%%%%%%% ", + " !! %%%%%%%%%%%%%%%%% ", + " !! %%%%%%% ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! &&&& ", + " !! ''' &&&&&& ", + " !! '''' &&&&&& ", + " !! '''''' &&&&&&&&&& ", + " !! '' & &&& ", + " !! '' &&& ", + " !! ''' &&&& ", + " !! &&&&&& ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + " !! ", + "!! ", + "! ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/grids/functional-expressions-length-512-512-2.0-grid-reference.json b/tests/visual_tests/grids/functional-expressions-length-512-512-2.0-grid-reference.json new file mode 100644 index 000000000..b079fcd86 --- /dev/null +++ b/tests/visual_tests/grids/functional-expressions-length-512-512-2.0-grid-reference.json @@ -0,0 +1,141 @@ +{ + "keys": [ + "", + "1", + "5", + "4", + "2", + "3" + ], + "data": {}, + "grid": [ + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " !!!! ", + " ######### !!!! ", + " ######### !!!! ", + " ########## !!!! $ $ ", + " ########### !!!! $$$$$$ ", + " ########### !!!! $$$$$$$$ ", + " ########### !!!! $$$$$$$$ ", + " ### ########### ## !!!! $$$$$$$$ ", + " ######### !!!! $$$$$$ ", + " # ###### !!!! $ $$ ", + " # ##### !!!! $$$$$ ", + " ####### !!!! $$$$ ", + " ##### %%%% %%%%% !!!! $$$$$$$ ", + " ###### %%%%%%% %%%%%%%!!!! $$$$$$ ", + " ########## %%%%%%%%% %%%%%%%%%!!! ", + " ########## %%%%%%%%%%% %%%%%%%%%%%% %%%%%%%%%%%!! ", + " ####### %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% ", + " %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% ", + " % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%% !!!!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%% !!!! %%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%% !!!! %%%%%%%%%%%%%%%%% ", + " % %%%%!!!! %%%%%%%%%%%%%%%%%% ", + " % %%%%%!! %%%%%%%%%%%%%%%%%%% ", + " %% %%%%% %%%%%%%%%%%%%%%%%%%%% ", + " !%%%%% %%%%%%%%%%%%%%%%%%%%% ", + " !!%%%%%% %%%%%%%%%%%%%%%%%%%%%% ", + " !!!!%%%%%%%%%%%%%%%%% %%%%% %%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%% %%%%% %%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%%%%%%%%%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%%%%%%%%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%% %%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%% %%%%% %%%%% %%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! &&&&&&& %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! &&&&&&& %%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!! &&&&&&& %%%%%%%%%%%%%% ", + " !!!! &&&&&&& ", + " !!!! &&&&&&&&&&& ", + " !!!! &&&&&& ", + " !!!! &&&&& ", + " !!!! &&& ", + " !!!! &&&&&& ", + " !!!! &&&&&&& ", + "!!!! &&& ", + "!!! ", + "!! ", + "! ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/images/functional-expressions-length-512-512-1.0-agg-reference.png b/tests/visual_tests/images/functional-expressions-length-512-512-1.0-agg-reference.png new file mode 100644 index 0000000000000000000000000000000000000000..7b9502e42e83e4f95149263975c535b2ae9b02cd GIT binary patch literal 8357 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 literal 0 HcmV?d00001 diff --git a/tests/visual_tests/images/functional-expressions-length-512-512-1.0-cairo-reference.png b/tests/visual_tests/images/functional-expressions-length-512-512-1.0-cairo-reference.png new file mode 100644 index 0000000000000000000000000000000000000000..d842e001c427e3eebc997a5aadb3530ba58e7875 GIT binary patch literal 8360 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 JMc+2y{{XQg$N>NV literal 0 HcmV?d00001 diff --git a/tests/visual_tests/images/functional-expressions-length-512-512-2.0-agg-reference.png b/tests/visual_tests/images/functional-expressions-length-512-512-2.0-agg-reference.png new file mode 100644 index 0000000000000000000000000000000000000000..e2582192fa48a2ba8cbfed8150511340defb160c GIT binary patch literal 10628 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 G{Qm%d61VIC literal 0 HcmV?d00001 diff --git a/tests/visual_tests/images/functional-expressions-length-512-512-2.0-cairo-reference.png b/tests/visual_tests/images/functional-expressions-length-512-512-2.0-cairo-reference.png new file mode 100644 index 0000000000000000000000000000000000000000..fe4da8d2eccdcafd0b4939b27eeeb139d5215365 GIT binary patch literal 10308 zcmd6t`9D!gnkznb>HX z8rte>7#bRynwsicnUeuP!`9Wp!ot;D*T%+%ghXmPdwAL!-@bj@-_hK~#YO)?fUUdh zrG-3ndG_L?hsz6$cXV`gPJ~aBpPO^?`)ALdxuldoNPkoOG$=7Ku{p%IBh1tD zWts2GcQLu?6)EBA>FHl$gOiGLyPib`y#17$oBJs{_R+h}-skZ}MMYWFC7rL6#$G-d z%*hCE6EOt?j9)$=_RqrLpbBh2vk-$A9KG zH#Z6Ezlb|)C;Pjngaa~}y!q;PJOBu`>1wH)2jy<$C1O~5w zU6WClY0RAB{OeeeZzR(%ux%DoF2M&Y#*y0Qrcbetk?mSv`Ltf?6f!BIi0*AOb0M>Y zq0ROAuS0<~yWuT1o%X&{Usqddck61kwToocly}Xk$yc{dC}<&6#nf~XVL!5adUZ3HJsxvi83dBgn znK!@>n&5Trk!*myxIqUR?1grMJ0wLw2_p%3Mz4N=qZ5z7F4@$4AaL#g6JWE9L8n5& zTo7APi-Op+15AKT8#%)ln?cM$eF?-G9bf`%vN4#TP+%6slL$o+%XWapW8+88FhB9k zJ0+!!4PcT5yW`dMz(Owf_JInx?pYxyaj*;hn-#E-i2tlpvOzIK7VO=t^8gh8=>@As zarJ@XivricaoN2At4?`#<}9lYI-~hHK<8eH>!A2P9vlFQ=Hi(+LJ$;lk1T^?X#SZP zoeqkj*`PR@p$r7CqQKnfNz{M?4WsPj8K!AG!;#>gL1&}D!7=i4fOSMu^`GGgIS^Z+ zz-kzot{h<%?5EC)g!QwMLY;l=a<1kU{NYyAyy-+AD#hOLeKl2 zKGm;b=#1L4l6}Fg&+dRLXyb>{4qlOPrrQV;5V^v!wsp_$A@7^&E9BQuf;d0A)A>#=_|g38YL3P84G#DTsyOy)IG1r{P>JetqQ*Hx?`z3gKkgv59>vd`sag`XF4FuZ19axD4cR_mf?P?Ea5#0-8kJ+N9Xbf zT}pL%{qcdVa+w}U3?Z{_Jv(KCQijKJaVELNh=D?!MJ!Yyp*z)>{%%dipL?EWf*4j9 z&@>IKbtTihX;PNfkyj{v-iCyJbz#9-&90t0{dv0V{aSi{Zfbt|VeQBI`j(>Frfc~e zdXGgen-4q|A!q}~L{>(}gwG>%Mfr~}WOH*)PXDl56CGV@9GA2Y)9kyv&9oNE-G{us zV~NH_Cp#-7(DQ%pTRe)T>`%#~ss1%YO8w5T=CFRMdEG+fc^ee!e?n7vx8bPh&#Mae ztm6|Os(P-agT39Z2N<=W9Dag03S01O;`N}CSI@D6#O_I&%(%f^r_Zn08%bO&eGU+a zGUXhQDRgY(Jij2sc9s=rTjgP9>Emq!(rVIZZe7cASb0W4@vGprAoDRK8bAnX(G3$Ida|J5YuW<_mf5=jvv~MDtI9 z!kflhca9QEM^c2$Lj8N`tDHxY5wF?MgY_s^30yc6P68)*O9#-qpK1S$$C0hjG9btf z-D=C?3=v}QA4;O>ouCo`)%*C14Xf~f$ilz&uV7b13LfQ9eE?Jg-Lz@{iUAdX?o{=^ zBJBX{#s~}S)OV;1xOH!`S0QEI9b7~!($(mX!pothL2|%_t{gau6}3U;l+IRfcH=gM zn9p%1b?`U4N2MSOe^oO2GuP0hBMm{!`AjcjR3%{TS z6t+}}Y3xN$8195keq8x%kdtrM7Cv5bic^Oh=utkC~xpvv#glTO2hU--0E3#s8$`$`!Ed|QFFZU>ut zWI(U7zIwx_l3HB^r^FlcctCCCi&xDm{ejCD0{5k8=;hk1KVn;KIgZ*Ba=a2l)K1aR zss+|Y-2kFcj&(BIs+Eieohoq%zf0FtMKNs?v~4spFl!gP}Yk5 z9*O)R>%;Aqof$ZU)8S~NfBbzGrntGujs_PmKm0m3FeUTb_?qI~@SogdFF8VTD{}hL zq~Awt2Dsc(i{|ADh*jKzDb`JL+x?HQLmMZ7coSy~fu7a~Wf_g71L4w{=;?MudB? zSZ;%#cFmdb5tzHe{R-I3=^8p=(|h+OBYb7=&*+zUdGFW9Z>;LS=BkAqKhLo(inph4 zHVOFLfnvdhVN!(W%#=cT@Xu1uMC?^Tdn0(y@hTs-yj&x2S5G$!zqhG=a@w|0opLfbtL>Ly|QK0Y`K$@ z=N9^Q#g@Km@JVo)?culNX0w3m4o4Q8$MxR3BE@zzj(5F`M0r=sOK)Ivua^vfIzbz8 z{H^0uuMGQg84kF&Ej#^fh_6ShrpijFQT)?9J9d2k!H!Y5U+i}#@6VK|u!k^hh@E_# z6}0r?#H+aJ@a7kcA=rMaR2JA^;H5~#UkUzA%?Zddp&<2|&ue}!E7B*{+~r3bMK zhy%P}FCn(T7Yp>ZHrD==9YmF2phw}yus`B6L|Mdwb1gtu(cLR}do3dSz-9|pz}TSS z5249@BA%sLC*UB_WGq_9f^C)9V@&xD|9gLW)a4evB?XP6gNACXDnY!#myj8-{5a<- z@55pwU;rZ`_r?Z>M)3j=xv@q;g?{vH`+GX`V*l4gm-aF%k*l6M#R~>w!?lh?6+Bdc z_BwUL(*<;t=%dYmV}Hi<=PC|lPL5GaZWwr4u>NQUD>Og|-C-Alr$a~FC<@QxWh>tQ zNaLk0y$SfT;G8Kv9lrmFS!|YLd=HGZJ2nC#?dhtOH?TBP74iAvRY2Xln{QgsZ=l9K z&{x`pIe_v5;2ALC2oa%5@>gNBfRrWzrCdQT<}KG0yVSAdb|}sRYtkPfU{8m=g}r&9 znEMr7dwAy<;*9|ne;$pNINW7@344@`G|h6ub>^e{vkNnJcVW%71CyRU)@5Ta16n@3GhJd8|kl5DMSDk`ck zp6YA-@p0W@hHH!K25n-3L9Ch$V-oP^X=;1x=E09&v99{-%+`$W-&J_o%@I#2XjA1lsvs& zU}MV_ztWRj=3JjR$klkv-08B|i!#UVO&T}X7TrA?; z15*q~`Mxh}Tr8z5sXwi&0>+lVT${;Mg?a#mU-!3j#O${}!nX_A&C}<)w$Xv_t>4CT%^b%DyW>o-d&Z%f_8BJj zZG5U-PWqRRgcft`oqg*lHU=&iT#KsA9G429VKk*_y%fEI#P@Z1hiZn^U-~3v+srMA z7r}MqHhw%}Y-_2)b4BB{(Ihs~^RmY$hhyoXsVB?&UTkWQx2}}gY?pZ_iFXJ;S@L+~ zchys|cb6IWIUsTZemW=lc1be#+U_SR%g2G<^A$^BB~L0x$8De&WDj+Eb|volQ>bSN zfnOiZD2lL_xpCwB^YCu-NnZT)VMyS?I&u4is4|-|$9d1RVV6jB^E!BlSv7Wg0u=gC z55vY>PY9^6cbc75Jr>jpG%0EvHceeEWNIslqrxKkw4__4i-gx*YGGW24mg^YrPf z#bqs$G9>GXSw1tsfYJF;z?;lh`alt}V&qX> zydhUueK*PJYlZb35ARLAQsxd8RNmz@hjhs_*TD<_y5a(D*>ag*ub)G5;4d){?^oVh zCE)q+$I#n0IF(M$A5a4!s-G7I>#gV573u;QqW`Mj@PqVeO-!Hf%(nbg`F^2i+xYxT z*47y2?5#YFU6pJ1@~jnaUW*~^ovSmj%ScYObMGy2dgUZxJCS!Iwzjs^8zMy6G$A>l zy})=c2(gar;QDg9T>f6=8a5cBy3c~Ewv;KpI|aY+5S!;D6uZQAzAUk9I`ei?rx=SC zGKFW;o?Wg?>^x`mM|ua?CX1WzD`V?nnVXOe*A`edOHSmr=b~CW7wikva`l{MOGSOG z$td%xD$(|t2;_N~$5fHSk7)%{YlF<#O{R!X&uUqZ_Q4AdOKG`%lJYhk0-hlf(KjpEi!l5P@G=3?~T<79wl06hUhHZY(X5|*}G=Q3saMJ zgtR$l->4hspvn2!><-O`CVZKYl69^)%`HfRU7^_gnaL%M6OQ$6<#Kc`ymD8gQYI5h+<2V+|M@}A@W(%Dg7a( ztmBVYtw%V7qLg3QQL=1FftO>xj1A(UqC-@0C1VZjSE~ex1w~d4@6uI+WOm{|$q|ZD zo=p1(H%s}@cVDxWQbek$gnsZND$MYfqsZUXQmGWc8|qt3D7h(sgRw#I$lhpp=sN~8 zJ-X|;O>BeTjacQM<48xdLS*lkN>|DL4#G9LQeYQ6w*FA7qP#gu$*ULdWU-6)BLFoc zZ(ZCabw8G)IU+ai)yBJ&~ac&KNvpw1RPJ!pBNt|kRsZZ8J~XhrP*kex=37}RLFO01e(wTZ=qcvHdGf|{d%ad;eeBJ<2o5Hhgliw+@8PO*C!6y|6sM(q;rHl%Gv9hi zRy02cjuOi0C@~d!^Z#H+kdD{=dudFhp@=An1%oEkdGum zY)eJa77>FA#w@*h-V1(B!IGR}446Zqzh><(t2Ze(BFdn|?XN}RzmXi>xoQ;)H7BUH z^|ra)zi9)nR-S%7Vs$@ZH!;WZ<_C)nJX>fIalG$6(V6pcecDeZXuxp~pFg3X_Ic;- zr-hm~w#BKuR1c7js|73HW@gJG_~SPlw-)zv$@;=J97E=$G5=DzKRWPKpl|l>(@$-fo#m52srABfiXr0QgcMzU zgiBXP_Gs@TpO4Cn)G3&oy;N;?2wgH|)3|E_uZWV}$F_fra+meO*oVU!mm_ar{XK&= z&Y5A!*$$EkX$#i}7n~m!w(!h5JwI3dYjf&cD>XkvHY$K~BGh|lnJRGF;X{B0bdzBF zMrWyFA5UqUAvHo5SoOf_D|}pNs%y>|Ou-~QeH9dPu0X%z``d$~k@be9 zv_fW-oYiB@_1a+3Adh*+zLRyrYQtsuu?c47<8fBc!1q7{tT!Q}oQzpu!Dqz?23j2t zE!?S!+*E(awzsQ{7D5Zn-4;0&{z_a>cy>5R+0SdEzfMt}OkAOqg1oIIbBUTmG2wq! zbjqtEqWA9>65kD@T#F569pa(p(3=HvWVN{^TBl0ub5#8WMhbLVeF_w@~EDf=w`~b`CIy=IR>EIP9_Vv^RhAL|pD|Ag#8a^h(o%3sivf$br~vZ-7SdToJMpxKh05$ zr%VG@P2ZU>@)9auWvW*HyS>}ic9?^S-TB>)szV;fGlBcw%o_5RhV1K!sOoSd%}N16 z{ZfQoSSm0&MKoJQlDYjPNNtNI4g|Ntuo!6V&94OsfEM)T3uvww>6(cMsqs*afcH7! z$K{fNVPcdr!H9{G+Pj+tb!$gMzjE74`Tj>3uYxr6D`;R4BUX4D$D084hq7=%Uif>S zUmdov+%A47hgHEGrMj@n*p|eAy@#wRSjzro)etZ#^^24TEH*(jRY@lc@f2E6s}}6L z8p|C8e9vaRCE|;f@apKSC2TP77ESvzM{u8Cxnh5?#mn=kyDHs>Gh8j*$(0sy6vc$q z1E|2~;A0+NfHIz7r=QL)Of$C%W7>e)z4KTrz>id71vk%$k1-;BE4{094nBLa>c-xJ zI8`%rau*XbqsH4C2v2x4FR-giB5=k2RfuRWWJM{EZA+nS#GY~p>0vmhegpYlBk#0B ztFu@rk-@YIX`D@#Hizsgv=TMKUj()cOorB^&8pntOMcpZuuVEDPb{vJQtn6qw_zuaUXiB zupT(IiOX7BtdFks6+sjMD{JI_swkdMum<)ag5hrW&P;^Dx~g(5K<8Z{BfiC?A%gWg zU7fCBxqWn;MOJnSyY=ZG^|f_E^23KUtuoh;ZJ{_#U^}9iKYvE#LMW7R4I`R&%>LDL z@#mEECUH8UMF~71s=}%=AE)kzQ8ee@vyh_E5C*D9Im*`!41bM=_ce-TKSEaoyD0i^ zR@SRdCj(v2F1ut((RT|0btDY)EL+`h!fDJp`{7Hm(9>%p%nT6uZ0WSXVDV-v1iN3f6tGM(VI$#{T;dt)*b{p%(nparsBp2$sUm&=;Z1FC>9)nFAgssr`|frs#ws9932_W_5en9P8Oo+@V|K%Qtd!G+-l%IB!G^ z*|KJ!;*v}W9k-xm; zF6G7r24?#Q910=1Lfj#fsS;>c!l)w~ZW{UcJsbMGGdRU?gf0Ujcih-<)3A@0G$?8l zaDpHdWdb<;*BSvn|Fs4{1fiD3Q6($Ij#vU`Ozs6I8dOs*Vn_aK1+bIEDR@=B&JUgD zayVlG{y)lx{rz8y!fv0n2nXQbna6d#`Nw5&#v6z;W5$nw)AFzs4mg^#0eqsLx3S@< z7LkmG;DiNlv>5sZ*day6K}aF$8#Iou{68BL?Af%>5lR`-0nU@)qefteOPByic^;*ISk`~No=QwuMEU~0yC{K68 zTl)~asoyezp`;*2IUn*B6`CX%rO-hHBM0Tce!V0XN4o3S!&#Ws&(Nt#otuV(JTzM1 z9T;iU%+2ijZ6EE!PbesHkl;K1^!Y-n(xU*28z?KR%uYeRQkvKkMttxyfcJ$oMvDm_ zytJ=iYB-jKE(ex&3x+IDDxu8=O!!j5j>*!>jG6b(?eHDT7g-d=7Z}CBZ7!W3!wi8{ zMHh9KQahwk4b3-z^KMBo1HwBH$%eN$+0Th9^l;h~x{XOW z7O!QeXvN&NLa?CkkVg0RYMX!eZh(~ptfKZAnf6rI9@Q|VG-Zzbg|L2rFTohI)Pm*$ znF{}kT*u~e+!?u6K9Ov}pzIrYb=i8l@6H5AdOkx4TYrV6%;OsS&(la(jMf+2F(-Jby!YF{vCQ3iHJElobTvV|Q znwlz;uKPWYGM!HiS+!oudw9)Jr$0@uUj(HE@DW1nPkIhpc9v!irmP=pv+o8Xz0F?9 z@(Pz7Um<)#Q6w}iY&X-t8S)_%eG$+A^+v%gM<(wh3&`c127Su&@q!CWjD^dRZf(^g zKEO$&_2$1;`dm{NM>H1T-zhjKJMG#1L;6?rJT=euFeBXPGoX-pb0fFm+Y9gNrK7_N zM?t(jRjJPfyfikB*kVZj?$_`)gNO>>A6;3!{~5TZx4Dx_5s^@%zdx8dkU% zWD^?KyU?`Cknrnt^S;{^dm*fgd6w1bztFxModO|V!&ad$P*Nt~1%WMZS)b-yHC!aP zV*_m70SaLzqU;%6cUS|~gc8#a%SPW9=1wQ$PjKS? zPl551T(3>PAG?QFRb4_C;*;m>j|4wdtt2l1tzZ!a^>30}_dj4-_J8O&gldKS* zklACwGm1M5353LgqotxxUl)GPQHyv#)8s=$zX$j$$>mXMI;|4E%ai|VCP@d`tdqRR zRkf?{bU3^*FCab18Kh@klXN(Hs%;ju7U`i&+qnj_*`_rDo@DOnm^31wl zz)=9pD7l+J=$WKL&oM8HU~@^l2H1xxDIX}m!bx{ONM>!Fe{dQ$R?T>I!R%^yG|`_I zTDVEKa}M2m#Nfx7oW|tJTICL@4R$+NtB564EcXvF&x^c=trt59V~^U1&z(@Ez^}W2 z0wg+tEK3V4E7BL=u`k=Wf|(j1CC2)ki1V~3wgrVeh5S-Dm(ljc=P=m^d&G~^2QKZZ zg(Er3N@_FEVhT6*CR}>FYo-}|_F92wJuOI8(+AQ!? z!_X4HMe0Sg&(JROVM~c&S0KJ<%E?fFGm_R@3+PWrx!0wd-jHp1=v4&D^VBQld29%U zP%>+)(&C|xI6JWM9or9QY#^x_n^4TjpLCI$kD!wr7k2`~pD(<{h!XW;?ToE62Oj}kRvm$Sf}ywy@xM};U6k<`}sq}&jDM}#xc;i7INAn zpF41cVy_$YOJoIa7Dqtf2K4H08T6G^;ZYui^Cop_^cD2vq= zgVtbfkZlVf1Hsr$Qfs$?Xr*m&$^NYIY>`{@**1gHU;|MN%n*$!vbdE|%KA47zAOs} z{@N@Ica1*x9U7Z*fT0L;X&3ZFzfJ#^tz*+e0wdfqY1<5O}poURwaHfO|o>$cC%iEI=@+9fk-ddoARt zTLIwlc8!Yht~U#?zrS!X4tTXi9tsM~egZ5X8CNm^2j@Q{3UPEx5EueOCV#DK`v*GJ zux4}73w0+3QDXxs3*#`5i^~Q7rY_uJMNJ?t-u@+k6D5{lgs_0`&hXI#8dDgGJ@hFH zI#osB6p50=yuH9b2S=Sm9NhiJ4>Nvs@M&8V+eMUHKk3qCM@Mu!@L-_5gKC}A=l6tx zDV1_#pg16YUl6-Tl>24)tr?EDqYzpu87aX5 z$GvFlyF9{!Fu|H3)nvX#8UW1%TNd8)TxCH26R(bozz$LJZOKqR(gbV0yXVLTG4EXv zIz%{Opecd04K&_=b89430ZPbN--7e;(pd6Pu-Z$YCk*K=lyfS9T<8MlDRzc^{;l#F zu^a|eSYZVga*zJ4TC=qzmH-ca6}Tv^wI}x^U!a!2rMmRg_6IU|^i~}@_V)I^ zJk0Z6&k@j3hFyKGGBa#oV4vH1HOEgH&xd>1*OpsO%U(h{StzJ23CMg`P)nRxUV7Ms zlfz5l*1tNKMZO1=$WzHV;3oplj~!A&j=)C<1(#5mtUdV({v8m|y>6&gso@y; Fe*itAL;nB( literal 0 HcmV?d00001 diff --git a/tests/visual_tests/styles/functional-expressions-length.xml b/tests/visual_tests/styles/functional-expressions-length.xml new file mode 100644 index 000000000..2827b89b9 --- /dev/null +++ b/tests/visual_tests/styles/functional-expressions-length.xml @@ -0,0 +1,117 @@ + + + + + + + + + frame + + ogr + 0 + + + + diff --git a/tests/visual_tests/test.py b/tests/visual_tests/test.py index 3e9d6f0ac..28694bf83 100755 --- a/tests/visual_tests/test.py +++ b/tests/visual_tests/test.py @@ -119,22 +119,22 @@ files = { 'marker-svg-empty-g-element':{}, 'marker-multi-policy': {'sizes':[(600,400)]}, 'marker-on-line': {'sizes':[(600,400)], - 'bbox': mapnik.Box2d(-10, 0, 15, 20)}, + 'bbox': mapnik.Box2d(-10, 0, 15, 20)}, 'marker-on-line-and-line-placement': {'sizes':[(600,400)], - 'bbox': mapnik.Box2d(-10, 0, 15, 20)}, + 'bbox': mapnik.Box2d(-10, 0, 15, 20)}, 'marker-on-line-spacing-eq-width': {'sizes':[(600,400)]}, 'marker-on-line-spacing-eq-width-overlap': {'sizes':[(600,400)]}, 'marker_line_placement_on_points':{}, 'marker-on-line-and-vertex-first-placement':{'sizes':[(600,400)], - 'bbox': mapnik.Box2d(-1, -1, 11, 4)}, + 'bbox': mapnik.Box2d(-1, -1, 11, 4)}, 'marker-on-line-and-vertex-last-placement':{'sizes':[(600,400)], - 'bbox': mapnik.Box2d(-1, -1, 11, 4)}, + 'bbox': mapnik.Box2d(-1, -1, 11, 4)}, 'marker-with-background-image-linear-comp-op': {}, 'marker-with-background-image': {'sizes':[(600,400),(400,600),(257,256)]}, 'marker-with-background-image-and-hsla-transform': {'sizes':[(600,400),(400,600),(257,256)]}, 'marker-on-hex-grid': {'sizes':[(600,400),(400,600),(257,256)]}, 'whole-centroid': {'sizes':[(600,400)], - 'bbox': mapnik.Box2d(736908, 4390316, 2060771, 5942346)}, + 'bbox': mapnik.Box2d(736908, 4390316, 2060771, 5942346)}, 'text-halo-rasterizer': {'sizes':[(600,400)]}, 'text-halo-transform': {'sizes':[(600,400)]}, 'text-ttc-font': {'sizes':[(600,400)]}, @@ -201,10 +201,10 @@ files = { 'gdal-filter-factor': {'sizes':[(600,400)]}, # https://github.com/mapnik/mapnik/issues/1622 'tiff-edge-alignment-gdal1': {'sizes':[(256,256),(255,257)], - 'bbox':mapnik.Box2d(-13267022.12540147,4618019.500877209,-13247454.246160466,4637587.380118214) + 'bbox':mapnik.Box2d(-13267022.12540147,4618019.500877209,-13247454.246160466,4637587.380118214) }, 'tiff-edge-alignment-gdal2': {'sizes':[(256,256),(255,257)], - 'bbox':mapnik.Box2d(-13267022.12540147,4598451.621636203,-13247454.246160466,4618019.500877209) + 'bbox':mapnik.Box2d(-13267022.12540147,4598451.621636203,-13247454.246160466,4618019.500877209) }, 'tiff-reprojection-1': {'sizes':[(250,250)]}, @@ -217,10 +217,10 @@ files = { #'tiff-nodata-edge-raster': {'sizes':[(600,400)]}, #'tiff-opaque-edge-raster': {'sizes':[(256,256)]}, 'road-casings-grouped-rendering': {'sizes':[(600,600)], - 'bbox':mapnik.Box2d(1477001.12245,6890242.37746,1480004.49012,6892244.62256) + 'bbox':mapnik.Box2d(1477001.12245,6890242.37746,1480004.49012,6892244.62256) }, 'road-casings-non-grouped-rendering': {'sizes':[(600,600)], - 'bbox':mapnik.Box2d(1477001.12245,6890242.37746,1480004.49012,6892244.62256) + 'bbox':mapnik.Box2d(1477001.12245,6890242.37746,1480004.49012,6892244.62256) }, 'style-level-compositing-tiled-0,0':{'sizes':[(512,512)],'bbox':merc_z1_bboxes['0,0']}, 'style-level-compositing-tiled-1,0':{'sizes':[(512,512)],'bbox':merc_z1_bboxes['1,0']}, @@ -281,6 +281,7 @@ files = { 'marker-on-line-and-avoid-edges':{'sizes':[(512,512)]}, 'text-typographic':{'sizes':[(512,512)]}, 'functional-expressions':{'sizes':[(256,256)], 'bbox':mapnik.Box2d(-10,-10,10,10)}, + 'functional-expressions-length':{'sizes':[(512,512)], 'bbox':mapnik.Box2d(-15,-15,15,15)}, 'marker-collide':{'sizes':[(512,512)]}, 'postgis-inline':{'sizes':[(512,512)]}, 'text-line-wrap':{'sizes':[(512,512)]}, @@ -292,158 +293,158 @@ class Reporting: OTHER = 3 REPLACE = 4 def __init__(self, quiet, overwrite_failures = False): - self.quiet = quiet - self.passed = 0 - self.failed = 0 - self.overwrite_failures = overwrite_failures - self.errors = [ #(type, actual, expected, diff, message) - ] + self.quiet = quiet + self.passed = 0 + self.failed = 0 + self.overwrite_failures = overwrite_failures + self.errors = [ #(type, actual, expected, diff, message) + ] def result_fail(self, actual, expected, diff): - self.failed += 1 - if self.quiet: - if platform.uname()[0] == 'Windows': - sys.stderr.write('.') - else: - sys.stderr.write('\x1b[31m.\x1b[0m') - else: - print '\x1b[31m✘\x1b[0m (\x1b[34m%u different pixels\x1b[0m)' % diff + self.failed += 1 + if self.quiet: + if platform.uname()[0] == 'Windows': + sys.stderr.write('.') + else: + sys.stderr.write('\x1b[31m.\x1b[0m') + else: + print '\x1b[31m✘\x1b[0m (\x1b[34m%u different pixels\x1b[0m)' % diff - if self.overwrite_failures: - self.errors.append((self.REPLACE, actual, expected, diff, None)) - contents = open(actual, 'r').read() - open(expected, 'wb').write(contents) - else: - self.errors.append((self.DIFF, actual, expected, diff, None)) + if self.overwrite_failures: + self.errors.append((self.REPLACE, actual, expected, diff, None)) + contents = open(actual, 'r').read() + open(expected, 'wb').write(contents) + else: + self.errors.append((self.DIFF, actual, expected, diff, None)) def result_pass(self, actual, expected, diff): - self.passed += 1 - if self.quiet: - if platform.uname()[0] == 'Windows': - sys.stderr.write('.') - else: - sys.stderr.write('\x1b[32m.\x1b[0m') - else: - if platform.uname()[0] == 'Windows': - print '\x1b[32m✓\x1b[0m' - else: - print '✓' + self.passed += 1 + if self.quiet: + if platform.uname()[0] == 'Windows': + sys.stderr.write('.') + else: + sys.stderr.write('\x1b[32m.\x1b[0m') + else: + if platform.uname()[0] == 'Windows': + print '\x1b[32m✓\x1b[0m' + else: + print '✓' def not_found(self, actual, expected): - self.failed += 1 - self.errors.append((self.NOT_FOUND, actual, expected, 0, None)) - if self.quiet: - sys.stderr.write('\x1b[33m.\x1b[0m') - else: - print '\x1b[33m?\x1b[0m (\x1b[34mReference file not found, creating\x1b[0m)' - contents = open(actual, 'r').read() - open(expected, 'wb').write(contents) + self.failed += 1 + self.errors.append((self.NOT_FOUND, actual, expected, 0, None)) + if self.quiet: + sys.stderr.write('\x1b[33m.\x1b[0m') + else: + print '\x1b[33m?\x1b[0m (\x1b[34mReference file not found, creating\x1b[0m)' + contents = open(actual, 'r').read() + open(expected, 'wb').write(contents) def other_error(self, expected, message): - self.failed += 1 - self.errors.append((self.OTHER, None, expected, 0, message)) - if self.quiet: - sys.stderr.write('\x1b[31m.\x1b[0m') - else: - print '\x1b[31m✘\x1b[0m (\x1b[34m%s\x1b[0m)' % message + self.failed += 1 + self.errors.append((self.OTHER, None, expected, 0, message)) + if self.quiet: + sys.stderr.write('\x1b[31m.\x1b[0m') + else: + print '\x1b[31m✘\x1b[0m (\x1b[34m%s\x1b[0m)' % message def make_html_item(self,actual,expected,diff): - item = ''' -
- - - -
- ''' % (expected,expected,'%') - item += '
%s
' % (diff) - item += ''' -
- - - -
- ''' % (actual,actual,'%') - return item + item = ''' +
+ + + +
+ ''' % (expected,expected,'%') + item += '
%s
' % (diff) + item += ''' +
+ + + +
+ ''' % (actual,actual,'%') + return item def summary(self): - if len(self.errors) == 0: - print '\nAll %s visual tests passed: \x1b[1;32m✓ \x1b[0m' % self.passed - return 0 - sortable_errors = [] - print "\nVisual rendering: %s failed / %s passed" % (len(self.errors), self.passed) - for idx, error in enumerate(self.errors): - if error[0] == self.OTHER: - print str(idx+1) + ") \x1b[31mfailure to run test:\x1b[0m %s (\x1b[34m%s\x1b[0m)" % (error[2],error[4]) - elif error[0] == self.NOT_FOUND: - print str(idx+1) + ") Generating reference image: '%s'" % error[2] - continue - elif error[0] == self.DIFF: - print str(idx+1) + ") \x1b[34m%s different pixels\x1b[0m:\n\t%s (\x1b[31mactual\x1b[0m)\n\t%s (\x1b[32mexpected\x1b[0m)" % (error[3], error[1], error[2]) - if '.png' in error[1]: # ignore grids - sortable_errors.append((error[3],error)) - elif error[0] == self.REPLACE: - print str(idx+1) + ") \x1b[31mreplaced reference with new version:\x1b[0m %s" % error[2] - if len(sortable_errors): - # drop failure results in folder - vdir = os.path.join(visual_output_dir,'visual-test-results') - if not os.path.exists(vdir): - os.makedirs(vdir) - html_template = open(os.path.join(dirname,'html_report_template.html'),'r').read() - name = 'comparison.html' - failures_realpath = os.path.join(vdir,name) - html_out = open(failures_realpath,'w+') - sortable_errors.sort(reverse=True) - html_body = '' - for item in sortable_errors: - # copy images into single directory - actual = item[1][1] - expected = item[1][2] - diff = item[0] - actual_new = os.path.join(vdir,os.path.basename(actual)) - shutil.copy(actual,actual_new) - expected_new = os.path.join(vdir,os.path.basename(expected)) - shutil.copy(expected,expected_new) - html_body += self.make_html_item(os.path.relpath(actual_new,vdir),os.path.relpath(expected_new,vdir),diff) - html_out.write(html_template.replace('{{RESULTS}}',html_body)) - print 'View failures by opening %s' % failures_realpath - return 1 + if len(self.errors) == 0: + print '\nAll %s visual tests passed: \x1b[1;32m✓ \x1b[0m' % self.passed + return 0 + sortable_errors = [] + print "\nVisual rendering: %s failed / %s passed" % (len(self.errors), self.passed) + for idx, error in enumerate(self.errors): + if error[0] == self.OTHER: + print str(idx+1) + ") \x1b[31mfailure to run test:\x1b[0m %s (\x1b[34m%s\x1b[0m)" % (error[2],error[4]) + elif error[0] == self.NOT_FOUND: + print str(idx+1) + ") Generating reference image: '%s'" % error[2] + continue + elif error[0] == self.DIFF: + print str(idx+1) + ") \x1b[34m%s different pixels\x1b[0m:\n\t%s (\x1b[31mactual\x1b[0m)\n\t%s (\x1b[32mexpected\x1b[0m)" % (error[3], error[1], error[2]) + if '.png' in error[1]: # ignore grids + sortable_errors.append((error[3],error)) + elif error[0] == self.REPLACE: + print str(idx+1) + ") \x1b[31mreplaced reference with new version:\x1b[0m %s" % error[2] + if len(sortable_errors): + # drop failure results in folder + vdir = os.path.join(visual_output_dir,'visual-test-results') + if not os.path.exists(vdir): + os.makedirs(vdir) + html_template = open(os.path.join(dirname,'html_report_template.html'),'r').read() + name = 'comparison.html' + failures_realpath = os.path.join(vdir,name) + html_out = open(failures_realpath,'w+') + sortable_errors.sort(reverse=True) + html_body = '' + for item in sortable_errors: + # copy images into single directory + actual = item[1][1] + expected = item[1][2] + diff = item[0] + actual_new = os.path.join(vdir,os.path.basename(actual)) + shutil.copy(actual,actual_new) + expected_new = os.path.join(vdir,os.path.basename(expected)) + shutil.copy(expected,expected_new) + html_body += self.make_html_item(os.path.relpath(actual_new,vdir),os.path.relpath(expected_new,vdir),diff) + html_out.write(html_template.replace('{{RESULTS}}',html_body)) + print 'View failures by opening %s' % failures_realpath + return 1 def render(filename,config, width, height, bbox, scale_factor, reporting): m = mapnik.Map(width, height) postfix = "%s-%d-%d-%s" % (filename, width, height, scale_factor) try: - mapnik.load_map(m, os.path.join(dirname, "styles", "%s.xml" % filename), True) - if bbox is not None: - m.zoom_to_box(bbox) - else: - m.zoom_all() + mapnik.load_map(m, os.path.join(dirname, "styles", "%s.xml" % filename), True) + if bbox is not None: + m.zoom_to_box(bbox) + else: + m.zoom_all() except Exception, e: - if 'Could not create datasource' in str(e): - return m - reporting.other_error(filename, repr(e)) - return m + if 'Could not create datasource' in str(e): + return m + reporting.other_error(filename, repr(e)) + return m for renderer in renderers: - if config.get(renderer['name'], True): - expected = os.path.join(dirname, renderer['dir'], '%s-%s-reference.%s' % - (postfix, renderer['name'], renderer['filetype'])) - actual = os.path.join(visual_output_dir, '%s-%s.%s' % - (postfix, renderer['name'], renderer['filetype'])) - if not quiet: - print "\"%s\" with %s..." % (postfix, renderer['name']), - try: - renderer['render'](m, actual, scale_factor) - if not os.path.exists(expected): - reporting.not_found(actual, expected) - else: - diff = renderer['compare'](actual, expected) - if diff > renderer['threshold']: - reporting.result_fail(actual, expected, diff) - else: - reporting.result_pass(actual, expected, diff) - except Exception, e: - reporting.other_error(expected, repr(e)) + if config.get(renderer['name'], True): + expected = os.path.join(dirname, renderer['dir'], '%s-%s-reference.%s' % + (postfix, renderer['name'], renderer['filetype'])) + actual = os.path.join(visual_output_dir, '%s-%s.%s' % + (postfix, renderer['name'], renderer['filetype'])) + if not quiet: + print "\"%s\" with %s..." % (postfix, renderer['name']), + try: + renderer['render'](m, actual, scale_factor) + if not os.path.exists(expected): + reporting.not_found(actual, expected) + else: + diff = renderer['compare'](actual, expected) + if diff > renderer['threshold']: + reporting.result_fail(actual, expected, diff) + else: + reporting.result_pass(actual, expected, diff) + except Exception, e: + reporting.other_error(expected, repr(e)) return m if __name__ == "__main__": @@ -461,32 +462,32 @@ if __name__ == "__main__": select_files = {} if len(sys.argv) > 1: - for name in sys.argv[1:]: - if name in files: - select_files[name]=files[name] - else: - select_files[name]={} + for name in sys.argv[1:]: + if name in files: + select_files[name]=files[name] + else: + select_files[name]={} if len(select_files) > 0: - files = select_files + files = select_files if not os.path.exists(visual_output_dir): - os.makedirs(visual_output_dir) + os.makedirs(visual_output_dir) reporting = Reporting(quiet, overwrite_failures) try: - for filename in files: - config = dict(defaults) - config.update(files[filename]) - for size in config['sizes']: - for scale_factor in config['scales']: - m = render(filename, - config, - size[0], - size[1], - config.get('bbox'), - scale_factor, - reporting) - #mapnik.save_map(m, os.path.join(dirname, 'xml_output', "%s-out.xml" % filename)) + for filename in files: + config = dict(defaults) + config.update(files[filename]) + for size in config['sizes']: + for scale_factor in config['scales']: + m = render(filename, + config, + size[0], + size[1], + config.get('bbox'), + scale_factor, + reporting) + #mapnik.save_map(m, os.path.join(dirname, 'xml_output', "%s-out.xml" % filename)) except KeyboardInterrupt: - pass + pass sys.exit(reporting.summary())