1010- Back navigation preserving state
1111- /generator/random and /generator/llm routes
1212"""
13+
1314import json
1415
1516import pytest
16-
1717from fm_generator .FMGenerator .models .config import Params
1818
19-
2019STEP1 = {"num_models_val" : "3" , "seed" : "42" , "name_prefix" : "fm" }
2120STEP2 = {
2221 "num_features_min" : "5" ,
@@ -66,6 +65,7 @@ def _walk_happy_path(client, step2=None, step3=None, step4=None):
6665
6766# ── Routes & top-level shape ─────────────────────────────────────────────
6867
68+
6969def test_landing_is_reachable (client ):
7070 assert client .get ("/generator" ).status_code == 200
7171 assert client .get ("/generator/" ).status_code == 200
@@ -85,6 +85,7 @@ def test_llm_placeholder_renders(client):
8585
8686# ── Session recovery ─────────────────────────────────────────────────────
8787
88+
8889def test_advancing_with_no_session_redirects_to_landing (client ):
8990 """Formerly returned a 400 "Error: Params missing in session" — now we
9091 redirect the user back to /generator so they can restart cleanly. This
@@ -97,6 +98,7 @@ def test_advancing_with_no_session_redirects_to_landing(client):
9798
9899# ── Happy path + contract ────────────────────────────────────────────────
99100
101+
100102def test_full_happy_path_produces_valid_params (client ):
101103 _walk_happy_path (client )
102104 r = client .get ("/generator/random/params-json" )
@@ -114,49 +116,51 @@ def test_step5_renders_when_session_ready(client):
114116
115117# ── Regression: 1.0007 slider sum ─────────────────────────────────────────
116118
119+
117120def test_parent_child_slider_sum_1p0007_renormalises (client ):
118121 """The slider rounds each segment to 4 decimals, which can leave up to
119122 0.0007 residue. The route must renormalise to exactly 1.0 before
120123 constructing Params."""
121124 client .post ("/generator/random/step1" , data = STEP1 )
122125 poisoned = dict (STEP2 )
123- poisoned .update ({
124- "dist_optional" : "0.2502" ,
125- "dist_mandatory" : "0.2502" ,
126- "dist_alternative" : "0.2502" ,
127- "dist_or" : "0.2501" ,
128- })
126+ poisoned .update (
127+ {
128+ "dist_optional" : "0.2502" ,
129+ "dist_mandatory" : "0.2502" ,
130+ "dist_alternative" : "0.2502" ,
131+ "dist_or" : "0.2501" ,
132+ }
133+ )
129134 r = client .post ("/generator/random/step2" , data = poisoned )
130135 assert r .status_code == 302 # reached step3, Params built OK
131136
132137 params = json .loads (client .get ("/generator/random/params-json" ).data )
133138 total = (
134- params ["DIST_OPTIONAL" ] + params ["DIST_MANDATORY" ]
135- + params ["DIST_ALTERNATIVE" ] + params ["DIST_OR" ]
139+ params ["DIST_OPTIONAL" ]
140+ + params ["DIST_MANDATORY" ]
141+ + params ["DIST_ALTERNATIVE" ]
142+ + params ["DIST_OR" ]
136143 + params ["DIST_GROUP_CARDINALITY" ]
137144 )
138145 assert abs (total - 1.0 ) < 1e-6
139146
140147
141148# ── Regression: boolean-ops sum residue ───────────────────────────────────
142149
150+
143151def test_boolean_ops_residue_renormalises (client ):
144152 _walk_happy_path (
145153 client ,
146- step3 = {** STEP3 ,
147- "prob_and" : "0.3334" , "prob_or" : "0.3333" ,
148- "prob_implies" : "0.1667" , "prob_equiv" : "0.1666" },
154+ step3 = {** STEP3 , "prob_and" : "0.3334" , "prob_or" : "0.3333" , "prob_implies" : "0.1667" , "prob_equiv" : "0.1666" },
149155 )
150156 params = json .loads (client .get ("/generator/random/params-json" ).data )
151- total = (
152- params ["PROB_AND" ] + params ["PROB_OR_CT" ]
153- + params ["PROB_IMPLICATION" ] + params ["PROB_EQUIVALENCE" ]
154- )
157+ total = params ["PROB_AND" ] + params ["PROB_OR_CT" ] + params ["PROB_IMPLICATION" ] + params ["PROB_EQUIVALENCE" ]
155158 assert abs (total - 1.0 ) < 1e-6
156159
157160
158161# ── Regression: EXTRA_CONSTRAINT_REPRESENTATIVENESS "0.5" ─────────────────
159162
163+
160164def test_extra_constraint_representativeness_is_int_in_session (client ):
161165 _walk_happy_path (client )
162166 params = json .loads (client .get ("/generator/random/params-json" ).data )
@@ -166,20 +170,26 @@ def test_extra_constraint_representativeness_is_int_in_session(client):
166170
167171# ── Regression: Spanish-locale decimal comma ──────────────────────────────
168172
173+
169174def test_spanish_locale_decimal_comma_is_accepted (client ):
170175 _walk_happy_path (
171176 client ,
172- step3 = {** STEP3 ,
173- "prob_not" : "0,3" ,
174- "prob_and" : "0,4" , "prob_or" : "0,2" ,
175- "prob_implies" : "0,2" , "prob_equiv" : "0,2" },
177+ step3 = {
178+ ** STEP3 ,
179+ "prob_not" : "0,3" ,
180+ "prob_and" : "0,4" ,
181+ "prob_or" : "0,2" ,
182+ "prob_implies" : "0,2" ,
183+ "prob_equiv" : "0,2" ,
184+ },
176185 )
177186 params = json .loads (client .get ("/generator/random/params-json" ).data )
178187 assert params ["PROB_NOT" ] == pytest .approx (0.3 )
179188
180189
181190# ── Regression: back navigation keeps state ───────────────────────────────
182191
192+
183193def test_back_nav_from_step3_preserves_step2_choices (client ):
184194 # Advance to step3 with a specific max_features
185195 client .post ("/generator/random/step1" , data = STEP1 )
0 commit comments