Skip to content

Commit 438595c

Browse files
Merge pull request #49 from lambda-feedback/validation_fix
refactor: improve validation logic and update tests for epsilon trans…
2 parents d9a2e73 + 64b6d06 commit 438595c

4 files changed

Lines changed: 67 additions & 119 deletions

File tree

evaluation_function/schemas/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"Params",
1919
# Result
2020
"Result",
21-
"ValidationResult"
21+
"ValidationResult",
2222
"ValidationError",
2323
"ElementHighlight",
2424
"ErrorCode",

evaluation_function/test/test_correction.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,19 @@ def test_non_minimal_fsa_fails_when_required(self, equivalent_dfa):
214214
class TestEpsilonTransitionCorrection:
215215
"""Test the full correction pipeline with ε-NFA inputs."""
216216

217-
def test_epsilon_nfa_vs_equivalent_dfa_correct(self):
217+
@pytest.fixture
218+
def nfa_params(self):
219+
"""Params that allow NFA/ε-NFA student submissions."""
220+
return Params(
221+
expected_type="any",
222+
check_completeness=False,
223+
check_minimality=False,
224+
evaluation_mode="lenient",
225+
highlight_errors=True,
226+
feedback_verbosity="detailed",
227+
)
228+
229+
def test_epsilon_nfa_vs_equivalent_dfa_correct(self, nfa_params):
218230
"""ε-NFA student answer equivalent to DFA expected should be correct."""
219231
# ε-NFA accepts exactly "a": q0 --ε--> q1 --a--> q2
220232
student_enfa = make_fsa(
@@ -237,11 +249,11 @@ def test_epsilon_nfa_vs_equivalent_dfa_correct(self):
237249
initial="s0",
238250
accept=["s1"],
239251
)
240-
result = analyze_fsa_correction(student_enfa, expected_dfa)
252+
result = analyze_fsa_correction(student_enfa, expected_dfa, nfa_params)
241253
assert isinstance(result, Result)
242254
assert result.is_correct is True
243255

244-
def test_epsilon_nfa_vs_different_dfa_incorrect(self):
256+
def test_epsilon_nfa_vs_different_dfa_incorrect(self, nfa_params):
245257
"""ε-NFA accepting 'a' vs DFA accepting 'b' should be incorrect."""
246258
student_enfa = make_fsa(
247259
states=["q0", "q1", "q2"],
@@ -262,13 +274,13 @@ def test_epsilon_nfa_vs_different_dfa_incorrect(self):
262274
initial="s0",
263275
accept=["s1"],
264276
)
265-
result = analyze_fsa_correction(student_enfa, expected_dfa)
277+
result = analyze_fsa_correction(student_enfa, expected_dfa, nfa_params)
266278
assert isinstance(result, Result)
267279
assert result.is_correct is False
268280
assert result.fsa_feedback is not None
269281
assert len(result.fsa_feedback.errors) > 0
270282

271-
def test_multi_epsilon_nfa_vs_dfa_correct(self):
283+
def test_multi_epsilon_nfa_vs_dfa_correct(self, nfa_params):
272284
"""ε-NFA for (a|b) with branching epsilons should match equivalent DFA."""
273285
student_enfa = make_fsa(
274286
states=["q0", "q1", "q2", "q3"],
@@ -292,11 +304,11 @@ def test_multi_epsilon_nfa_vs_dfa_correct(self):
292304
initial="s0",
293305
accept=["s1"],
294306
)
295-
result = analyze_fsa_correction(student_enfa, expected_dfa)
307+
result = analyze_fsa_correction(student_enfa, expected_dfa, nfa_params)
296308
assert isinstance(result, Result)
297309
assert result.is_correct is True
298310

299-
def test_epsilon_nfa_structural_info_reports_nondeterministic(self):
311+
def test_epsilon_nfa_structural_info_reports_nondeterministic(self, nfa_params):
300312
"""ε-NFA should have structural info reporting non-deterministic."""
301313
student_enfa = make_fsa(
302314
states=["q0", "q1", "q2"],
@@ -317,7 +329,7 @@ def test_epsilon_nfa_structural_info_reports_nondeterministic(self):
317329
initial="s0",
318330
accept=["s1"],
319331
)
320-
result = analyze_fsa_correction(student_enfa, expected_dfa)
332+
result = analyze_fsa_correction(student_enfa, expected_dfa, nfa_params)
321333
assert result.fsa_feedback is not None
322334
assert result.fsa_feedback.structural is not None
323335
assert result.fsa_feedback.structural.is_deterministic is False

evaluation_function/test/test_validation.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ def test_isomorphic_dfas(self):
314314
initial="s0",
315315
accept=["s1"],
316316
)
317-
assert are_isomorphic(fsa_user, fsa_sol) == []
317+
assert are_isomorphic(fsa_user, fsa_sol).ok
318318

