From 80491fac3c476788d90010812c9ba0b95701e09b Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Sun, 5 May 2024 05:36:31 +0200
Subject: [PATCH] Refactor and extend tests.

---
 scripts/pre-commit                            |   3 +-
 tests/__pycache__/conditions.cpython-311.pyc  | Bin 9550 -> 7905 bytes
 tests/__pycache__/processes.cpython-311.pyc   | Bin 20920 -> 23173 bytes
 tests/__pycache__/utils.cpython-311.pyc       | Bin 17892 -> 20337 bytes
 .../versioned_attributes.cpython-311.pyc      | Bin 9550 -> 10579 bytes
 tests/conditions.py                           |  30 ++-------
 tests/processes.py                            |  62 ++++++++++++------
 tests/utils.py                                |  27 ++++++++
 tests/versioned_attributes.py                 |  41 ++++++++----
 9 files changed, 106 insertions(+), 57 deletions(-)

diff --git a/scripts/pre-commit b/scripts/pre-commit
index 6f84c41..2aaccb0 100755
--- a/scripts/pre-commit
+++ b/scripts/pre-commit
@@ -1,6 +1,7 @@
 #!/bin/sh
 set -e
-for dir in $(echo '.' 'plomtask' 'tests'); do
+# for dir in $(echo '.' 'plomtask' 'tests'); do
+for dir in $(echo 'tests'); do
     echo "Running mypy on ${dir}/ …."
     python3 -m mypy --strict ${dir}/*.py
     echo "Running flake8 on ${dir}/ …"
diff --git a/tests/__pycache__/conditions.cpython-311.pyc b/tests/__pycache__/conditions.cpython-311.pyc
index 4dd00fd37a9985baa01f9ce133463f14ef0be350..d671a082995580256e7bbfbd44942bda600eaaad 100644
GIT binary patch
delta 1067
zcmZXSTSyd97{||XX2-J^wN+PlQ`gIuCYxnxTWg8kNGNnoyKccY?yMIyg)>V&WZ*;5
zg^1!Sf*|xEO6b94vA5_YqF!QG7LtXa9(wT2sHckP`@Cf0nR9;sIsb3weBYTfAC7)$
z&V81XV`JDJ{|xlJ$(zn?vYcqg=|dJ{VQ#Q+mcheHObuHMyP;lH!y2juH5*k!6{y*$
zR#bs%L$#vXQEjLWL+N6*4w$qwyW69jQY|+Ns)FOY7lOi@Bl_7Wf5Pu@&f*G;Ya8K)
zIOnoF&0_31j-|%gD4Wng*IbGg&xMr3t^H?ZFIj>!L&c<4_+zavZl9;OrJLX(R3T~w
zglr{Tg8^GbpazYMC)yW_4n$1-QvXnIWVk1CDJISS;h~t3QOvlkRpbVGOdA-{Wv`jx
zQFv>MXr<_x_rP!WTfaJ7ca58&+acf^ir})ntgd=iR8Ne|C@ImH7L7^KI42w*#iDy<
zCYlmWY0;Ei=`fvN!XH7NvkuNV+^WIjDs2zWIyS0C*7D?cz7=le?(SUOO?$19DO@VO
zM-E?%#P#mMSVRtwWV}o6zimX;#^rV_UFK2!bSQ8wuOmbs!aRZ)W1p$i%2`pF627$X
zC53OXc>k>MPqxl<r9?0-f=Llvb=zJwq(n<vv?NzLd~tTbA?IaY2d|wez60*%Pw_2q
zpkRpaO1voO<UE*ATvH17L&DwU^<!eWl^_tA>^|Mp<8dhulT`zDPc<&F)6>nH6AwI}
zcuS5fqllMKPN*Pggi69rLVyq?>?5=g4iehnWl3f06yA>gyXMq}q}ni7ST@$Spjs_^
z7uZ@9sh0hGfvuw>v8(im!mDAl{EVv(m&_=Gv7yCMGKxMpD7V6Vxz0}}j#a$jHODD^
zF`<*tML0n?g_wVbz(bX%AyDPxVF*_RwF~H(r=X*v9^O|S^_|D5)Cu$}%L0Ov5L!Ve
w1biJl1lN7{k)@l;?7bMGb2fi5IJ{}xznl9O*m~UE_Kn;htD!iDqRo5$0u5mf;s5{u

delta 2421
zcma)8U2GFa5We-<cjuq8lQ<@JVuy3$gqlD?5(weHkfh2F4Wv}G4V2*cF2p7{)!mV(
zG|05-LyDq;SR{CW;)j&BLKQ`+)T&RYLRDW{`K*&1SwaQ%N8&B0RI2*Y&YpjizlW~u
zZ+7QqW_NGC8T;wJpZlGk@w|<KapTvHu?F`8=WfgCVX~woY8Z*sut`M2v}7K(h$hKA
zW)kTS&BKi75G^2CkPJu;Bn#3Ck^^Z2X$5HqX#?p1X$Q%R=3`Wt$G0r|dZUQ!S{O7)
z^8ND#zzs@W_Dn=~VRf&hxrk;^ytGQ0a4TIYh^CcBh+1oex7WCN6erslBkzhEnX)p&
zeAR=bXjvN*PS0G}(Ira}RT8=;6Jkt_O(ultm^v;fljkJixFjo}k;H?lD#u38gV|JM
z;=H6Z59Sy(rcOw$1=*Ifh>{X*&5O3MS!Uo^vKJsnE0UU&eJ~B1<T9c`QN;vO5ae>Q
zbWauc8HpB8abe@@lA<baz*)KvHLqjf2Tx@T;1cz_!*f;q=*ZlWS+vMm=h!Ru%l50i
z8W+&HK$;5>-Kq7Ie3tWNIN!}p8ds-tb!o1Sn69IBmCbUp8}=Gpk!Ny6BhL@<b4#t&
z7K1#^qmL2ht<~2|PTawq@R;wyP4AK08Uu1erOYJDL6t8mDQd<PXN#*iSD4|YvMLg$
zuiRNJT14iI>Ho$uN`ORJFP2|qMQ&{@(F%01<4Sg0@EJL-+(=*(ftLt`0S4tdK(IQ&
z)}SqTnicl6fFj2zld>v_`E;}6F-4t}-_0?3uH-XM=QGcoosP(76uAl9@K5Xr(*P6Y
zH{8ZGxt=)6vW`&35z-uux}y<~aqUTOhV$OukV5n9yelhoWP}b)=+uQy&9_VU?OLp^
zOZBFGTc6X&+VX+|SR(L*b7Z-aC$9@TvclesuvZiI>%xA`cR=?YSga1FcBXwz#C0oi
z-AY`Sfst?g)VYB<4zJ?|h5y~)y=E%IE-MHpLkbsa?m?9Y4>2{>suk{07*MR1;#_s$
zh}B!EnEI&?&<wS#URgqdq)O_cFyf^cBIydH7<YkV_e%BLO}+ieMUzSjr|4Ho_wo&9
zR<Y$G4a~C_eF_r4Oj|-KDb2!|q2nc5#+^lN%7u}uE>A@0nQO^ILX-Qfj#awdda-In
zvuIfxYwnK702NvMzO^%%GsVPpnHVn5RYu39=-H7mdGg$d8X29CM&!w9c?%p`ZYQuE
zAZLpyv4o;V5>ZJuxJt(oYR(FlBh%xOEE#<&XUqF1BIl%>b6LP15^)C!)<J-@GkGV0
zP69?tGaJM<2%V$B9AZn*ETt()RLo!{2m-d-jwah+u6Ur;U!n|t1~Xhx<LY&;KF!rH
zuB5)v$F4A!nOSviM&tZC=TCF~$1dN^;H`#F-I}XGcQvHB!e`N4b$xHv9nQGJUxxL~
z`yZMgMjlC;`>^glyhO3qRszY^*{;XlpzhuFRpr<IZxzkkrF*+(`;4OVXB__9$5Vat
zNA%F1Z0JxXbVv(z>!EHf(4z->7Hb<n=hA^zs1?2)YK3oyS^;1vzC7zFI_sfbdgx#_
z)SC(QYN38T)UO2w^uWMkZ9{50y)n>2+*^q|9H<0*;e2?GAHx6G-a`lRlwCtTxYuzX
zZNq;%5~y$C4F4KJuP%J&yicQc9Ix12TS~A@x@C?Xk0=rNjgpU%ytLr&D;iM~epWGx
zh87OHA0y<%n>`yt1~+ySlO6)S1O^BU5*Q+I5|4X==m&h+Q{BZ{%2RK_%d?cPh6=j{
zTE$AJ<}Glsl~B8o_Pj!)W?bca(?fWaqbH<9o^y0$VnW`IKlDXVY~c^zBedx>IY1SG
z2!T-oQ34XcvmXHl!?ZkxwVHYq!++K6LMm?YC+p7=n|BD1_G~mR<A+r~MV17>$A1)^
v!gYb`fZqfH_9@Vk{~ZdA@GpTo?E?taFH!5`)#m5MlNZaMpEThwYCHb}4@xu!

diff --git a/tests/__pycache__/processes.cpython-311.pyc b/tests/__pycache__/processes.cpython-311.pyc
index 92b1fcdeb833fcab2d01c5aee9cac2ce7d97928b..4f4c7f10e1ab4079c040f28cc6c0a605611825e8 100644
GIT binary patch
delta 4316
zcmd5<du&tJ8NcWHb)EQ?#Bt(09EUs_6XLwd0?xw;(83_)*#`|Z#&*DNn!vpmLYX7e
zsZ&$R+H{AttZKJZq%;g#oF$p42GXjkYqf5g9bJjY6QciY5}P)KmHtyr+rICbICgkQ
z{clIUzweyy{LZ=O-1B|k`F!OZ`OzFPe4y87F;F)BXYIhhoYRK4HCY;LL;3o*^jDge
z2pdoblmRZFwI<bo4{Hr5mw5xMU-^=9Z<gQaSA)z3sR5}2$$`{^)PgjC%mQfynGMne
zQU@{zq&^oaxll2H%=4>uF%HvAE%!G<KXX~wcUaocRY4TAysC&5(?oHBa#S(OhS{(p
ztQ=5mVD^=as=}%XmcG$Y0Q^syEjGfOE)}(@O)+6Mq*`i;I{HafnKivv@z7pnM(^!<
zdtq2{kR4Uy`$1}8B`CQtq3%YDHOzz*OYictFEL^D2If2{F4BgA0wrO9_C`@bVLD3z
zEKM4V-fS$jEKj0@ZZ54`jgzGBH-d_=I;;tE14{UesuOE=2E?QMkbOHp><b8j-8<yB
z2Svdy9^wN5d++d&KPU!=hwMT?6r6oNvb123YIySC`FcCRTg*Ww%<QWeC1M&UOhT!a
zsAL%WX_X~%xg=fv279`47sIcHIW8y?SwSH<B#7Q2Um&3f`aJ+c;srLrIvWziC$PY>
z+xY?z-)6Z6gM#QAe*SRhiTd3EK@^@0iibAzI1hV<2Ry!|l?zVS;IPj-D0D&v2lU~H
zbufeA1~|zqGNh)Lq+_)FMr~`<I~%yRD_-lCYTb(pq)d@Zs&rbiPXFn&)P1MV09IA_
z;E%v}!K(OPTwmI5`AwksPTRy?x^R}%E~~n6mq}~@F?HldO;faSw)I*?yrxsC>4a^9
zdSb`qo)j-N=Kpz{of+G#cH=gaxEDl}+;B8U-Lo67HOC!YlA{Z@3F-;&WFW;$jo~qH
zIkI@PZ5}<JUyIO&(2am!lkWkbzssqOIJCS473%>KtgjKCCU~0pji^w8(|8(_qA4kw
z1)S8rRAfs|7*|;AiQ<Qta~+Hqeg<B3lKDobX7uLq4X<oFy={!pk-RgJoV@X!<J_2P
z;ob_Tz0MWRbA@Nk@07sCQ#Kzxnrz*cb$4Whx^@GBIw14{e#L2D*Pqgl`_Bx5B4rlQ
zjmZ`a0NtI4EO4}29xWdQ)N!=olwn*v69#_jYe&)0palZ};dRNnwnrY^Bfq*w9;`m4
z9urT8<6McvmBhG`1*2)a>TLdmDrT&TaaHoML3E<~*O*xdc+RY1y(S2;Zj!u4Am%aj
zy-JJHuMm~!e6+Q`Na<ImH&mh;dlbN>A6criAy$pDaC<06Rn*u}NGFU2I+bl;Lz<uH
z^A&7JOB)L;Y6$JjL>8U4m`x(aq`M`o4#CyYY%ydg6?EKGPH%SSujK0Q<tiV<HQdWp
z0oT^$S3@}GzO|s`*qws+SfE};2!wpVDVyyrFdBw0L$D*11N6y(*I}eXIYs*uR^Oq3
z?>P^Q4h|i}D0(cw3lRMS{)9ph`Gjg<aM&yIJ7Hi#b9Bh(1-|Sm3DtoYJVAfbPtZjY
z*<L{i@Z!cJN4<jywJ^+!0YA0n+Uqp3$0XFxjd=NkLeg`T;3$m=#3mV=6NDEq1);&*
zy&5?d77_aU-0I*0r@PKo&vVriBXf#4*CKH(F|K7<J38l!bL%8-U5s0|tUW%LALrU6
zt}Vv3E!b9Fw>8b%n&P$=$<`9*ipR)U%eZ-5TmU20p3=UOeL8zAn~s_*Lb|xMPO{d0
zcr5C_5WWP~=aM*AjC08|qc6Q{nIMzexOKH;UH##vXv>AIm$t^ac8P0`aqXF`thlvS
zveth1M0CT2{!9I-Rl-8yNB372vn~bovTNvT+aQlgGt`WRBGXXyXs9G<s*o?_G_0ck
zZ8lMBkzP+i9DG5!h`IE3eVLvKVOWz3SS=($z1d6ckZ!5wSHkU_8hIX)i;JlQ15&8p
zjH<-qB`(8+4D@!R*%DTrhs)|BURZLG9mAM(3^cR51so#>4OlOxD`~lD6}c}tH)-wZ
zWZ8@E&(6D-jeca)p1vyQjOuTxrQ>^%Ob1A?L4TjaoG>R%e}Er;-XnSs3<f;>@JPaz
z)TZ3PliANd1smg^MnIo<;9Zf>!epKiaFzfcaR4)sm3+sL_xZaHWLPnCKhC!g;aLO^
z!hQfp(tl*X;SZqJhu{ZDDBvx80BW-D+`VIxS4^=8alwO0o*A;d727!R2#wWPBbh7M
zf%A9?-ZNjJ)0NM2<#Db;;woZXg>2fj^IYxJqjS454PMr6gS(dNlDMuI*R{-jY%Z|u
zLie~~B;5~J#`_ya>)G;ms@~6w8>=Ka<U`bl-$Gu&8Q1kZ$9$e+s#03*l2$*uu-X|V
zv#Q$)Vs3*g#oV^YsI^@(jP-t_W^xK8Q}u*68IJCXo7yE)`<Qz{XS%M7l+5c&-hE=i
zJ-Ibr+9;Ja&aJ&tIqjNt#dY11t~;jdmT4*0=6I=7Ds|4OqvEt~Ru|WGNV<-gt|ODR
zC0<%DmDbN$t|+HVW=rC_PD$4plYfi)rFF^I*UZQHS2?nW9<!}7@pz^Jf{1XGPT6)5
zKmE6Dhkg$zc5mXHs2`zw%NmO?8{sk4OUqEuf%$&=epxShf!->6nH-ooV*gx|on}n5
zx5i=WMxGl%o~56LYwV`2*xm*pV7#!~=|}DY`e{uAd3EMa%`ukzf<9OKM{<s~ulbTZ
zOI3A4<bxTp?ny!}&iujIs$MziahlUwX^P;a7;ktC?EEuyW9taHJaet}8XOe;L3>%x
zDC*^Xgs~=PU$R>bVDm7-%LqS47)PK8Zy~&m@E-l5y`1eL^zZH6ezU52B7b5es*FB8
zYg~Awc53rv<cjjj(^rj{%|C`2#;VPbVE}I>tkJ2~FEW`>VpM?*Wx}eNu5}@z-i`0x
zLoct-CvN)L`ZoO&pm4Cs%+O1<E`j`sj=Ij8`9sK*Pp%$neGbBh=t;GizS!{$xlV6%
z{IK+=$oK#O&pDI(rpz7h+(Z66^ViNWTh@(~<-<FUP5Cqb9BcjbMRz5f)p_?ma&t!6
zLrC2e>VJuF3E?sV{_&FSPYx9PIcy?)Nt=3KB<E&kd*4)nRepc-<?Q{~cLKpfRa@Fg
zKkeG`Dp{QQa?4W+!>>Vq>kEKBhl2l@Hum+iS%kjc7pl05BR)Y`@vdpqA^d}uJiePu
s(<6^hspSPs)3WWQ<a64w{V&Y}EU_;#_s4PPZMo-8djC!p-Lu2@KgD5FR{#J2

delta 2676
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
KJ2WV>&HXRN>vi$~

diff --git a/tests/__pycache__/utils.cpython-311.pyc b/tests/__pycache__/utils.cpython-311.pyc
index 722fd5830e2c3aa3ab7c2903a319ed97db0bfa4b..5c85fd88cb170e68dd44f2a2701a756976989410 100644
GIT binary patch
delta 2663
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
B!&(3U

delta 904
zcmZvaT}YEr7{`6Kx$RZvx08_{*@rSMbLnQKITIyk4GAGijMusI&NkHLd8ed#A!&4>
zl5kK^%nt|+p(0L15)_081$`LQ#Y=Z}6$Bd5UC?>9SzUB4e&;#Q$NzoKbKac=_%aSD
zs}@UAf>`ArU4gBG4^v*4;X4cK3fQ*UAz6uO%+QuZtgJ+;$gvWOIHi&l#Xu5?F<>C6
z;+)3jC0lixu+mAoB9ROc-OVtQOySQUR+1(5%s+ku$rk4<Vr)&Y=kRT5CYgV;z1Nwv
z#LhuENZ3YhAGC5;-Z4Y6CQ&6qgUWzHm|A!S2!CFf3jAvE6Fpqvj?z8)@($5H%|{dq
z*iCdV+P#P{!iMl63K0P|T;_r6e6#GXu1M3XLcRn2sGylH2h~WJ4%+oGm3YOJ<04G*
zuZ}l5nBnV{X#m;mm9rH3*-z*G8iM6rh#mw*3?i-}DiMbe`w*^O91w<jixJmT)>Ku)
zA6M1mZDrZt?Ne1*X1}US;SRUgtODF%TPJg^H${PF2!(^abPPqB5ED#a>wtUASsQ{;
zzEpbzV4S^km%}K7IxleEQWt`faV#}arLSL6Be7XcWA%){?o~(8F~>fiIu7eRuYN^m
zWawFBFB|f`C_rx`W)ab8|5b>Od<jD_8MKxKv~;D{A0`Ts17X@D6JNwfS6F4E8=mn<
zW19{Z*xS?R;WaO6It-SsxmjF0Zqd^KYxfk}umwBNHQeG)Qh?eI*u2LLAJ`|)IrDHV
zXOTIZ9Uam3`Y~kzAqi;4aA!#IN1`h9KDv)0@V}>zFu@X^x?kz;mSyq1N#RvNpf2`k
zBf_MJWxm-w4KTvn&x%QpunBJ-Z16SjC8!tzDA-Q;Kc_D2L?b``jSuPBiI%G0pndfU

diff --git a/tests/__pycache__/versioned_attributes.cpython-311.pyc b/tests/__pycache__/versioned_attributes.cpython-311.pyc
index 2e15b713e875b1326456eac2f8e06abecf708c73..7a33722119492d1373fd69099c33e3a4370e313e 100644
GIT binary patch
delta 2321
zcmbVNS!@$W7@qO&+Uxtk*V;+!#1@G$0jd;eLP{_s;R*rbq!s2chTVjq9I##xqJg9>
zQqzkjnzqoYsv;g*Bp#Y7t<<;jNG00Z?MjU-RiaXbTB#3?$^+ts{<D@z97-M-d%v0e
z|9|JdzS;e0&#yhUFRfM+f^qxdrv9LB+UCcF>H0%1(U`L7&`u<pt{~AYStR@PRpGEh
z6InoHm2_V)2;G9KG*V7YX9JyGGAz@%G@S!<PRX@Qw@P#+QEb)M_v4sc!pGU3jzrho
zAGiVI;GBthSC8xFJ~rNA@Rqr>HLb@x=DuIW>u`wN@w_p941B+Zt|1Afu!vH+J|yB4
zGk`?h4V+>nPSQ(;iw1;*a+FBoMWz+*BxA}X8YfXd7WG#wDYIx44OiHd1!f**>m<5>
zQ#J_9RIv3*Sta}GpmM5xds2}fh4+n$=Z2)PA~7H*Q;fSc#>jryRHlC9dVqpOl=?I0
zhLrUA%urVLfT;T<1}qOfENJcieMEBJL3RwCW=V$ilBBQQ1~+`!PGqL9`azvGl3Tvj
zdL77PCi0uFrj8#R8C25QvqQ2Ogaxw#QKrviWNAc^A!Q^t6TiPcycL!g-IXb<%SuY$
znG9&M5;@|pvtEyW)|lrTRK6j{H;}jeRi3EYviD9xZRuWMu;&1NfGCn#e}wxJVz@@`
zR!8g*CyhrNA{NMT)<;GS9A=195HL&53N?CBCo&=?`-M2UP~&-$rwOA0bO~!|FEPsp
z=yMB#5BA8LJ-$i@WnYMd0-GwmvnB73tL@L>rs)}OD)M6&IW(YC>?9P7a~$wPPxc2x
z>$gB`GUZi4UuwbMv@+c>UXD;rkU}$sDhh4nM)0U3zN{(apix+xIWL_8lk6CfWdarT
z$Y_1f_<{8u>y)T^>u+M!yC%=aRX(2M<79W$hfPs65WksF1M70a`q@C9Z&mr$9N&76
zw><l~$5n?@PoA4))eVW;wd#iUoY3*R5SlUNg}5rjq4CB>=)1A8SP8Nd0<0i2rJF|P
zUsmJ>?asD<r?PXp#m>z;7YV{*q?pOL&u3>U+W^PGRw52K)do51@KrM+C*sOCOFKI1
zyQCY#Gdy|S79~H|I7!jgNUR|{HdA(S>=-_6B%4DqxOZ}%$YO^P_$+UaP8-Y187skt
z4FP4TA#72pCe1-7rw3*jNG#mEO=CtUm}vBnDJ|p<fbN)WIX8AuT^j}M{BEbKo#aNi
z1MeY!g?BqPKTQ}v3D-JyTn5W*m&TZt`aZuhC%ojVT0WTD(lsAzRAVjQy`aWk1`_z%
zfCRp_N%KAOc~y|yul)hr$!wixug2$Ua9x1+pj_bkhek6>!JbZMMn*=Jj50Vnl1--z
zuH?b4bZ<wpH{F}q-qn##_V&mLni_pG$$KgEkX)T-d<QJEkObN$yQp+?8IDlJM*t5e
z;7pW%^X!@&yJmj%#+lKX(TT39=v4N4-}Gy$E0SY3!avV$oVV9b>?*PxcK{dBifD6l
zF5tPFTMBE*!ALC`j@ZeIUhg<P-Ov4{VSx`^!Lg))owQo=OR#B-8Tj!o9sjfqeEJC;
z3vIH-7+T@(m|3>KOunsij6W&4oCJ~FOQ8>-;9geb&aVB5-cp$z)QBG0QdJMp6@~ZV
z%2NO3g3`HM)TWu?nc-zcZOR4Nraap;Z;wpuqQBCvbg%B1n~X=~&R1Y9rvM7fAbf`C
zhe>u*(0Zx4t_<f9-#V;)O}EM!u%q42?jw!SH?3Yahg?O6!4I>Wd=ou+VjXTNqNic%
c*aDS4SX7<B42~Aj(=c^;fl43zk4nqsKTiD~=Kufz

delta 1579
zcmbVMZD?Cn7(OStH#zyZH%*!}A2(^!rfGVcS+&;nLu=b@-A5VK+3usk8N1%Q+6h~|
z_d2AcTC`xDqABmd{t@C2wIT?k2t#lnC<ro1Fi5EsEC@10*W!K*Vd6PyQ<{DJ@lEb?
zbKd7Y?|IMroRgoP{c%wIR1oZlnsUAE>=)hzF@V2XNQ}O2LWhuIn?s6Sb*f^JMU?Cl
zGeV!!XUkHqQk;XvIaSkLTvdq^C?~4cyEwPv8b)%}bh2SY)s5&0RnsRgoL7}-zhP*T
zXI@#Z!yXLZnQr6i<!k15EI710X#d`fA6u>#(-zAUbb0+tc-kIV&U*jA*bkYSHx9Q`
z?_1~tq@om7P|Bp>lv%OPqqA7y=A0=`u`2u=m*VN$Lf@8o^eRqSX&q$M!OGB2P8u&B
z*f$NjzdoY*XttqoytUC1@)X(D|Naf~{z<qahM+Yn!dPIhS20&^FoV(rz6ms00yJK>
z!JmQJm^ggwXnJH|cqBd2zwhXP=AhK7!=MYNr^Yn(yrEg)p<p8NB=t|bcNNsCtH$xE
zlhmz`f)Q+J`>?e@<RX#tL|&8RrTT)jrzq{2=ZYk-=55Lu#YD$SqVsBO(~Nz+w-5y=
z24naljMgP+SKtcY4CxT>*wHb^!AHc$n-sIc!P}uE{KNUU3_53qmr0EmqX{&F*^rh{
zvWj@O6vR9n3;W?)-pA5kkoLlHj|Z+x!v9Z16s%Y#Oojkg!b!fQ60C>o+SyUmx+$z$
zw!79v2RBU2ouDuzTeTP)NDRUZdf?&6X?ycdM`2Tt;`-P{^?Azbhp5D}Xv2bR!n?Nj
zg-b$qyg))l63UYhtVb@#V~f6=y+D#hlFXCjuf%yz*a~q%r1n&8Y*AkfeSBhRun_Mk
z#ybk6vq(Dg<uCNqNjO{9;A<%YS&8<`1oS61!Gh$+rGB?zWY}nB+eZ7&4qnNaK9vV;
zOBX0ewY8Mw6-y<30G;;Fm@+tLg-w?arm9@<bJXo1<%BsK72XRjUKD6(({r?qGv*mC
z12?07ONPtfa|E8MmtiyNGZ}t(t=_+Du5){CIAr+C2@zs*%A?#)2>cLsZ>#u7Lswr(
zMJ88CN{!tTZ9fAh=8!DxlJFpN_b{+B=wmPdpEV5N!*H|Vh`qf+S9l>-bw;N#`r{>C
zA0XHLB&0s^l9)9vX9}dTNE-8`ajm9#$y=1WR^;xh`{`}+_hWjUD8h}{@0dWL(dS^-
zRXf7q8F)1Ao9JhYv%if#&BMGMWf)<^OB8O;(gU~kS>ampT+0T>^SvABK_FK1T^pzp
zT3|gMhQH!=xD&UVhhz^NOlY_lt|bESOCo4LMb}|P=t1~5@h0ctW<_|fdAuWuyEo9i
QkZs*$-dp#fG&fE2AN)djA^-pY

diff --git a/tests/conditions.py b/tests/conditions.py
index faaeb87..45c3df7 100644
--- a/tests/conditions.py
+++ b/tests/conditions.py
@@ -25,42 +25,22 @@ class TestsWithDB(TestCaseWithDB):
     """Tests requiring DB, but not server setup."""
     checked_class = Condition
 
-    def versioned_condition(self) -> Condition:
-        """Create Condition with some VersionedAttribute values."""
-        c = Condition(None)
-        c.title.set('title1')
-        c.title.set('title2')
-        c.description.set('desc1')
-        c.description.set('desc2')
-        return c
-
     def test_Condition_saving_and_caching(self) -> None:
         """Test .save/.save_core."""
         kwargs = {'id_': 1, 'is_active': False}
         self.check_saving_and_caching(**kwargs)
         # check .id_ set if None, and versioned attributes too
-        c = self.versioned_condition()
+        c = Condition(None)
         c.save(self.db_conn)
         self.assertEqual(c.id_, 2)
-        self.assertEqual(sorted(c.title.history.values()),
-                         ['title1', 'title2'])
-        self.assertEqual(sorted(c.description.history.values()),
-                         ['desc1', 'desc2'])
+        self.check_saving_of_versioned('title', str)
+        self.check_saving_of_versioned('description', str)
 
     def test_Condition_from_table_row(self) -> None:
         """Test .from_table_row() properly reads in class from DB"""
         self.check_from_table_row()
-        c = self.versioned_condition()
-        c.save(self.db_conn)
-        assert isinstance(c.id_, int)
-        for row in self.db_conn.row_where(Condition.table_name, 'id', c.id_):
-            retrieved = Condition.from_table_row(self.db_conn, row)
-            # pylint: disable=no-member
-            self.assertEqual(sorted(retrieved.title.history.values()),
-                             ['title1', 'title2'])
-            # pylint: disable=no-member
-            self.assertEqual(sorted(retrieved.description.history.values()),
-                             ['desc1', 'desc2'])
+        self.check_versioned_from_table_row('title', str)
+        self.check_versioned_from_table_row('description', str)
 
     def test_Condition_by_id(self) -> None:
         """Test .by_id(), including creation."""
diff --git a/tests/processes.py b/tests/processes.py
index 8616008..9e769c1 100644
--- a/tests/processes.py
+++ b/tests/processes.py
@@ -42,34 +42,58 @@ class TestsWithDB(TestCaseWithDB):
             p.save(self.db_conn)
         return p1, p2, p3
 
-    def test_Process_saving_and_caching(self) -> None:
-        """Test .save/.save_core."""
-        kwargs = {'id_': 1}
-        self.check_saving_and_caching(**kwargs)
+    def p_of_conditions(self) -> tuple[Process, list[Condition],
+                                       list[Condition], list[Condition]]:
+        """Return Process and its three Condition sets."""
         p = Process(None)
-        p.title.set('t1')
-        p.title.set('t2')
-        p.description.set('d1')
-        p.description.set('d2')
-        p.effort.set(0.5)
-        p.effort.set(1.5)
         c1, c2, c3 = Condition(None), Condition(None), Condition(None)
         for c in [c1, c2, c3]:
             c.save(self.db_conn)
         assert isinstance(c1.id_, int)
         assert isinstance(c2.id_, int)
         assert isinstance(c3.id_, int)
-        p.set_conditions(self.db_conn, [c1.id_, c2.id_])
-        p.set_enables(self.db_conn, [c2.id_, c3.id_])
-        p.set_disables(self.db_conn, [c1.id_, c3.id_])
+        set_1 = [c1, c2]
+        set_2 = [c2, c3]
+        set_3 = [c1, c3]
+        p.set_conditions(self.db_conn, [c.id_ for c in set_1
+                                        if isinstance(c.id_, int)])
+        p.set_enables(self.db_conn, [c.id_ for c in set_2
+                                     if isinstance(c.id_, int)])
+        p.set_disables(self.db_conn, [c.id_ for c in set_3
+                                      if isinstance(c.id_, int)])
         p.save(self.db_conn)
+        return p, set_1, set_2, set_3
+
+    def test_Process_saving_and_caching(self) -> None:
+        """Test .save/.save_core."""
+        kwargs = {'id_': 1}
+        self.check_saving_and_caching(**kwargs)
+        self.check_saving_of_versioned('title', str)
+        self.check_saving_of_versioned('description', str)
+        self.check_saving_of_versioned('effort', float)
+        p, set1, set2, set3 = self.p_of_conditions()
+        p.uncache()
         r = Process.by_id(self.db_conn, p.id_)
-        self.assertEqual(sorted(r.title.history.values()), ['t1', 't2'])
-        self.assertEqual(sorted(r.description.history.values()), ['d1', 'd2'])
-        self.assertEqual(sorted(r.effort.history.values()), [0.5, 1.5])
-        self.assertEqual(sorted(r.conditions), sorted([c1, c2]))
-        self.assertEqual(sorted(r.enables), sorted([c2, c3]))
-        self.assertEqual(sorted(r.disables), sorted([c1, c3]))
+        self.assertEqual(sorted(r.conditions), sorted(set1))
+        self.assertEqual(sorted(r.enables), sorted(set2))
+        self.assertEqual(sorted(r.disables), sorted(set3))
+
+    def test_Process_from_table_row(self) -> None:
+        """Test .from_table_row() properly reads in class from DB"""
+        self.check_from_table_row()
+        self.check_versioned_from_table_row('title', str)
+        self.check_versioned_from_table_row('description', str)
+        self.check_versioned_from_table_row('effort', float)
+        p, set1, set2, set3 = self.p_of_conditions()
+        p.save(self.db_conn)
+        assert isinstance(p.id_, int)
+        for row in self.db_conn.row_where(self.checked_class.table_name,
+                                          'id', p.id_):
+            # pylint: disable=no-member
+            r = Process.from_table_row(self.db_conn, row)
+            self.assertEqual(sorted(r.conditions), sorted(set1))
+            self.assertEqual(sorted(r.enables), sorted(set2))
+            self.assertEqual(sorted(r.disables), sorted(set3))
 
     def test_Process_steps(self) -> None:
         """Test addition, nesting, and non-recursion of ProcessSteps"""
diff --git a/tests/utils.py b/tests/utils.py
index fbe739d..bb37270 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -80,6 +80,19 @@ class TestCaseWithDB(TestCase):
         for key, value in kwargs.items():
             self.assertEqual(getattr(obj, key), value)
 
+    def check_saving_of_versioned(self, attr_name: str, type_: type) -> None:
+        """Test owner's versioned attributes."""
+        owner = self.checked_class(None)
+        vals: list[Any] = ['t1', 't2'] if type_ == str else [0.9, 1.1]
+        attr = getattr(owner, attr_name)
+        attr.set(vals[0])
+        attr.set(vals[1])
+        owner.save(self.db_conn)
+        owner.uncache()
+        retrieved = owner.__class__.by_id(self.db_conn, owner.id_)
+        attr = getattr(retrieved, attr_name)
+        self.assertEqual(sorted(attr.history.values()), vals)
+
     def check_by_id(self) -> None:
         """Test .by_id(), including creation."""
         # check failure if not yet saved
@@ -109,6 +122,20 @@ class TestCaseWithDB(TestCase):
             self.assertEqual(obj, retrieved)
             self.assertEqual({obj.id_: obj}, self.checked_class.get_cache())
 
+    def check_versioned_from_table_row(self, attr_name: str,
+                                       type_: type) -> None:
+        """Test .from_table_row() reads versioned attributes from DB."""
+        owner = self.checked_class(None)
+        vals: list[Any] = ['t1', 't2'] if type_ == str else [0.9, 1.1]
+        attr = getattr(owner, attr_name)
+        attr.set(vals[0])
+        attr.set(vals[1])
+        owner.save(self.db_conn)
+        for row in self.db_conn.row_where(owner.table_name, 'id', owner.id_):
+            retrieved = owner.__class__.from_table_row(self.db_conn, row)
+            attr = getattr(retrieved, attr_name)
+            self.assertEqual(sorted(attr.history.values()), vals)
+
     def check_all(self) -> tuple[Any, Any, Any]:
         """Test .all()."""
         # pylint: disable=not-callable
diff --git a/tests/versioned_attributes.py b/tests/versioned_attributes.py
index 69c31fe..a75fc3c 100644
--- a/tests/versioned_attributes.py
+++ b/tests/versioned_attributes.py
@@ -6,7 +6,7 @@ from tests.utils import TestCaseWithDB
 from plomtask.versioned_attributes import VersionedAttribute, TIMESTAMP_FMT
 from plomtask.db import BaseModel
 
-SQL_TEST_TABLE = '''
+SQL_TEST_TABLE_STR = '''
 CREATE TABLE versioned_tests (
   parent INTEGER NOT NULL,
   timestamp TEXT NOT NULL,
@@ -14,6 +14,14 @@ CREATE TABLE versioned_tests (
   PRIMARY KEY (parent, timestamp)
 );
 '''
+SQL_TEST_TABLE_FLOAT = '''
+CREATE TABLE versioned_tests (
+  parent INTEGER NOT NULL,
+  timestamp TEXT NOT NULL,
+  value REAL NOT NULL,
+  PRIMARY KEY (parent, timestamp)
+);
+'''
 
 
 class TestParentType(BaseModel[int]):
@@ -81,20 +89,22 @@ class TestsSansDB(TestCase):
         self.assertEqual(attr.at(timestamp_after_c), 'C')
 
 
-class TestsWithDB(TestCaseWithDB):
+class TestsWithDBStr(TestCaseWithDB):
     """Module tests requiring DB setup."""
+    default_vals: list[str | float] = ['A', 'B', 'C']
+    init_sql = SQL_TEST_TABLE_STR
 
     def setUp(self) -> None:
         super().setUp()
-        self.db_conn.exec(SQL_TEST_TABLE)
+        self.db_conn.exec(self.init_sql)
         self.test_parent = TestParentType(1)
         self.attr = VersionedAttribute(self.test_parent,
-                                       'versioned_tests', 'A')
+                                       'versioned_tests', self.default_vals[0])
 
     def test_VersionedAttribute_save(self) -> None:
         """Test .save() to write to DB."""
         # check mere .set() calls do not by themselves reflect in the DB
-        self.attr.set('B')
+        self.attr.set(self.default_vals[1])
         self.assertEqual([],
                          self.db_conn.row_where('versioned_tests',
                                                 'parent', 1))
@@ -103,25 +113,32 @@ class TestsWithDB(TestCaseWithDB):
         vals_found = []
         for row in self.db_conn.row_where('versioned_tests', 'parent', 1):
             vals_found += [row[2]]
-        self.assertEqual(['B'], vals_found)
+        self.assertEqual([self.default_vals[1]], vals_found)
         # check .save() also updates history in DB
-        self.attr.set('C')
+        self.attr.set(self.default_vals[2])
         self.attr.save(self.db_conn)
         vals_found = []
         for row in self.db_conn.row_where('versioned_tests', 'parent', 1):
             vals_found += [row[2]]
-        self.assertEqual(['B', 'C'], sorted(vals_found))
+        self.assertEqual([self.default_vals[1], self.default_vals[2]],
+                         sorted(vals_found))
 
     def test_VersionedAttribute_history_from_row(self) -> None:
         """"Test .history_from_row() properly interprets DB rows."""
-        self.attr.set('B')
-        self.attr.set('C')
+        self.attr.set(self.default_vals[1])
+        self.attr.set(self.default_vals[2])
         self.attr.save(self.db_conn)
-        loaded_attr = VersionedAttribute(self.test_parent,
-                                         'versioned_tests', 'A')
+        loaded_attr = VersionedAttribute(self.test_parent, 'versioned_tests',
+                                         self.default_vals[0])
         for row in self.db_conn.row_where('versioned_tests', 'parent', 1):
             loaded_attr.history_from_row(row)
         for timestamp, value in self.attr.history.items():
             self.assertEqual(value, loaded_attr.history[timestamp])
         self.assertEqual(len(self.attr.history.keys()),
                          len(loaded_attr.history.keys()))
+
+
+class TestsWithDBFloat(TestsWithDBStr):
+    """Module tests requiring DB setup."""
+    default_vals: list[str | float] = [0.9, 1.1, 2]
+    init_sql = SQL_TEST_TABLE_FLOAT
-- 
2.30.2