Skip to content

Commit 6174b3e

Browse files
committed
Add transition count methods to NFA and TM; implement states retrieval in PDA; remove AutomatonMetrics and its tests
1 parent 40d4280 commit 6174b3e

File tree

7 files changed

+282
-310
lines changed

7 files changed

+282
-310
lines changed

src/main/java/NondeterministicFiniteAutomaton/NFA.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,14 @@ public Map<State, List<FSATransition>> getTransitions() {
941941
return transitions;
942942
}
943943

944+
/**
945+
* Returns the total number of transitions in the NFA.
946+
* @return the total transition count
947+
*/
948+
public int getTransitionCount() {
949+
return transitions.values().stream().mapToInt(List::size).sum();
950+
}
951+
944952
@Override
945953
public String getDefaultTemplate() {
946954
return "Start: q1\n" +

src/main/java/PushDownAutomaton/PDA.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,15 @@ public int getTransitionCount() {
392392
return transitionMap.values().stream().mapToInt(List::size).sum();
393393
}
394394

395+
/**
396+
* Returns the set of states in this PDA.
397+
*
398+
* @return the set of states
399+
*/
400+
public Set<State> getStates() {
401+
return states != null ? Collections.unmodifiableSet(states) : Collections.emptySet();
402+
}
403+
395404
/**
396405
* Validates the number of transitions against a maximum limit.
397406
*

src/main/java/TuringMachine/TM.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,14 @@ public List<ValidationMessage> validate(String inputText) {
234234
return TMFileValidator.validateFromString(inputText);
235235
}
236236

237+
/**
238+
* Returns the total number of transitions in the Turing Machine.
239+
* @return the total transition count
240+
*/
241+
public int getTransitionCount() {
242+
return transitionFunction.size();
243+
}
244+
237245
@Override
238246
public String getDefaultTemplate() {
239247
return "start: q0\n" +

src/main/java/viewmodel/AutomatonMetrics.java

Lines changed: 0 additions & 114 deletions
This file was deleted.

src/test/java/controller/AutomatonControllerTest.java

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import static org.junit.jupiter.api.Assertions.assertTrue;
1717
import org.junit.jupiter.api.BeforeEach;
1818
import org.junit.jupiter.api.DisplayName;
19+
import org.junit.jupiter.api.Nested;
1920
import org.junit.jupiter.api.Test;
2021
import org.junit.jupiter.api.io.TempDir;
2122

@@ -29,6 +30,7 @@
2930
import service.SessionService;
3031
import service.TestService;
3132
import service.VisualizationService;
33+
import viewmodel.TestResultViewModel;
3234

3335
/**
3436
* Integration tests for AutomatonController.
@@ -359,6 +361,175 @@ void defaultConstructor_works() {
359361
assertNotNull(dfa);
360362
}
361363

364+
// ═══════════════════════════════════════════════════════════════════
365+
// ViewModel Test Execution Tests
366+
// ═══════════════════════════════════════════════════════════════════
367+
368+
@Nested
369+
@DisplayName("ViewModel Test Execution")
370+
class ViewModelTestExecutionTests {
371+
372+
// Valid CFG definition with 8 rules (S -> aB | bA, A -> a | aS | bAA, B -> b | bS | aBB)
373+
private static final String CFG_WITH_MANY_RULES =
374+
"Variables = S A B\n" +
375+
"Terminals = a b\n" +
376+
"Start = S\n" +
377+
"\n" +
378+
"S -> a B | b A\n" +
379+
"A -> a | a S | b A A\n" +
380+
"B -> b | b S | a B B\n";
381+
382+
// Valid PDA with 5 transitions
383+
private static final String PDA_WITH_TRANSITIONS =
384+
"states: q0 q1 q2 q3\n" +
385+
"alphabet: a b\n" +
386+
"stack_alphabet: a Z\n" +
387+
"start: q0\n" +
388+
"stack_start: Z\n" +
389+
"finals: q3\n" +
390+
"transitions:\n" +
391+
"q0 a Z -> q1 aZ\n" +
392+
"q0 a a -> q1 aa\n" +
393+
"q1 b a -> q2 eps\n" +
394+
"q2 b a -> q2 eps\n" +
395+
"q2 eps Z -> q3 eps\n";
396+
397+
@Test
398+
@DisplayName("runTestsWithViewModel returns success for DFA")
399+
void testRunTestsWithViewModel_DFASuccess() throws Exception {
400+
Automaton dfa = controller.createAutomaton(MachineType.DFA);
401+
controller.parse(dfa, VALID_DFA);
402+
403+
// Create test file with CSV format: input,expected (1=accept, 0=reject)
404+
File testFile = tempDir.resolve("test.test").toFile();
405+
writeFile(testFile, "0,1\n1,0\n");
406+
407+
TestResultViewModel result = controller.runTestsWithViewModel(dfa, testFile.getAbsolutePath(), null);
408+
409+
assertNotNull(result);
410+
assertFalse(result.hasLimitViolation());
411+
assertEquals(2, result.getTotalTests());
412+
}
413+
414+
@Test
415+
@DisplayName("runTestsWithViewModel returns CFG violation when rules exceed limit")
416+
void testRunTestsWithViewModel_CFGViolation() throws Exception {
417+
Automaton cfg = controller.createAutomaton(MachineType.CFG);
418+
controller.parse(cfg, CFG_WITH_MANY_RULES);
419+
420+
// Create test file
421+
File testFile = tempDir.resolve("test.test").toFile();
422+
writeFile(testFile, "ab,1\n");
423+
424+
// Set settings with max 3 rules (CFG has 8)
425+
controller.setTestSettings(new SessionService.TestSettings(0, 100, 30, 3, null, null));
426+
427+
TestResultViewModel result = controller.runTestsWithViewModel(cfg, testFile.getAbsolutePath(), null);
428+
429+
assertNotNull(result);
430+
assertTrue(result.hasLimitViolation());
431+
assertEquals("CFG_RULES", result.getLimitViolationType());
432+
assertEquals(0.0, result.getEarnedPoints());
433+
}
434+
435+
@Test
436+
@DisplayName("runTestsWithViewModel returns PDA violation when transitions exceed limit")
437+
void testRunTestsWithViewModel_PDAViolation() throws Exception {
438+
Automaton pda = controller.createAutomaton(MachineType.PDA);
439+
controller.parse(pda, PDA_WITH_TRANSITIONS);
440+
441+
// Create test file
442+
File testFile = tempDir.resolve("test.test").toFile();
443+
writeFile(testFile, "ab,1\n");
444+
445+
// Set settings with max 2 transitions (PDA has 5)
446+
controller.setTestSettings(new SessionService.TestSettings(0, 100, 30, null, 2, null));
447+
448+
TestResultViewModel result = controller.runTestsWithViewModel(pda, testFile.getAbsolutePath(), null);
449+
450+
assertNotNull(result);
451+
assertTrue(result.hasLimitViolation());
452+
assertEquals("PDA_TRANSITIONS", result.getLimitViolationType());
453+
assertEquals(0.0, result.getEarnedPoints());
454+
}
455+
}
456+
457+
// ═══════════════════════════════════════════════════════════════════
458+
// Limit Validation Tests
459+
// ═══════════════════════════════════════════════════════════════════
460+
461+
@Nested
462+
@DisplayName("Limit Validation")
463+
class LimitValidationTests {
464+
465+
@Test
466+
@DisplayName("validateLimits returns CFG violation when rules exceed limit")
467+
void testValidateLimits_CFGViolation() {
468+
String cfgInput =
469+
"Variables = S A B\n" +
470+
"Terminals = a b\n" +
471+
"Start = S\n" +
472+
"\n" +
473+
"S -> a B | b A\n" +
474+
"A -> a | a S | b A A\n" +
475+
"B -> b | b S | a B B\n";
476+
477+
Automaton cfg = controller.createAutomaton(MachineType.CFG);
478+
controller.parse(cfg, cfgInput);
479+
480+
// Set settings with max 3 rules (CFG has 8)
481+
controller.setTestSettings(new SessionService.TestSettings(0, 100, 30, 3, null, null));
482+
483+
ValidationMessage violation = controller.validateLimits(cfg);
484+
485+
assertNotNull(violation);
486+
assertTrue(violation.getMessage().contains("CFG"));
487+
}
488+
489+
@Test
490+
@DisplayName("validateLimits returns PDA violation when transitions exceed limit")
491+
void testValidateLimits_PDAViolation() {
492+
String pdaInput =
493+
"states: q0 q1 q2 q3\n" +
494+
"alphabet: a b\n" +
495+
"stack_alphabet: a Z\n" +
496+
"start: q0\n" +
497+
"stack_start: Z\n" +
498+
"finals: q3\n" +
499+
"transitions:\n" +
500+
"q0 a Z -> q1 aZ\n" +
501+
"q0 a a -> q1 aa\n" +
502+
"q1 b a -> q2 eps\n" +
503+
"q2 b a -> q2 eps\n" +
504+
"q2 eps Z -> q3 eps\n";
505+
506+
Automaton pda = controller.createAutomaton(MachineType.PDA);
507+
controller.parse(pda, pdaInput);
508+
509+
// Set settings with max 2 transitions (PDA has 5)
510+
controller.setTestSettings(new SessionService.TestSettings(0, 100, 30, null, 2, null));
511+
512+
ValidationMessage violation = controller.validateLimits(pda);
513+
514+
assertNotNull(violation);
515+
assertTrue(violation.getMessage().contains("PDA"));
516+
}
517+
518+
@Test
519+
@DisplayName("validateLimits returns null when within limits")
520+
void testValidateLimits_NoViolation() {
521+
Automaton dfa = controller.createAutomaton(MachineType.DFA);
522+
controller.parse(dfa, VALID_DFA);
523+
524+
// Set permissive settings
525+
controller.setTestSettings(new SessionService.TestSettings(0, 100, 30, 100, 100, null));
526+
527+
ValidationMessage violation = controller.validateLimits(dfa);
528+
529+
assertNull(violation);
530+
}
531+
}
532+
362533
// ═══════════════════════════════════════════════════════════════════
363534
// Helper Methods
364535
// ═══════════════════════════════════════════════════════════════════

0 commit comments

Comments
 (0)