/**
   * Test functionality of the ForgotUsername page:
   *
   * <ul>
   *   <li>A user can be found using correct email
   *   <li>No user is found using wrong email
   *   <li>Email text is properly escaped
   * </ul>
   */
  @Test
  public void testForgotUsername() {
    String space = "Test";
    String page = "SQLTestPage";
    String mail = "[email protected]"; // default Admin mail
    String user = "Admin";
    String badMail = "[email protected]";

    // Ensure there is a page we will try to find using HQL injection
    editInWikiEditor(space, page);
    setFieldValue("title", page);
    setFieldValue("content", page);
    clickEditSaveAndView();

    // test that it finds the correct user
    open("XWiki", "ForgotUsername");
    setFieldValue("e", mail);
    submit("//input[@type='submit']"); // there are no other buttons
    assertTextNotPresent("No account is registered using this email address");
    assertElementPresent("//div[@id='xwikicontent']//strong[text()='" + user + "']");

    // test that bad mail results in no results
    open("XWiki", "ForgotUsername");
    setFieldValue("e", badMail);
    submit("//input[@type='submit']"); // there are no other buttons
    assertTextPresent("No account is registered using this email address");
    assertElementNotPresent("//div[@id='xwikicontent']//strong[@value='" + user + "']");

    // XWIKI-4920 test that the email is properly escaped
    open("XWiki", "ForgotUsername");
    setFieldValue("e", "a' synta\\'x error");
    submit("//input[@type='submit']"); // there are no other buttons
    assertTextPresent("No account is registered using this email address");
    assertTextNotPresent("Error");
  }
  /*
   * Make sure html macros and pre tags are not being stripped
   * @see: http://jira.xwiki.org/jira/browse/XAADMINISTRATION-141
   *
   * Tests: XWiki.ConfigurableClass
   */
  @Test
  public void testNotStrippingHtmlMacros() {
    String space = "Main";
    String page = "TestConfigurable";
    String test = "{{html}} <pre> {{html clean=\"false\"}} </pre> {{/html}}";

    String fullName = space + "." + page;
    String form =
        "//div[@id='admin-page-content']/form[@action='/xwiki/bin/save/"
            + space
            + "/"
            + page
            + "']";

    createConfigurableApplication(space, page, "TestSection1", true);
    open(space, page, "edit", "editor=object");
    expandObject(fullName, 0);
    setFieldValue(fullName + "_0_TextArea", test);
    setFieldValue(fullName + "_0_String", test);
    clickEditSaveAndView();

    open("XWiki", "XWikiPreferences", "admin", "editor=globaladmin&section=TestSection1");
    waitForTextPresent(form + "/fieldset//textarea[@name='" + fullName + "_0_TextArea']", test);
    // Getting content from an input field required getValue and not getText
    assertTrue(
        getSelenium()
            .getValue(form + "/fieldset//input[@name='" + fullName + "_0_String']")
            .equals(test));
  }
  /*
   * If CodeToExecute is defined in a configurable app, then it should be evaluated.
   * Also header should be evaluated and not just printed.
   * If XWiki.ConfigurableClass is saved with programming rights, it should resave itself so that it doesn't have them.
   */
  @Test
  public void testCodeToExecutionAndAutoSandboxing() {
    String space = "Main";
    String page = "TestConfigurable";
    String codeToExecute =
        "#set($code = 's sh')"
            + "Thi${code}ould be displayed."
            + "#if($xcontext.hasProgrammingRights())"
            + "This should not be displayed."
            + "#end";
    String heading = "#set($code = 'his sho')" + "T${code}uld also be displayed.";
    createConfigurableApplication(space, page, "TestSection6", true);
    open(space, page, "edit", "editor=object");
    expandObject("XWiki.ConfigurableClass", 0);
    setFieldValue("XWiki.ConfigurableClass_0_codeToExecute", codeToExecute);
    setFieldValue("XWiki.ConfigurableClass_0_heading", heading);
    setFieldValue("XWiki.ConfigurableClass_0_configurationClass", "");
    clickEditSaveAndView();

    // Our admin will foolishly save XWiki.ConfigurableClass, giving it programming rights.
    open("XWiki", "ConfigurableClass", "edit", "editor=wiki");

    try {
      // Since we modify ConfigurableClass, we must modify it back after to prevent polluting
      // further tests.
      // See http://code.google.com/p/selenium/issues/detail?id=2876 .
      getDriver()
          .findElement(By.id("content"))
          .sendKeys(
              Keys.chord(Keys.CONTROL, "a"),
              Keys.chord(Keys.CONTROL, "c"),
              Keys.ARROW_RIGHT,
              "{{velocity}}Has Programming permission: $xcontext.hasProgrammingRights(){{/velocity}}");
      clickEditSaveAndContinue();

      // Now we look at the section for our configurable.
      open("XWiki", "ConfigurableClass", "view", "editor=globaladmin&section=TestSection6");

      assertTextPresent("This should be displayed.");
      assertTextPresent("This should also be displayed.");
      assertTextNotPresent("This should not be displayed.");
      assertTextPresent("Has Programming permission: false");
      // Make sure javascript has not added a Save button.
      assertElementNotPresent("//div/div/p/span/input[@type='submit'][@value='Save']");
    } finally {
      open("XWiki", "ConfigurableClass", "edit", "editor=wiki");
      getDriver()
          .findElement(By.id("content"))
          .sendKeys(Keys.chord(Keys.CONTROL, "a"), Keys.chord(Keys.CONTROL, "v"));
      clickEditSaveAndContinue();
    }
  }
  /*
   * Proves that ConfigurationClass#codeToExecute is not rendered inline even if there is no
   * custom configuration class and the on;y content is custom content.
   * Tests: XWiki.ConfigurableClass
   */
  @Test
  public void testCodeToExecuteNotInlineIfNoConfigurationClass() {
    String space = "Main";
    String page = "TestConfigurable";
    String test = "{{html}} <div> <p> hello </p> </div> {{/html}}";

    open(space, page, "delete", "confirm=1");
    createConfigurableApplication(space, page, "TestSection1", true);
    open(space, page, "edit", "editor=object");
    expandObject("XWiki.ConfigurableClass", 0);
    setFieldValue("XWiki.ConfigurableClass_0_configurationClass", "");
    setFieldValue("XWiki.ConfigurableClass_0_codeToExecute", test);
    clickEditSaveAndView();

    open("XWiki", "XWikiPreferences", "admin", "editor=globaladmin&section=TestSection1");
    assertElementNotPresent("//span[@class='xwikirenderingerror']");
  }
  /*
   * Fails unless XWiki.ConfigurableClass locks each page on view and unlocks any other configurable page.
   * Also fails if codeToExecute is not being evaluated.
   *
   * Tests: XWiki.ConfigurableClass
   */
  @Test
  public void testLockingAndUnlocking() {
    String space = "Main";
    String page1 = "TestConfigurable";
    String page2 = "TestConfigurable2";
    String isThisPageLocked = "{{velocity}}Is This Page Locked $doc.getLocked(){{/velocity}}";
    createConfigurableApplication(space, page1, "TestSection4", true);
    createConfigurableApplication(space, page2, "TestSection5", true);
    open(space, page1, "edit", "editor=wiki");
    setFieldValue("content", isThisPageLocked);
    clickEditSaveAndView();
    open(space, page2, "edit", "editor=wiki");
    setFieldValue("content", isThisPageLocked);
    clickEditSaveAndView();

    // Now we go to the documents and see which is locked.
    open("XWiki", "XWikiPreferences", "admin", "editor=globaladmin&section=TestSection4");

    try {
      // We have to switch user context without logging out, logging out removes all locks.
      // We have to open a new window because otherwise the lock is removed when we leave the
      // administration page.
      getSelenium()
          .openWindow("http://127.0.0.1:8080" + getUrl(space, page1, "view"), getTestMethodName());
      getSelenium().selectWindow(getTestMethodName());
      assertTextPresent("Is This Page Locked true");

      open("http://127.0.0.1:8080" + getUrl(space, page2, "view"));
      assertTextPresent("Is This Page Locked false");

      getSelenium().selectWindow(null);
      open("XWiki", "XWikiPreferences", "admin", "editor=globaladmin&section=TestSection5");

      getSelenium().selectWindow(getTestMethodName());
      open("http://127.0.0.1:8080" + getUrl(space, page1, "view"));
      assertTextPresent("Is This Page Locked false");

      open("http://127.0.0.1:8080" + getUrl(space, page2, "view"));
      assertTextPresent("Is This Page Locked true");

      // Close the window we needed for a different user context.
      getSelenium().close();
    } finally {
      getSelenium().selectWindow(null);
    }
  }
  /*
   * If a value is specified for linkPrefix, then a link is generated with linkPrefix + prettyName of the property from
   * the configuration class.
   * linkPrefix = "http://www.xwiki.org/bin/view/Main/"
   * property prettyName = "WebHome"
   * generated link should equal "http://www.xwiki.org/bin/view/Main/WebHome"
   *
   * Tests: XWiki.ConfigurableClass
   */
  @Test
  public void testLabelLinkGeneration() {
    String space = "Main";
    String page = "TestConfigurable";
    createConfigurableApplication(space, page, "TestSection3", true);
    open(space, page, "edit", "editor=object");
    setFieldValue("XWiki.ConfigurableClass_0_linkPrefix", "TheLinkPrefix");
    clickEditSaveAndView();

    open("XWiki", "XWikiPreferences", "admin", "editor=globaladmin&section=TestSection3");
    assertElementPresent("//form/fieldset//a[@href='TheLinkPrefixString']");
    assertElementPresent("//form/fieldset//a[@href='TheLinkPrefixBoolean']");
    assertElementPresent("//form/fieldset//a[@href='TheLinkPrefixTextArea']");
    assertElementPresent("//form/fieldset//a[@href='TheLinkPrefixSelect']");
  }
  /*
   * Proves that ConfigurationClass#codeToExecute is not rendered inline whether it's at the top of the
   * form or inside of the form.
   * Tests: XWiki.ConfigurableClass
   */
  @Test
  public void testCodeToExecuteNotInline() {
    String space = "Main";
    String page = "TestConfigurable";
    String test = "{{html}} <div> <p> hello </p> </div> {{/html}}";

    createConfigurableApplication(space, page, "TestSection1", true);
    open(space, page, "edit", "editor=object");
    expandObject("XWiki.ConfigurableClass", 0);
    setFieldValue("XWiki.ConfigurableClass_0_codeToExecute", test);
    setFieldValue("XWiki.ConfigurableClass_0_propertiesToShow", "String, Boolean");

    getSelenium().select("classname", "value=XWiki.ConfigurableClass");
    clickButtonAndContinue("//input[@name='action_objectadd']");
    setFieldValue("XWiki.ConfigurableClass_1_displayInSection", "TestSection1");
    setFieldValue("XWiki.ConfigurableClass_1_configurationClass", space + "." + page);
    setFieldValue("XWiki.ConfigurableClass_1_propertiesToShow", "TextArea, Select");
    setFieldValue("XWiki.ConfigurableClass_1_codeToExecute", test);
    getSelenium().check("XWiki.ConfigurableClass_1_configureGlobally");
    clickEditSaveAndView();

    open("XWiki", "XWikiPreferences", "admin", "editor=globaladmin&section=TestSection1");
    assertElementNotPresent("//span[@class='xwikirenderingerror']");
  }
  /*
   * Test Panel Wizard
   */
  @Test
  public void testPanelsAdmin() {
    open("XWiki", "XWikiPreferences", "admin");

    // test panel wizard at global level
    clickLinkWithLocator("//a[text()='Panel Wizard']");
    waitForBodyContains("Page Layout");
    clickLinkWithXPath("//a[@href='#PageLayoutSection']", false);
    waitForElement("//div[@id = 'rightcolumn']");
    clickLinkWithXPath("//div[@id='rightcolumn']", false);
    waitForBodyContains("Panel List");
    clickLinkWithXPath("//a[@href='#PanelListSection']", false);
    dragAndDrop(
        By.xpath("//div[@class='panel expanded CategoriesPanel']//h1"), By.id("rightPanels"));
    assertElementPresent("//div[@id = 'rightPanels']/div[contains(@class, 'CategoriesPanel')]");
    clickLinkWithXPath("//button[text()='Save the new layout']", false);
    waitForNotificationSuccessMessage("The layout has been saved properly.");
    open("Main", "WebHome");
    assertElementNotPresent("leftPanels");
    assertElementPresent("rightPanels");
    assertElementPresent("//div[@id = 'rightPanels']/div[contains(@class, 'CategoriesPanel')]");

    // Revert changes
    open("XWiki", "XWikiPreferences", "admin");
    clickLinkWithLocator("//a[text()='Panel Wizard']");
    waitForBodyContains("Page Layout");
    clickLinkWithXPath("//a[@href='#PageLayoutSection']", false);
    waitForCondition("selenium.isElementPresent(\"//div[@id='bothcolumns']\")!=false;");
    clickLinkWithXPath("//div[@id='bothcolumns']", false);
    waitForBodyContains("Panel List");
    clickLinkWithXPath("//a[@href='#PanelListSection']", false);
    dragAndDrop(
        By.xpath("//div[@id='rightPanels']//div[contains(@class, 'CategoriesPanel')]//h1"),
        By.xpath("//div[@id='allviewpanels']//div[@class='accordionTabContentBox']"));
    assertElementNotPresent("//div[@id = 'rightPanels']//div[contains(@class, 'CategoriesPanel')]");
    clickLinkWithXPath("//button[text()='Save the new layout']", false);
    waitForNotificationSuccessMessage("The layout has been saved properly.");
    open("Main", "WebHome");
    assertElementPresent("leftPanels");
    assertElementPresent("rightPanels");
    assertElementNotPresent("//div[@id = 'rightPanels']//div[contains(@class, 'CategoriesPanel')]");

    // test panel wizard at space level
    open("TestPanelsAdmin", "WebHome", "edit", "editor=wiki");
    setFieldValue("content", "aaa");
    clickEditSaveAndView();
    open("TestPanelsAdmin", "WebPreferences", "admin");
    clickLinkWithLocator("//a[text()='Panel Wizard']");
    waitForBodyContains("Page Layout");
    clickLinkWithXPath("//a[@href='#PageLayoutSection']", false);
    waitForCondition("selenium.isElementPresent(\"//div[@id='leftcolumn']\")!=false;");
    clickLinkWithXPath("//div[@id='leftcolumn']", false);
    waitForBodyContains("Panel List");
    clickLinkWithXPath("//a[@href='#PanelListSection']", false);
    dragAndDrop(
        By.xpath("//div[@class='panel expanded CategoriesPanel']//h1"), By.id("leftPanels"));
    clickLinkWithXPath("//button[text()='Save the new layout']", false);
    waitForNotificationSuccessMessage("The layout has been saved properly.");
    open("TestPanelsAdmin", "WebHome");
    assertElementPresent("leftPanels");
    assertElementPresent("//div[@id = 'leftPanels']//div[contains(@class, 'CategoriesPanel')]");
    open("XWiki", "WebHome");
    assertElementPresent("rightPanels");
    assertElementNotPresent("//div[@id = 'leftPanels']//div[contains(@class, 'CategoriesPanel')]");
  }
  /**
   * Creates a new page with a configuration class with some simple fields<br>
   * then adds an object of class configurable and one of it's own class.<br>
   * Tests: XWiki.ConfigurableClass
   */
  public void createConfigurableApplication(
      String space, String page, String section, boolean global) {
    // We have to use an existing space because the copy page form doesn't allow entering a new
    // space.
    String storageSpace = "Sandbox";
    String storagePage = "CreateConfigurableApplication";

    if (!tryToCopyPage(storageSpace, storagePage, space, page)) {
      // Create the page with a simple configuration class.
      createPage(space, page, "Test configurable application.", "xwiki/2.1");
      open(space, page, "edit", "editor=class");
      setFieldValue("propname", "String");
      setFieldValue("proptype", "String");
      clickButtonAndContinue("//input[@name='action_propadd']");
      setFieldValue("propname", "Boolean");
      setFieldValue("proptype", "Boolean");
      clickButtonAndContinue("//input[@name='action_propadd']");
      setFieldValue("propname", "TextArea");
      setFieldValue("proptype", "TextArea");
      clickButtonAndContinue("//input[@name='action_propadd']");
      // Expand the TextArea property we just added in order to set the "editor" meta property.
      getSelenium().click("xproperty_TextArea");
      getSelenium().select("TextArea_editor", "value=Text");
      clickEditSaveAndContinue();
      setFieldValue("propname", "Select");
      setFieldValue("proptype", "StaticList");
      clickButtonAndContinue("//input[@name='action_propadd']");

      // Go to the object section.
      open(space, page, "edit", "editor=object");

      // Add a configurable object which points to the new class as the configuration class.
      getSelenium().select("classname", "value=XWiki.ConfigurableClass");
      clickButtonAndContinue("//input[@name='action_objectadd']");
      clickEditSaveAndView();

      // Try to place it in the storage area.
      tryToCopyPage(space, page, storageSpace, storagePage);
    }

    // Go to the object section.
    open(space, page, "edit", "editor=object");

    // Add an object of the new class.
    waitForElement("classname");
    getSelenium().select("classname", "value=" + space + "." + page);
    // Scroll the page to the top because the edit menu can be activated when we hover over the add
    // button.
    getSelenium().runScript("window.scrollTo(0, 0)");
    clickButtonAndContinue("//input[@name='action_objectadd']");

    setFieldValue("XWiki.ConfigurableClass_0_displayInSection", section);
    setFieldValue("XWiki.ConfigurableClass_0_heading", "Some Heading");
    setFieldValue("XWiki.ConfigurableClass_0_configurationClass", space + "." + page);

    // Unfold the XWiki.ConfigurableClass object so that we can modify its properties
    WebElement configurableClassObj =
        getDriver().findElement(By.id("xobject_XWiki.ConfigurableClass_0"));
    if (configurableClassObj.getAttribute("class").contains("collapsed")) {
      configurableClassObj.click();
    }

    if (global) {
      getSelenium().check("XWiki.ConfigurableClass_0_configureGlobally");
    } else {
      getSelenium().uncheck("XWiki.ConfigurableClass_0_configureGlobally");
    }
    // We won't set linkPrefix, propertiesToShow, codeToExecute, or iconAttachment.

    clickEditSaveAndView();
  }
  /*
   * Creates a document with 2 configurable objects, one gets configured globally in one section and displays
   * 2 configuration fields, the other is configured in the space in another section and displays the other 2
   * fields. Fails if they are not displayed as they should be.
   *
   * Tests: XWiki.ConfigurableClass
   */
  @Test
  public void testApplicationConfiguredInMultipleSections() {
    String space = "Main";
    String page = "TestConfigurable";

    createConfigurableApplication(space, page, "TestSection1", true);
    open(space, page, "edit", "editor=object");
    // Add a second configurable object.
    getSelenium().select("classname", "value=XWiki.ConfigurableClass");
    clickButtonAndContinue("//input[@name='action_objectadd']");
    setFieldValue("XWiki.ConfigurableClass_1_displayInSection", "TestSection2");
    setFieldValue("XWiki.ConfigurableClass_1_heading", "Some Other Heading");
    setFieldValue("XWiki.ConfigurableClass_1_configurationClass", space + "." + page);
    getSelenium().uncheck("XWiki.ConfigurableClass_1_configureGlobally");
    // Set propertiesToShow so that each config only shows half of the properties.
    setFieldValue("XWiki.ConfigurableClass_1_propertiesToShow", "TextArea, Select");
    setFieldValue("XWiki.ConfigurableClass_0_propertiesToShow", "String, Boolean");
    clickEditSaveAndView();

    // Assert that half of the configuration shows up but not the other half.
    open("XWiki", "XWikiPreferences", "admin", "editor=globaladmin&section=TestSection1");
    assertElementPresent("//div[@id='admin-page-content']/h2[@id='HSomeHeading']/span");
    // Fields
    String fullName = space + "." + page;
    String form =
        "//div[@id='admin-page-content']/form[@action='/xwiki/bin/save/"
            + space
            + "/"
            + page
            + "']";
    assertElementPresent(form + "/fieldset//label['String']");
    assertElementPresent(form + "/fieldset//input[@name='" + fullName + "_0_String']");
    assertElementPresent(form + "/fieldset//label['Boolean']");
    assertElementPresent(form + "/fieldset//select[@name='" + fullName + "_0_Boolean']");
    assertElementPresent(form + "/fieldset/input[@id='" + fullName + "_redirect']");
    // xredirect
    assertElementPresent(
        form + "/fieldset/input[@value='" + getSelenium().getLocation() + "'][@name='xredirect']");
    // Save button
    // assertElementPresent(form + "/div/p/span/input[@type='submit']");
    // Javascript injects a save button outside of the form and removes the default save button.
    waitForElement("//div/div/p/span/input[@type='submit'][@value='Save']");
    // Should not be here
    assertElementNotPresent(form + "/fieldset//textarea[@name='" + fullName + "_0_TextArea']");
    assertElementNotPresent(form + "/fieldset//select[@name='" + fullName + "_0_Select']");

    // Now we go to where the other half of the configuration should be.
    open("Main", "WebPreferences", "admin", "editor=spaceadmin&section=TestSection2");
    assertElementPresent("//h2[@id='HSomeOtherHeading']/span");
    // Fields
    assertElementPresent(form + "/fieldset//label");
    assertElementPresent(form + "/fieldset//textarea[@name='" + fullName + "_0_TextArea']");
    assertElementPresent(form + "/fieldset//select[@name='" + fullName + "_0_Select']");
    assertElementPresent(form + "/fieldset/input[@id='" + fullName + "_redirect']");
    // xredirect
    assertElementPresent(
        form + "/fieldset/input[@value='" + getSelenium().getLocation() + "'][@name='xredirect']");
    // Save button
    // assertElementPresent(form + "/div/p/span/input[@type='submit']");
    // Javascript injects a save button outside of the form and removes the default save button.
    waitForElement("//div/div/p/span/input[@type='submit'][@value='Save']");
    // Should not be here
    assertElementNotPresent(form + "/fieldset//input[@name='" + fullName + "_0_String']");
    assertElementNotPresent(form + "/fieldset//select[@name='" + fullName + "_0_Boolean']");
  }