319319

320320
class TestEpsilonTransitions:
@@ -332,7 +332,7 @@ def test_valid_fsa_with_epsilon_unicode(self):
332332
initial="q0",
333333
accept=["q2"],
334334
)
335-
assert is_valid_fsa(fsa) == []
335+
assert is_valid_fsa(fsa).ok
336336

337337
def test_valid_fsa_with_epsilon_string(self):
338338
"""ε-NFA with 'epsilon' string should pass structural validation."""
@@ -346,7 +346,7 @@ def test_valid_fsa_with_epsilon_string(self):
346346
initial="q0",
347347
accept=["q2"],
348348
)
349-
assert is_valid_fsa(fsa) == []
349+
assert is_valid_fsa(fsa).ok
350350

351351
def test_valid_fsa_with_empty_string_epsilon(self):
352352
"""ε-NFA with empty string epsilon should pass structural validation."""
@@ -360,7 +360,7 @@ def test_valid_fsa_with_empty_string_epsilon(self):
360360
initial="q0",
361361
accept=["q2"],
362362
)
363-
assert is_valid_fsa(fsa) == []
363+
assert is_valid_fsa(fsa).ok
364364

365365
def test_epsilon_nfa_is_not_deterministic(self):
366366
"""ε-NFA should be flagged as non-deterministic."""
@@ -373,9 +373,9 @@ def test_epsilon_nfa_is_not_deterministic(self):
373373
initial="q0",
374374
accept=["q1"],
375375
)
376-
errors = is_deterministic(fsa)
377-
assert len(errors) > 0
378-
assert ErrorCode.NOT_DETERMINISTIC in [e.code for e in errors]
376+
result = is_deterministic(fsa)
377+
assert not result.ok
378+
assert ErrorCode.NOT_DETERMINISTIC in [e.code for e in result.errors]
379379

380380
def test_accepts_string_via_epsilon_closure(self):
381381
"""ε-NFA should accept 'a' by following q0 --ε--> q1 --a--> q2."""
@@ -389,7 +389,7 @@ def test_accepts_string_via_epsilon_closure(self):
389389
initial="q0",
390390
accept=["q2"],
391391
)
392-
assert accepts_string(fsa, "a") == []
392+
assert accepts_string(fsa, "a").ok
393393

394394
def test_rejects_string_with_epsilon_nfa(self):
395395
"""ε-NFA that accepts 'a' should reject empty string."""
@@ -403,8 +403,8 @@ def test_rejects_string_with_epsilon_nfa(self):
403403
initial="q0",
404404
accept=["q2"],
405405
)
406-
errors = accepts_string(fsa, "")
407-
assert len(errors) > 0
406+
result = accepts_string(fsa, "")
407+
assert not result.ok
408408

409409
def test_accepts_empty_string_via_epsilon(self):
410410
"""ε-NFA should accept empty string when initial reaches accept via ε."""
@@ -417,7 +417,7 @@ def test_accepts_empty_string_via_epsilon(self):
417417
initial="q0",
418418
accept=["q1"],
419419
)
420-
assert accepts_string(fsa, "") == []
420+
assert accepts_string(fsa, "").ok
421421

422422
def test_epsilon_nfa_equivalent_to_dfa(self):
423423
"""ε-NFA and DFA accepting the same language should be equivalent."""
@@ -440,7 +440,7 @@ def test_epsilon_nfa_equivalent_to_dfa(self):
440440
initial="s0",
441441
accept=["s1"],
442442
)
443-
assert fsas_accept_same_language(enfa, dfa) == []
443+
assert fsas_accept_same_language(enfa, dfa).ok
444444

445445
def test_epsilon_nfa_not_equivalent_to_different_dfa(self):
446446
"""ε-NFA and DFA accepting different languages should not be equivalent."""
@@ -463,8 +463,8 @@ def test_epsilon_nfa_not_equivalent_to_different_dfa(self):
463463
initial="s0",
464464
accept=["s1"],
465465
)
466-
errors = fsas_accept_same_language(enfa, dfa)
467-
assert len(errors) > 0
466+
result = fsas_accept_same_language(enfa, dfa)
467+
assert not result.ok
468468

469469
def test_multi_epsilon_nfa_equivalent_to_dfa(self):
470470
"""ε-NFA for (a|b) with branching epsilons should match equivalent DFA."""
@@ -491,7 +491,7 @@ def test_multi_epsilon_nfa_equivalent_to_dfa(self):
491491
initial="s0",
492492
accept=["s1"],
493493
)
494-
assert fsas_accept_same_language(enfa, dfa) == []
494+
assert fsas_accept_same_language(enfa, dfa).ok
495495

496496

497497
if __name__ == "__main__":

0 commit comments

Comments
 (0)