ForLoopIterationContext extends DefaultContext { public static StackFrameContext findContextForLoopIteration(final StackFrameContext currentContext, final String keywordName) { if (!(currentContext instanceof ForLoopContext)) { throw new IllegalDebugContextStateException( "For loop iteration can only be called when already context was moved to for-loop context"); } final URI uri = currentContext.getAssociatedPath().orElse(null); if (currentContext.isErroneous()) { final String errorMsg = String.format(ErrorMessages.executableIterationNotFound, keywordName); return new ForLoopIterationContext(uri, currentContext.getFileRegion().orElse(null), errorMsg); } final ForLoopContext execContext = (ForLoopContext) currentContext; final FileRegion region = execContext.currentElement().getForVariablesRegion(); final List<RobotToken> tokens = execContext.currentElement().getForVariables(); final List<String> actualIterators = extractVariablesUsed(keywordName); final List<String> expectedIterators = tokens.stream().map(RobotToken::getText).collect(toList()); if (actualIterators.equals(expectedIterators)) { return new ForLoopIterationContext(execContext.currentElement(), uri, region); } else { final String errorMsg = String.format(ErrorMessages.executableIterationMismatch, actualIterators.stream().collect(joining(", ")), expectedIterators.stream().collect(joining(", "))); return new ForLoopIterationContext(execContext.currentElement(), uri, region, errorMsg); } } @VisibleForTesting  ForLoopIterationContext(final URI locationUri, final FileRegion region, final String errorMsg); @VisibleForTesting  ForLoopIterationContext(final ExecutableWithDescriptor forLoopExecutable, final URI locationUri,
            final FileRegion region); @VisibleForTesting  ForLoopIterationContext(final ExecutableWithDescriptor forLoopExecutable, final URI locationUri,
            final FileRegion region, final String errorMsg); static StackFrameContext findContextForLoopIteration(final StackFrameContext currentContext,
            final String keywordName); @Override boolean isErroneous(); @Override Optional<String> getErrorMessage(); @Override Optional<URI> getAssociatedPath(); @Override Optional<FileRegion> getFileRegion(); @Override StackFrameContext moveTo(final RunningKeyword keyword, final RobotBreakpointSupplier breakpointSupplier);  }
@Test public void itIsIllegalToConstructForLoopContext_whenCurrentFrameContextIsNotForLoopContext() { assertThatExceptionOfType(IllegalDebugContextStateException.class) .isThrownBy( () -> ForLoopIterationContext.findContextForLoopIteration(mock(StackFrameContext.class), "${x} = 1")) .withMessage("For loop iteration can only be called when already context was moved to for-loop context") .withNoCause(); }