private static void assertMethodAndParameterAnnotationsValues(
      ExternalAnnotationsManager manager,
      PsiMethod method,
      PsiParameter parameter,
      String expectedValue) {
    PsiAnnotation methodAnnotation =
        manager.findExternalAnnotation(method, AnnotationUtil.NULLABLE);
    assertNotNull(methodAnnotation);
    assertEquals(expectedValue, methodAnnotation.findAttributeValue("value").getText());

    PsiAnnotation parameterAnnotation =
        manager.findExternalAnnotation(parameter, AnnotationUtil.NOT_NULL);
    assertNotNull(parameterAnnotation);
    assertEquals(expectedValue, parameterAnnotation.findAttributeValue("value").getText());
  }
  public void testListenerNotifiedOnExternalChanges() {
    addDefaultLibrary();
    myFixture.configureByFiles("/content/anno/p/annotations.xml");
    myFixture.configureByFiles("lib/p/Test.java");

    ExternalAnnotationsManager.getInstance(myProject)
        .findExternalAnnotation(getOwner(), AnnotationUtil.NOT_NULL); // force creating service

    startListeningForExternalChanges();
    new WriteCommandAction(myProject) {
      @Override
      protected void run(final Result result) throws Throwable {
        VirtualFile file =
            LocalFileSystem.getInstance()
                .findFileByPath(myFixture.getTempDirPath() + "/content/anno/p/annotations.xml");
        assert file != null;
        String newText =
            "  "
                + StreamUtil.readText(file.getInputStream())
                + "      "; // adding newspace to the beginning and end of file
        FileUtil.writeToFile(
            VfsUtil.virtualToIoFile(file),
            newText); // writing using java.io.File to make this change external
        file.refresh(false, false);
      }
    }.execute();
    stopListeningAndCheckEvents();
  }
  public void testEditingMultiRootAnnotations() {
    addLibrary("/content/annoMultiRoot/root1", "/content/annoMultiRoot/root2");
    myFixture.configureByFiles(
        "/content/annoMultiRoot/root1/multiRoot/annotations.xml",
        "/content/annoMultiRoot/root2/multiRoot/annotations.xml");
    myFixture.configureByFiles("lib/multiRoot/Test.java");

    final ExternalAnnotationsManager manager = ExternalAnnotationsManager.getInstance(myProject);
    final PsiMethod method = ((PsiJavaFile) myFixture.getFile()).getClasses()[0].getMethods()[0];
    final PsiParameter parameter = method.getParameterList().getParameters()[0];

    assertMethodAndParameterAnnotationsValues(manager, method, parameter, "\"foo\"");

    final PsiAnnotation annotationFromText =
        JavaPsiFacade.getElementFactory(myProject)
            .createAnnotationFromText("@Annotation(value=\"bar\")", null);

    startListening(method, AnnotationUtil.NULLABLE, true);
    new WriteCommandAction(myProject) {
      @Override
      protected void run(final Result result) throws Throwable {
        manager.editExternalAnnotation(
            method, AnnotationUtil.NULLABLE, annotationFromText.getParameterList().getAttributes());
      }
    }.execute();
    stopListeningAndCheckEvents();

    startListening(parameter, AnnotationUtil.NOT_NULL, true);
    new WriteCommandAction(myProject) {
      @Override
      protected void run(final Result result) throws Throwable {
        manager.editExternalAnnotation(
            parameter,
            AnnotationUtil.NOT_NULL,
            annotationFromText.getParameterList().getAttributes());
      }
    }.execute();
    stopListeningAndCheckEvents();

    assertMethodAndParameterAnnotationsValues(manager, method, parameter, "\"bar\"");

    myFixture.checkResultByFile(
        "content/annoMultiRoot/root1/multiRoot/annotations.xml",
        "content/annoMultiRoot/root1/multiRoot/annotations_after.xml",
        false);
    myFixture.checkResultByFile(
        "content/annoMultiRoot/root2/multiRoot/annotations.xml",
        "content/annoMultiRoot/root2/multiRoot/annotations_after.xml",
        false);
  }
  public void testAnnotateLibrary() throws Throwable {

    addDefaultLibrary();
    myFixture.configureByFiles("lib/p/TestPrimitive.java", "content/anno/p/annotations.xml");
    myFixture.configureByFiles("lib/p/Test.java");
    final PsiFile file = myFixture.getFile();
    final Editor editor = myFixture.getEditor();

    final IntentionAction fix = myFixture.findSingleIntention("Annotate method 'get' as @NotNull");
    assertTrue(fix.isAvailable(myProject, editor, file));

    // expecting other @Nullable annotations to be removed, and default @NotNull to be added
    List<Trinity<PsiModifierListOwner, String, Boolean>> expectedSequence =
        new ArrayList<Trinity<PsiModifierListOwner, String, Boolean>>();
    for (String notNull : NullableNotNullManager.getInstance(myProject).getNullables()) {
      expectedSequence.add(Trinity.create(getOwner(), notNull, false));
    }
    expectedSequence.add(Trinity.create(getOwner(), AnnotationUtil.NOT_NULL, true));
    startListening(expectedSequence);
    new WriteCommandAction(myProject) {
      @Override
      protected void run(final Result result) throws Throwable {
        fix.invoke(myProject, editor, file);
      }
    }.execute();

    FileDocumentManager.getInstance().saveAllDocuments();

    final PsiElement psiElement = file.findElementAt(editor.getCaretModel().getOffset());
    assertNotNull(psiElement);
    final PsiModifierListOwner listOwner =
        PsiTreeUtil.getParentOfType(psiElement, PsiModifierListOwner.class);
    assertNotNull(listOwner);
    assertNotNull(
        ExternalAnnotationsManager.getInstance(myProject)
            .findExternalAnnotation(listOwner, AnnotationUtil.NOT_NULL));
    stopListeningAndCheckEvents();

    myFixture.checkResultByFile(
        "content/anno/p/annotations.xml",
        "content/anno/p/annotationsAnnotateLibrary_after.xml",
        false);
  }