7i?dZddlZddlmcmZddlZddlZddl Z ddl Z ddl m Z ddl mZddlmZmZej$dZGddZGd d ZGd d Zy) z`Comprehensive tests for database layer. Tests DatabaseManager, Recipe model, and Output model. N)Path)DatabaseManager)RecipeOutputc#NKtjd\}}tj|t |}|j ||jt |jrtj|dt_ dt_ yw)zoCreate a temporary test database. Yields: DatabaseManager: Initialized test database manager. z.db)suffixNF) tempfilemkstemposcloser init_databaserexistsunlink _instance _initialized)temp_fd temp_pathdbs :/mnt/ssd/data/python-lab/ChefSystem/tests/test_database.pytest_dbrs"))7GYHHW  #B HHHJ I )!%O#(O sB#B%c.eZdZdZdZdZdZdZdZy)TestDatabaseManagerz Tests for DatabaseManager class.chtd}td}||u}|stjd|fd||fdtjvstj |rtj |nddtjvstj |rtj |nddz}dd |iz}ttj|d }||u}|stjd|fd||fdtjvstj |rtj |ndd tjvstj |rtj |nd dz}dd |iz}ttj|d }y ) z9Verify that DatabaseManager implements singleton pattern.ztest1.dbztest2.dbis)z%(py0)s is %(py2)sdb1db2)py0py2zassert %(py4)spy4Nr) r @pytest_ar_call_reprcompare @py_builtinslocals_should_repr_global_name _safereprAssertionError_format_explanation)selfrrr @py_assert1 @py_format3 @py_format5s rtest_singleton_patternz*TestDatabaseManager.test_singleton_pattern-sj)j)czscssccg~sgssggc$|j}|jd}|jDcgc]}|d }}d}||v}|stjd|fd||ftj |dt jvstj|rtj |nddz}dd |iz} ttj| d x}}d }||v}|stjd|fd||ftj |dt jvstj|rtj |nddz}dd |iz} ttj| d x}}y cc}w) z(Verify that database tables are created.z?SELECT name FROM sqlite_master WHERE type='table' ORDER BY namerrecipesinz%(py1)s in %(py3)stablespy1py3assert %(py5)spy5Noutputs) get_connectionexecutefetchallr!r"r&r#r$r%r'r() r)rconncursorrowr4 @py_assert0 @py_assert2 @py_format4 @py_format6s rtest_init_databasez&TestDatabaseManager.test_init_database6s%%' M %+OO$56S#a&66"yF""""yF"""y""""""F"""F""""""""yF""""yF"""y""""""F"""F"""""""7s F cf|j}|jd}|j}|d}d}||k(}|sltjd|fd||ftj |tj |dz}dd|iz} t tj| d x}x}}y ) z0Verify that foreign key constraints are enabled.zPRAGMA foreign_keysr==z%(py1)s == %(py4)sr6r assert %(py6)spy6N)r;r<fetchoner!r"r&r'r() r)rr>r?resultrA @py_assert3rBr, @py_format7s rtest_foreign_keys_enabledz-TestDatabaseManager.test_foreign_keys_enabledAsx%%'34"ayAyA~yAyAr.c|5}|jdddddtj|}t|}d}||k(}|st j d|fd||fdt jvst jtrt jtnddt jvst j|rt j|ndt j|t j|d z}d d |iz}tt j|dx}x}}|d } | j}d }||k(}|st j d|fd||ft j| t j|t j|dz}d d |iz}tt j|dx} x}x}}y#1swYxYw)z(Test context manager commits on success.5INSERT INTO recipes (name, prompt_text) VALUES (?, ?) Test Recipez Test promptNrGrHz0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)slenr0rr6r7rMassert %(py8)spy8rrVz,%(py3)s {%(py3)s = %(py1)s.name } == %(py6)sr6r7rM) r<rget_allrXr!r"r#r$r%r&r'r(name) r)rr>r0rB @py_assert5 @py_assert4rQ @py_format9rAs rtest_context_manager_commitz/TestDatabaseManager.test_context_manager_commitIs,   LLG.  ..)7| q |q    |q      s   s      7   7   |   q       qz/z/-/-////-///z//////-///////  s G&&G0c |5}|jddtd#1swYnxYwn#t$rYnwxYwtj|}t |}d}||k(}|st j d|fd||fdtjvst jtrt jtndd tjvst j|rt j|nd t j|t j|d z}d d |iz}tt j|dx}x}}y) z)Test context manager rolls back on error.rTrUz Test errorNrrHrWrXr0rYrZr[) r< Exceptionrr^rXr!r"r#r$r%r&r'r() r)rr>r0rBr`rarQrbs rtest_context_manager_rollbackz1TestDatabaseManager.test_context_manager_rollbackVs  .D K2  --  . . .   ..)7| q |q    |q      s   s      7   7   |   q       s/"+/ ;;N) __name__ __module__ __qualname____doc__r-rErRrcrfr.rrr*s* # 0!r.rcveZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZy) TestRecipezTests for Recipe model.c tj|ddddd}d}||u}|stjd|fd ||fd t j vstj |rtj|nd tj|d z}d d |iz}ttj|dx}}|j}d}||u}|stjd|fd||fd t j vstj |rtj|nd tj|tj|dz}dd|iz} ttj| dx}x}}|j}d}||k(}|stjd|fd||fd t j vstj |rtj|nd tj|tj|dz}dd|iz} ttj| dx}x}}|j}d}||k(}|stjd|fd||fd t j vstj |rtj|nd tj|tj|dz}dd|iz} ttj| dx}x}}|j}d}||k(}|stjd|fd||fd t j vstj |rtj|nd tj|tj|dz}dd|iz} ttj| dx}x}}|j}d}||k(}|stjd|fd||fd t j vstj |rtj|nd tj|tj|dz}dd|iz} ttj| dx}x}}|j}d}||k(}|stjd|fd||fd t j vstj |rtj|nd tj|tj|dz}dd|iz} ttj| dx}x}}|j }d}||u}|stjd|fd||fd t j vstj |rtj|nd tj|tj|dz}dd|iz} ttj| dx}x}}|j"}d}||u}|stjd|fd||fd t j vstj |rtj|nd tj|tj|dz}dd|iz} ttj| dx}x}}y)zTest creating a new recipe.rVzThis is a test promptz test,pythonz A test recipez Some notes)r_ prompt_texttags descriptionnotesNis notz%(py0)s is not %(py3)sreciperr7r8r9z.%(py2)s {%(py2)s = %(py0)s.id } is not %(py5)srrr9assert %(py7)spy7rHz,%(py2)s {%(py2)s = %(py0)s.name } == %(py5)sz3%(py2)s {%(py2)s = %(py0)s.prompt_text } == %(py5)sz,%(py2)s {%(py2)s = %(py0)s.tags } == %(py5)s)z3%(py2)s {%(py2)s = %(py0)s.description } == %(py5)s)z-%(py2)s {%(py2)s = %(py0)s.notes } == %(py5)s)z6%(py2)s {%(py2)s = %(py0)s.created_at } is not %(py5)sz6%(py2)s {%(py2)s = %(py0)s.updated_at } is not %(py5)s)rcreater!r"r#r$r%r&r'r(idr_rorprqrr created_at updated_at) r)rrvrBr*rCrDrarP @py_format8s rtest_create_recipezTestRecipe.test_create_recipeks /'  "!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!yy$$y$$$$y$$$$$$v$$$v$$$y$$$$$$$$$${{+m+{m++++{m++++++v+++v+++{+++m+++++++!!<%<<!%<<<<<!%<<<<<< tj|dd}|j}tj||jddd}d}||u}|st j d |fd ||fd tjvst j|rt j|nd t j|d z}d d|iz}tt j|dx}}tj||j} | j}d} || k(} | st j d| fd|| fdtjvst j| rt j| ndt j|t j| dz}dd|iz} tt j| dx}x} } | j}d} || k(} | st j d| fd|| fdtjvst j| rt j| ndt j|t j| dz}dd|iz} tt j| dx}x} } | j }d} || k(} | st j d| fd|| fdtjvst j| rt j| ndt j|t j| dz}dd|iz} tt j| dx}x} } | j}d} || u} | st j d| fd|| fdtjvst j| rt j| ndt j|t j| dz}dd|iz} tt j| dx}x} } | j}||k\} | st j d| fd||fdtjvst j| rt j| ndt j|dtjvst j|rt j|nddz} dd| iz}tt j|dx}} y) zTest updating a recipe.OriginalzOriginal promptrUpdatedzUpdated promptznew,tagsr_rorpTrrsuccessrwr8r9NrHr|updatedryrzr{r}r~rsr)>=)z2%(py2)s {%(py2)s = %(py0)s.updated_at } >= %(py4)soriginal_updated_at)rrr rLrM)rrrupdaterr!r"r#r$r%r&r'r(rr_rorp)r)rrvrrrBr*rCrDrrarPrr,rQs rtest_update_recipezTestRecipe.test_update_recipeswZEVW$//--  II(  w$w$ww$""7FII6||(y(|y((((|y((((((w(((w(((|(((y(((((((""6&66"&66666"&6666666w666w666"666&66666666||)z)|z))))|z))))))w)))w)))|)))z)))))))!!--!----!------w---w---!----------!!8!%88888!%8888888w888w888!888888%8888%88888888r.c~tj|dd}d}||u}|stjd|fd||fdt j vstj |rtj|ndtj|dz}d d |iz}ttj|d x}}y ) z0Test updating non-existent recipe returns False.rzDoes not existr_Frrrrwr8r9N) rrr!r"r#r$r%r&r'r(r)rrrBr*rCrDs rtest_update_recipe_not_foundz'TestRecipe.test_update_recipe_not_foundsn--4DEw%w%ww%r.ctj|ddtj|dd}tj||jd}d}||u}|st j d|fd ||fd t jvst j|rt j|nd t j|d z}d d |iz}tt j|dx}}y)z/Test updating recipe with duplicate name fails.rrrrrrFrrrrwr8r9N) rrrrr!r"r#r$r%r&r'r()r)rrecipe2rrBr*rCrDs r!test_update_recipe_duplicate_namez,TestRecipe.test_update_recipe_duplicate_names gGD--hJO--'Bw%w%ww%r.cHtj|dd}tj||j}d}||u}|st j d|fd||fdt jvst j|rt j|ndt j|dz}d d |iz}tt j|d x}}tj||j}d }||u}|st j d|fd||fd t jvst j|rt j|nd t j|dz}d d |iz}tt j|d x}}y ) zTest deleting a recipe.z To DeleterrTrrrrwr8r9NrO) rrdeleterr!r"r#r$r%r&r'r(r) r)rrvrrBr*rCrDrOs rtest_delete_recipezTestRecipe.test_delete_recipesw[hO--3w$w$ww$!!'6995v~vvvr.cztj|d}d}||u}|stjd|fd||fdt j vstj |rtj|ndtj|dz}dd|iz}ttj|d x}}y ) z0Test deleting non-existent recipe returns False.rFrrrrwr8r9N) rrr!r"r#r$r%r&r'r(rs rtest_delete_recipe_not_foundz'TestRecipe.test_delete_recipe_not_foundsk--.w%w%ww%r.ctj|ddtj|ddtj|ddtj|d}t|}d}||k(}|st j d |fd ||fd t jvst jtrt jtnd d t jvst j|rt j|nd t j|t j|d z}dd|iz}tt j|dx}x}}|Dcgc]}|j} }d} | | v}|st j d|fd| | ft j| dt jvst j| rt j| nddz} dd| iz} tt j| dx} }d} | | v}|st j d|fd| | ft j| dt jvst j| rt j| nddz} dd| iz} tt j| dx} }ycc}w)zTest searching recipes by name.zPython TutorialrrzJavaScript GuidezPython AdvancedpythonqueryrHrWrXresultsrYrZr[Nr1r3rr5r8r9 rrsearchrXr!r"r#r$r%r&r'r(r_ r)rrrBr`rarQrbrrrArCrDs rtest_search_by_namezTestRecipe.test_search_by_names g$58L g$6HM g$58L--x87| q |q    |q      s   s      7   7   |   q       !()A)) ) E)))) E))) ))))))E)))E))))))) ) E)))) E))) ))))))E)))E)))))))*s4Kctj|dddtj|dddtj|dddtj|d g }t|}d }||k(}|st j d |fd ||fdt jvst jtrt jtnddt jvst j|rt j|ndt j|t j|dz}dd|iz}tt j|dx}x}}|Dcgc]}|j} }d} | | v}|st j d|fd| | ft j| dt jvst j| rt j| nddz} dd| iz} tt j| dx} }d} | | v}|st j d|fd| | ft j| dt jvst j| rt j| nddz} dd| iz} tt j| dx} }ycc}w)zTest filtering recipes by tags.rP python,webrr javascriptr python,datar)rprrHrWrXrrYrZr[Nr1r3rr5r8r9rrs rtest_search_by_tagszTestRecipe.test_search_by_tagss gJClS gJClS gJCmT--xj97| q |q    |q      s   s      7   7   |   q       !()A))"zU""""zU"""z""""""U"""U""""""""zU""""zU"""z""""""U"""U"""""""*s8Kc0tj|dddtj|dddtj|dddtj|d d g }t|}d }||k(}|st j d |fd||fdt jvst jtrt jtnddt jvst j|rt j|ndt j|t j|dz}dd|iz}tt j|dx}x}}|d}|j}d}||k(}|st j d |fd||ft j|t j|t j|dz}dd|iz}tt j|dx}x}x}}y)z#Test combined name and tags search.z Python Webrrrz Python Datarz Web Designzweb,cssPythonweb)rrprGrHrWrXrrYrZr[Nrr\r]r) r)rrrBr`rarQrbrAs rtest_search_combinedzTestRecipe.test_search_combineds< gLc U gMsW gLc R--xugF7| q |q    |q      s   s      7   7   |   q       qz.z.,.,....,...z......,.......r.ctj|ddtj|d}t|}d}||k(}|st j d|fd||fd t jvst jtrt jtnd d t jvst j|rt j|nd t j|t j|d z}d d |iz}tt j|dx}x}}y)z/Test search with no matches returns empty list.rrr nonexistentrrrHrWrXrrYrZr[N) rrrrXr!r"r#r$r%r&r'r()r)rrrBr`rarQrbs rtest_search_no_resultsz!TestRecipe.test_search_no_results s gFA--}=7| q |q    |q      s   s      7   7   |   q       r.cxtj|dd}|j}t|t}|s ddt j vstjtrtjtnddt j vstj|rtj|nddt j vstjtrtjtndtj|dz}ttj|d }|d }d}||k(}|sltjd |fd ||ftj|tj|d z}dd|iz}ttj|d x}x}}|d}d}||k(}|sltjd |fd ||ftj|tj|d z}dd|iz}ttj|d x}x}}|d} t| t} | sddt j vstjtrtjtndtj| dt j vstjtrtjtndtj| dz} ttj| d x} } |d} t| t} | sddt j vstjtrtjtndtj| dt j vstjtrtjtndtj| dz} ttj| d x} } y )z"Test recipe to_dict serialization.rrr5assert %(py4)s {%(py4)s = %(py0)s(%(py1)s, %(py2)s) } isinstancedatadictrr6rr Nr_rHrJrKrLrMror5assert %(py5)s {%(py5)s = %(py0)s(%(py2)s, %(py3)s) }strrrr7r9r)rrto_dictrrr#r$r!r%r&r'r(r"r) r)rrvrrPr,rArBrQr*rarDs r test_to_dictzTestRecipe.test_to_dictsHwVJ~~$%%%%%%%%z%%%z%%%%%%$%%%$%%%%%%%%%%%%%%%%%%%F|%v%|v%%%%|v%%%|%%%v%%%%%%%M".h."h...."h..."...h.......|,2z,c22222222z222z222,222222c222c2222222222|,2z,c22222222z222z222,222222c222c2222222222r.ctj|dd}|j}tj|}|j}|j}||k(}|st j d|fd||fdtjvst j|rt j|ndt j|dtjvst j|rt j|ndt j|dz}d d |iz} tt j| d x}x}}|j}|j}||k(}|st j d|fd ||fdtjvst j|rt j|ndt j|dtjvst j|rt j|ndt j|dz}d d |iz} tt j| d x}x}}|j}|j}||k(}|st j d|fd ||fdtjvst j|rt j|ndt j|dtjvst j|rt j|ndt j|dz}d d |iz} tt j| d x}x}}y )z&Test recipe from_dict deserialization.rrrrHrrestoredoriginalrrZr[Nr)zR%(py2)s {%(py2)s = %(py0)s.created_at } == %(py6)s {%(py6)s = %(py4)s.created_at })rrr from_dictrr!r"r#r$r%r&r'r(r_r) r)rrrrr*r`rPrQrbs rtest_from_dictzTestRecipe.test_from_dicts==v8L!##D){{)hkk){k)))){k))))))x)))x))){))))))h)))h)))k)))))))}}- -} ----} ------x---x---}------------ -------""9h&9&99"&99999"&9999999x999x999"999999h999h999&99999999r.N)rgrhrirjrrrrrrrrrrrrrrrrrrkr.rrmrmhsZ!-*!< #! 94    * # /! 3 :r.rmcLeZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z y ) TestOutputzTests for Output model.c tj|dd}tj||jddddd }d }||u}|st j d |fd ||fd t jvst j|rt j|nd t j|dz}dd|iz}tt j|d x}}|j}d }||u} | st j d | fd||fd t jvst j|rt j|nd t j|t j|dz}dd|iz} tt j| d x}x} }|j}|j} || k(} | st j d| fd|| fd t jvst j|rt j|nd t j|dt jvst j|rt j|ndt j| dz} dd| iz} tt j| d x}x} } |j}d}||k(} | st j d| fd||fd t jvst j|rt j|nd t j|t j|dz}dd|iz} tt j| d x}x} }|j}d}||k(} | st j d| fd||fd t jvst j|rt j|nd t j|t j|dz}dd|iz} tt j| d x}x} }|j}d}||k(} | st j d| fd||fd t jvst j|rt j|nd t j|t j|dz}dd|iz} tt j| d x}x} }|j }d}||k(} | st j d| fd||fd t jvst j|rt j|nd t j|t j|dz}dd|iz} tt j| d x}x} }|j"}d}||k(} | st j d| fd||fd t jvst j|rt j|nd t j|t j|dz}dd|iz} tt j| d x}x} }|j$}d }||u} | st j d | fd ||fd t jvst j|rt j|nd t j|t j|dz}dd|iz} tt j| d x}x} }y )!zTest creating a new output.rVrrz output.pdfzrecipe_1/output.pdfz.pdfizTest execution) recipe_idfilenamefilepath file_type file_sizeexecution_notesNrsruoutputrwr8r9rxryrzr{rH)zI%(py2)s {%(py2)s = %(py0)s.recipe_id } == %(py6)s {%(py6)s = %(py4)s.id }rvrrZr[z0%(py2)s {%(py2)s = %(py0)s.filename } == %(py5)s)z0%(py2)s {%(py2)s = %(py0)s.filepath } == %(py5)s)z1%(py2)s {%(py2)s = %(py0)s.file_type } == %(py5)s)z1%(py2)s {%(py2)s = %(py0)s.file_size } == %(py5)sz7%(py2)s {%(py2)s = %(py0)s.execution_notes } == %(py5)s)z8%(py2)s {%(py2)s = %(py0)s.generated_at } is not %(py5)s)rrrrr!r"r#r$r%r&r'r(rrrrrr generated_at)r)rrvrrBr*rCrDrarPrr`rQrbs rtest_create_outputzTestOutput.test_create_output+sFw]Q ii!*, "!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!yy$$y$$$$y$$$$$$v$$$v$$$y$$$$$$$$$$,699,9,,,,9,,,,,,v,,,v,,,,,,,,,6,,,6,,,9,,,,,,,.,.,....,......v...v......,.......7"77"77777"7777777v777v777777"77777777)6)6))))6))))))v)))v))))))6)))))))'4'4''''4''''''v'''v''''''4'''''''%%9)99%)99999%)9999999v999v999%999)99999999"".$."$...."$......v...v..."...$.......r.ctj|ddd}d}||u}|stjd|fd||fdt j vstj |rtj|ndtj|dz}d d |iz}ttj|dx}}y) z2Test creating output with invalid recipe_id fails.rtest.pdfrrrNrrrrwr8r9) rrr!r"r#r$r%r&r'r()r)rrrBr*rCrDs r!test_create_output_invalid_recipez,TestOutput.test_create_output_invalid_recipeEsv   v~vvvr.cPtj|dd}tj||jdd}tj||j}d}||u}|st j d|fd||fd tjvst j|rt j|nd t j|d z}d d |iz}tt j|dx}}|j}|j} || k(} | st j d | fd|| fd tjvst j|rt j|nd t j|dtjvst j|rt j|ndt j| dz} dd| iz} tt j| dx}x} } |j}|j} || k(} | st j d | fd|| fd tjvst j|rt j|nd t j|dtjvst j|rt j|ndt j| dz} dd| iz} tt j| dx}x} } y)zTest retrieving output by ID.rrrrrNrsrurrwr8r9rHrrrrZr[zN%(py2)s {%(py2)s = %(py0)s.filename } == %(py6)s {%(py6)s = %(py4)s.filename })rrrrrr!r"r#r$r%r&r'r(r) r)rrvrrrBr*rCrDr`rPrQrbs rrzTestOutput.test_get_by_idQswX8L--699z\fg$$Wgjj9 $$y$$$$y$$$$$$y$$$y$$$$$$$$$$||)wzz)|z))))|z))))))y)))y)))|))))))w)))w)))z)))))))!!5W%5%55!%55555!%5555555y555y555!555555W555W555%55555555r.ctj|dd}tj||jddtj||jddtj||jd d tj||j}t |}d }||k(}|st jd |fd ||fdtjvst jt rt jt nddtjvst j|rt j|ndt j|t j|dz}dd|iz}tt j|dx}x}}|D cgc]} | j} } d} | | v}|st jd|fd| | ft j| dtjvst j| rt j| nddz} dd| iz} tt j| dx} }d} | | v}|st jd|fd| | ft j| dtjvst j| rt j| nddz} dd| iz} tt j| dx} }d } | | v}|st jd|fd| | ft j| dtjvst j| rt j| nddz} dd| iz} tt j| dx} }ycc} w)z)Test retrieving all outputs for a recipe.rrrz output1.pdfpath1rz output2.pdfpath2z output3.pdfpath3rrHrWrXr:rYrZr[Nr1r3 filenamesr5r8r9)rrrr get_by_reciperXr!r"r#r$r%r&r'r(r)r)rrvr:rBr`rarQrborrArCrDs rtest_get_by_recipezTestOutput.test_get_by_recipe[s$wX8L  g]U\] g]U\] g]U\]&&w :7| q |q    |q      s   s      7   7   |   q       )01AQZZ1 1)} ))))} )))})))))) ))) ))))))))} ))))} )))})))))) ))) ))))))))} ))))} )))})))))) ))) )))))))2s6N;c:tj|dd}tj|dd}tj||jddtj||jd d tj|}t |}d }||k(}|st jd |fd ||fdtjvst jt rt jt nddtjvst j|rt j|ndt j|t j|dz}dd|iz} tt j| dx}x}}y)zTest retrieving all outputs.rP1rrP2out1.pdfp1rout2.pdfp2rrHrWrXr:rYrZr[N)rrrrr^rXr!r"r#r$r%r&r'r() r)rrecipe1rr:rBr`rarQrbs rrzTestOutput.test_get_allls--jdK--jdK gjSWX gjSWX..)7| q |q    |q      s   s      7   7   |   q       r.cjtj|dd}tj||jdd}tj||jdd }d }||u}|st j d |fd ||fd tjvst j|rt j|nd t j|dz}dd|iz}tt j|dx}}tj||j} | j}d} || k(} | st j d| fd|| fdtjvst j| rt j| ndt j|t j| dz}dd|iz} tt j| dx}x} } | j}d} || k(} | st j d| fd|| fdtjvst j| rt j| ndt j|t j| dz}dd|iz} tt j| dx}x} } y)zTest updating an output.rrrz original.pdfpathrz updated.pdfz Updated notes)rrTrrrrwr8r9NrHrrryrzr{r)rrrrrr!r"r#r$r%r&r'r(rrr) r)rrvrrrBr*rCrDrrarPrs rtest_update_outputzTestOutput.test_update_outputwswX8Lw&))n_ef--  II"+  w$w$ww$""7FII60=0=0000=000000w000w000000=0000000&&9/9&/9999&/999999w999w999&999/9999999r.ctj|dd}tj||jdd}tj||j}d}||u}|st j d|fd ||fd tjvst j|rt j|nd t j|d z}d d |iz}tt j|dx}}tj||j} d}| |u}|st j d|fd | |fdtjvst j| rt j| ndt j|d z}d d |iz}tt j|dx}}y)zTest deleting an output.rrrrr rTrrrrwr8r9NrO)rrrrrr!r"r#r$r%r&r'r(r) r)rrvrrrBr*rCrDrOs rtest_delete_outputzTestOutput.test_delete_outputswX8Lw&))j[ab--3w$w$ww$!!'6995v~vvvr.ctj|dd}tj||jddtj||jddtj||jd d tj||j}t |}d }||k(}|st jd |fd ||fdtjvst jt rt jt nddtjvst j|rt j|ndt j|t j|dz}dd|iz}tt j|dx}x}}tj||jtj||j} t | }d}||k(}|st jd |fd ||fdtjvst jt rt jt nddtjvst j| rt j| ndt j|t j|dz}dd|iz}tt j|dx}x}}y)z9Test CASCADE delete: deleting recipe deletes its outputs.rrrrrrrrzout3.pdfp3rrHrWrXoutputs_beforerYrZr[Nr outputs_after)rrrrrrXr!r"r#r$r%r&r'r(r) r)rrvrrBr`rarQrbrs rtest_cascade_deletezTestOutput.test_cascade_deleteswX8L  gZRVW gZRVW gZRVW --gvyyA>"'a'"a''''"a''''''s'''s''''''>'''>'''"'''a'''''''  gvyy),,Wfii@ =!&Q&!Q&&&&!Q&&&&&&s&&&s&&&&&&=&&&=&&&!&&&Q&&&&&&&r.ctj|dd}tj||jdd}|j }t |t }|s ddtjvstjt rtjt ndd tjvstj|rtj|nd d tjvstjt rtjt nd tj|d z}ttj|d }|d }d}||k(}|sltjd|fd||ftj|tj|dz}dd|iz} ttj| d x}x}}|d} t | t} | sddtjvstjt rtjt ndtj| dtjvstjtrtjtndtj| dz} ttj| d x} } y )z"Test output to_dict serialization.rrrrr rrrrrrNrrHrJrKrLrMrrrr)rrrrrrrr#r$r!r%r&r'r(r"r) r)rrvrrrPr,rArBrQr*rarDs rrzTestOutput.test_to_dictswX8Lw&))j[ab~~$%%%%%%%%z%%%z%%%%%%$%%%$%%%%%%%%%%%%%%%%%%%J-:-:----:------:-------~.4z.44444444z444z444.4444444444444444444r.ctj|dd}tj||jdd}|j }tj |}|j}|j}||k(}|st jd|fd||fd tjvst j|rt j|nd t j|d tjvst j|rt j|nd t j|d z} d d | iz} tt j| dx}x}}|j}|j}||k(}|st jd|fd||fd tjvst j|rt j|nd t j|d tjvst j|rt j|nd t j|d z} d d | iz} tt j| dx}x}}y)z&Test output from_dict deserialization.rrrrr rrHrrrrrZr[Nr)rrrrrrr!r"r#r$r%r&r'r(r) r)rrvrrrr*r`rPrQrbs rrzTestOutput.test_from_dictsuwX8L==FII ]cd!##D){{)hkk){k)))){k))))))x)))x))){))))))h)))h)))k)))))))  5H$5$55 $55555 $5555555x555x555 555555H555H555$55555555r.N)rgrhrirjrrrrrr r rrrrkr.rrr(s7!/4 6*" !:$ '(56r.r)rjbuiltinsr#_pytest.assertion.rewrite assertionrewriter!pytestsqlite3r r pathlibrsrc.database.db_managerrsrc.database.modelsrrfixturerrrmrrkr.rrsa   3.))4;!;!|}:}:@R6R6r.