From 80491fac3c476788d90010812c9ba0b95701e09b Mon Sep 17 00:00:00 2001 From: Christian Heller 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^|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-{X*&5O3MS!Uo^vKJsnE0UU&eJ~B1Q zbWauc8HpB8abe@@lA-Kq7Ie3tWNIN!}p8ds-tb!o1Sn69IBmCbUp8}=Gpk!Ny6BhL@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&?&A@0nQO^ILX-Qfj#awdda-In zvuIfxYwnK702NvMzO^%%GsVPpnHVn5RYu39=-H7mdGg$d8X29CM&!w9c?%p`ZYQuE zAZLpyv4o;V5>ZJuxJt(oYR(FlBh%xOEE#<&XUqF1BIl%>b6LP15^)C!)^glyhO3qRszY^*{;XlpzhuFRpr!EHf(4z->7Hb2+*^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$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 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 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 zcmc(he{2)y8OQzJ5BnVKoP!<5Hc2?rFzn!@A-@BZ{AemQg+eJU+R)mozfN7v}5P488HDlj2L&M@_) zDC}{D6vs>4i3%k|nw;$!x9U_XRZ-y;`>0(J>4--ODIQu^DODuNYR|~v8bw-ur?0N!P+vyMbf2(E4^Yyi4@>^BI>@=e@8$PG4Hs%yY zVNWtCR-wx|$;@y%zu_~@PNTP|-%rce&G6Gak)#@)Q|v(-xzOw9kgaTTluTr%sheeU zc5)%)BTsc!+NlehbdbKi^`zDBX4$0kdo_M;#;)@u+gM9(YzvWkkK4^BUF*4X?)8hw z#okJCwPtHZL3H`T`G#jyO_$Q=QYzl1Ns}tp66utxNU$G?kqKSZS`HT&eGmP$ef`;Q zp?uT#^{YRGa<31=N^mztq!I_9-457AQD8My$0wjW0A0sKDjtiUQVUL5j*rDMnkLHy zeq>5cD0n+~)dQZkTu&u5J&mUd_Q}}TgsMdxSc1Xl0Wx^-)`SZj9oGsR%(dXeG+jcS zR29uZU8GXM4d5Q6dE=*LEjF1*os`p~@}%lqTj=>PIa=i>Z}{vP%f4nlMlaL;MDe2S z4<6r&r(xOCkn6~M!loyj90@wUG?z(G5 zYG0Px^HQfNb>@RzX0U6C%L|W~!XtOrzc^|$zFTcFJU&GiO}YbT(F?}gfgX;>DKLCf zdk~#9dg??(2KuU*{r@K&^th5`Jz0XNuA)ky6SRsVP+bV*bus7|o3YcjliU_}kiYsX zI_;Zu=eSRojtA({mfHfF3F#Y04OM2+y`C&r`5%&+9k)c~JipfxRm&(&kIQ;&WK5ND z`dm07VKt^aSY#6TN<)J!hjEN%z$1V-Kmn9xh7ZziMBJn`tb$XfEH-=u`cDBYX`O`D zQ9xN_I04-xMMT)7E_@n>#sK4h;{bRHG=XAGSW-z@^(AFl=SDRg9P<5(KHp5`Rh=oH zE1QOAAgT+2%!+nfRrUW!Xqip=dw|fqHS_ydypd&ZWO1k2w0CLf_Re2N^4>$H_fXNs zItNjS*+*9cbyvleK-Y4h>z4kD>D$NhfnhT+oE`qs8(QeiCGy@@)7zRIT6K9=T(!%t z+H1#iEkoB2tu%HoH+JV6d(Fn)eBEBNj^@a_229t$UF%zPl(QK9^`Efl^3NN#v8^D- z(p`f?b^RoK5v&&g@N{Af*a1k9gFA=OHRH<8MW&(jSZqXqTOMIccYDn{9{vtmG(HM{ z&Y<^<+1(z50_0kBH+q@;Ci+n1FoaA4CIIIEQ-BQMCBQ|%WnypMf&N0m&A*In;Sbzu zFWP9eq+8V;&Z;&eM80a?-{#^6(GpvLR=xGRa8UV}>=SUpQ$IC^Qvufx?prdZ!J0*1HA(>=Y&G-i9=V(f2%lg8t+64PV&ee$DyedzbbSNl#d=q5RE z;5hoTapgcWa$4sBollm0(YGrI=_3e#0M*)!wFLh$5&Qd4ksRqiD$JIA-X)9udtR`n z_A<5Ln*b+8!JZyTs&U+;a`D++j?VbT3j6)lVzF@HeaKvwe?%40G 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$rk4Ku) 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>OdzFu@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 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 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