@Test
 public void combo_1() throws Exception {
   String origContents =
       "*Setting\nTest Setup  K0\n*Test Cases\nTestCase\n  K1\n  [Arguments]  ${abc}\n  [Setup]  K2\n  K3\nTestCase2  [Teardown]  K4\n  ...  arg1\n  K5\n*Settings\nTest Teardown  K6\n*Keywords\nKeyword\n  K7\n  [Teardown]  K8\n  Run Keyword  K9\nRun Keyword";
   IFile origFile = addFile("orig.txt", origContents);
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(10, 1));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   int n = 10;
   assertEquals(proposals.toString(), n, proposals.size());
   String[] callLocationRegexps = {
     "SETTING Test Setup",
     "TEST CASE TestCase",
     "TEST CASE TestCase, via SETTING [Setup]",
     "TEST CASE TestCase",
     "TEST CASE TestCase2, via SETTING [Teardown]",
     "TEST CASE TestCase2",
     "SETTING Test Teardown",
     "KEYWORD Keyword",
     "KEYWORD Keyword, via SETTING [Teardown]",
     "KEYWORD Keyword",
   };
   for (int i = 0; i < n; ++i) {
     try {
       assertEquals("K" + i, proposals.get(i).getMatchArgument());
       assertThat(
           htmlToText(proposals.get(i).getAdditionalProposalInfo()),
           is(PREAMBLE + "- " + callLocationRegexps[i] + ""));
     } catch (AssertionError e) {
       throw new Error("For i = " + i, e);
     }
   }
 }
 @Test
 public void should_propose_missing_keyword_used_multiple_times_only_once() throws Exception {
   IFile origFile =
       addFile(
           "orig.txt",
           "*"
               + table
               + "\nTestCaseOrKeyword1\n  Missing keyword\nTestCaseOrKeyword2\n  Missing keyword\n");
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 1, proposals.size());
   assertEquals("Missing keyword", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(
           PREAMBLE
               + "- "
               + callHostIdentifier
               + " TestCaseOrKeyword1\n- "
               + callHostIdentifier
               + " TestCaseOrKeyword2"));
 }
 @Test
 public void should_not_propose_keyword_definition_for_premature_keyword_calls()
     throws Exception {
   IFile origFile = addFile("orig.txt", "*" + table + "\n  Premature keyword");
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 0, proposals.size());
 }
 @Test
 public void should_propose_keyword_on_continuation_line() throws Exception {
   IFile origFile = addFile("orig.txt", "*Settings\nTest Setup\n...  Missing keyword");
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 1, proposals.size());
   assertEquals("Missing keyword", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(PREAMBLE + "- SETTING Test Setup"));
 }
 @Test
 public void should_not_propose_regular_call_matched_by_wildcard_keyword_definition()
     throws Exception {
   IFile origFile =
       addFile(
           "orig.txt",
           "*" + table + "\nTestCaseOrKeyword\n  Say hello\n*Keywords\nSay ${something}");
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 0, proposals.size());
 }
 @Test
 public void should_not_propose_locally_missing_keywords_actually_found_in_included_library()
     throws Exception {
   IFile origFile =
       addFile(
           "orig.txt",
           "*Settings\nLibrary  MyLibrary\nSuite Setup  Existing keyword\nSuite Setup  Missing keyword 1  argument1");
   addLibraryIndex("MyLibrary", "Existing keyword\n");
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 1, proposals.size());
   assertEquals("Missing keyword 1", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(PREAMBLE + "- SETTING Suite Setup"));
 }
 @Test
 public void should_not_propose_keywords_missing_from_included_file() throws Exception {
   IFile origFile =
       addFile(
           "orig.txt",
           "*Settings\nResource  other.txt\nSuite Teardown  Missing keyword 1  argument1");
   IFile otherFile =
       addFile("other.txt", "*Settings\nSuite Teardown  Missing keyword 2  argument2\n");
   when(resourceManager.getRelativeFile(origFile, "other.txt")).thenReturn(otherFile);
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 1, proposals.size());
   assertEquals("Missing keyword 1", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(PREAMBLE + "- SETTING Suite Teardown"));
 }
 @Test
 public void should_not_propose_builtin_keyword() throws Exception {
   IFile origFile =
       addFile(
           "orig.txt",
           "*"
               + table
               + "\nTestCaseOrKeyword\n  [Setup]  "
               + BUILTIN_KEYWORD
               + "\n  [Setup]  Missing keyword 1  argument1");
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 1, proposals.size());
   assertEquals("Missing keyword 1", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(PREAMBLE + "- " + callHostIdentifier + " TestCaseOrKeyword, via SETTING [Setup]"));
 }
 @Test
 public void should_propose_keyword_at_cursor_as_missing() throws Exception {
   Content origContents =
       new Content(
           "*Settings\nTest Teardown  Existing keyword\nTest Teardown  Missing keyword 1  argument1\n*Keywords\n<arg>Existing keyword<argend>");
   IFile origFile = addFile("orig.txt", origContents.c());
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, origContents.ps("arg-argend", 0, ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 2, proposals.size());
   assertEquals("Existing keyword", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(PREAMBLE + "- SETTING Test Teardown"));
   assertEquals("Missing keyword 1", proposals.get(1).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(1).getAdditionalProposalInfo()),
       is(PREAMBLE + "- SETTING Test Teardown"));
 }
 @Test
 public void should_propose_missing_keywords_in_single_file() throws Exception {
   IFile origFile =
       addFile(
           "orig.txt",
           "*Settings\nTest Setup  Existing keyword\nTest Setup  Missing keyword 1  argument1\n*Keywords\nExisting keyword\n  Missing keyword 2  argument2");
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 2, proposals.size());
   assertEquals("Missing keyword 1", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(PREAMBLE + "- SETTING Test Setup"));
   assertEquals("Missing keyword 2", proposals.get(1).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(1).getAdditionalProposalInfo()),
       is(PREAMBLE + "- KEYWORD Existing keyword"));
 }
 @Test
 public void
     should_not_propose_regular_calls_matched_by_wildcard_keyword_definitions_mixed_with_regular()
         throws Exception {
   IFile origFile =
       addFile(
           "orig.txt",
           "*"
               + table
               + "\nTestCaseOrKeyword\n  Say hello\n  Missing keyword\n  Existing keyword\n*Keywords\nSay ${something}\n${action} database\nExisting keyword\n");
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 1, proposals.size());
   assertEquals("Missing keyword", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(PREAMBLE + "- " + callHostIdentifier + " TestCaseOrKeyword"));
 }
 @Test
 public void should_not_propose_locally_missing_keywords_actually_found_in_included_file()
     throws Exception {
   IFile origFile =
       addFile(
           "orig.txt",
           "*Setting\nResource  other.txt\n*"
               + table
               + "\nTestCaseOrKeyword\n  [Template]  Existing keyword\n  [Template]  Missing keyword 1");
   IFile otherFile = addFile("other.txt", "*Keywords\nExisting keyword\n");
   when(resourceManager.getRelativeFile(origFile, "other.txt")).thenReturn(otherFile);
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, new ParsedString("", 0).setType(ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet = visitor.visitAttempt("", new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 1, proposals.size());
   assertEquals("Missing keyword 1", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(PREAMBLE + "- " + callHostIdentifier + " TestCaseOrKeyword, via SETTING [Template]"));
 }
 @Test
 public void should_filter_missing_keywords_by_attempted_prefix() throws Exception {
   Content origContents =
       new Content(
           "*Settings\nSuite Setup  Existing keyword\nSuite Teardown  Keyword missing 1  argument1\nTest Setup  Keyword missing 2\nTest Teardown  Keyword existing\nTest Template  Non-existent but mismatching prefix\n*Keywords\nKeyword existing\n<arg>Keyword <cursor>missing 1<argend>");
   IFile origFile = addFile("orig.txt", origContents.c());
   visitor =
       new KeywordDefinitionAttemptVisitor(
           origFile, origContents.ps("arg-argend", 0, ArgumentType.NEW_KEYWORD));
   RobotCompletionProposalSet proposalSet =
       visitor.visitAttempt(origContents.s("arg-cursor").toLowerCase(), new Region(0, 0));
   List<RobotCompletionProposal> proposals = proposalSet.getProposals();
   assertEquals(proposals.toString(), 2, proposals.size());
   assertEquals("Keyword missing 1", proposals.get(0).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(0).getAdditionalProposalInfo()),
       is(PREAMBLE + "- SETTING Suite Teardown"));
   assertEquals("Keyword missing 2", proposals.get(1).getMatchArgument());
   assertThat(
       htmlToText(proposals.get(1).getAdditionalProposalInfo()),
       is(PREAMBLE + "- SETTING Test Setup"));
 }