@Test
  public void testExecute() throws Exception {
    InstructorAttributes instructor1OfCourse1 = dataBundle.instructors.get("instructor1OfCourse1");
    String instructorId = instructor1OfCourse1.googleId;

    String adminUserId = "admin.user";

    gaeSimulation.loginAsInstructor(instructorId);

    ______TS("Not enough parameters");
    verifyAssumptionFailure();
    verifyAssumptionFailure(Const.ParamsNames.COURSE_NAME, "ticac tac name");

    ______TS("Error: Invalid parameter for Course ID");

    Action addAction =
        getAction(
            Const.ParamsNames.COURSE_ID, "ticac,tpa1,id",
            Const.ParamsNames.COURSE_NAME, "ticac tpa1 name");
    ShowPageResult pageResult = (ShowPageResult) addAction.executeAndPostProcess();

    assertEquals(
        Const.ViewURIs.INSTRUCTOR_COURSES + "?error=true&user=idOfInstructor1OfCourse1",
        pageResult.getDestinationWithParams());
    assertEquals(true, pageResult.isError);
    assertEquals(Const.StatusMessages.COURSE_INVALID_ID, pageResult.getStatusMessage());

    InstructorCoursesPageData pageData = (InstructorCoursesPageData) pageResult.data;
    assertEquals(1, pageData.allCourses.size());

    String expectedLogMessage =
        "TEAMMATESLOG|||instructorCourseAdd|||instructorCourseAdd"
            + "|||true|||Instructor|||Instructor 1 of Course 1|||idOfInstructor1OfCourse1|||[email protected]"
            + "|||Please use only alphabets, numbers, dots, hyphens, underscores and dollar signs in course ID."
            + "|||/page/instructorCourseAdd";
    assertEquals(expectedLogMessage, addAction.getLogMessage());

    ______TS("Typical case, 1 existing course");

    addAction =
        getAction(
            Const.ParamsNames.COURSE_ID, "ticac.tpa1.id",
            Const.ParamsNames.COURSE_NAME, "ticac tpa1 name");
    pageResult = (ShowPageResult) addAction.executeAndPostProcess();

    pageData = (InstructorCoursesPageData) pageResult.data;
    assertEquals(2, pageData.allCourses.size());

    expectedLogMessage =
        "TEAMMATESLOG|||instructorCourseAdd"
            + "|||instructorCourseAdd|||true|||Instructor|||Instructor 1 of Course 1"
            + "|||idOfInstructor1OfCourse1|||[email protected]"
            + "|||Course added : ticac.tpa1.id<br>Total courses: 2|||/page/instructorCourseAdd";
    assertEquals(expectedLogMessage, addAction.getLogMessage());

    String expected =
        Const.StatusMessages.COURSE_ADDED
            .replace(
                "${courseEnrollLink}",
                "/page/instructorCourseEnrollPage?courseid=ticac.tpa1.id&user=idOfInstructor1OfCourse1")
            .replace(
                "${courseEditLink}",
                "/page/instructorCourseEditPage?courseid=ticac.tpa1.id&user=idOfInstructor1OfCourse1");
    assertEquals(expected, pageResult.getStatusMessage());

    ______TS("Error: Try to add the same course again");

    addAction =
        getAction(
            Const.ParamsNames.COURSE_ID, "ticac.tpa1.id",
            Const.ParamsNames.COURSE_NAME, "ticac tpa1 name");
    pageResult = (ShowPageResult) addAction.executeAndPostProcess();

    assertEquals(
        Const.ViewURIs.INSTRUCTOR_COURSES + "?error=true&user=idOfInstructor1OfCourse1",
        pageResult.getDestinationWithParams());
    assertEquals(true, pageResult.isError);
    assertEquals(Const.StatusMessages.COURSE_EXISTS, pageResult.getStatusMessage());

    pageData = (InstructorCoursesPageData) pageResult.data;
    assertEquals(2, pageData.allCourses.size());

    expectedLogMessage =
        "TEAMMATESLOG|||instructorCourseAdd|||instructorCourseAdd"
            + "|||true|||Instructor|||Instructor 1 of Course 1|||idOfInstructor1OfCourse1"
            + "|||[email protected]|||A course by the same ID already exists in the system, possibly created by another user. Please choose a different course ID"
            + "|||/page/instructorCourseAdd";
    assertEquals(expectedLogMessage, addAction.getLogMessage());

    ______TS("Masquerade mode, 0 courses");

    CoursesLogic.inst().deleteCourseCascade(instructor1OfCourse1.courseId);
    CoursesLogic.inst().deleteCourseCascade("ticac.tpa1.id");
    gaeSimulation.loginAsAdmin(adminUserId);
    addAction =
        getAction(
            Const.ParamsNames.USER_ID, instructorId,
            Const.ParamsNames.COURSE_ID, "ticac.tpa2.id",
            Const.ParamsNames.COURSE_NAME, "ticac tpa2 name");
    pageResult = (ShowPageResult) addAction.executeAndPostProcess();

    String expectedDestination =
        Const.ViewURIs.INSTRUCTOR_COURSES + "?error=false&user=idOfInstructor1OfCourse1";
    assertEquals(expectedDestination, pageResult.getDestinationWithParams());
    assertEquals(false, pageResult.isError);
    String expectedStatus =
        "The course has been added.. Click <a href=\"/page/instructorCourseEnrollPage?courseid=ticac.tpa2.id&user=idOfInstructor1OfCourse1\">here</a> to add students to the course or "
            + "click <a href=\"/page/instructorCourseEditPage?courseid=ticac.tpa2.id&user=idOfInstructor1OfCourse1\">here</a> to add other instructors.<br>If you don't see the course in the list below, please refresh the page after a few moments.";
    assertEquals(expectedStatus, pageResult.getStatusMessage());

    pageData = (InstructorCoursesPageData) pageResult.data;
    assertEquals(1, pageData.allCourses.size());

    expectedLogMessage =
        "TEAMMATESLOG|||instructorCourseAdd|||instructorCourseAdd"
            + "|||true|||Instructor(M)|||Instructor 1 of Course 1"
            + "|||idOfInstructor1OfCourse1|||[email protected]|||Course added : ticac.tpa2.id<br>Total courses: 1"
            + "|||/page/instructorCourseAdd";
    assertEquals(expectedLogMessage, addAction.getLogMessage());

    // delete the new course
    CoursesLogic.inst().deleteCourseCascade("ticac.tpa2.id");
  }
  @Test
  public void testExecuteAndPostProcess() throws Exception {
    InstructorAttributes instructor = dataBundle.instructors.get("instructor1OfCourse1");
    String instructorId = instructor.googleId;
    String courseId = instructor.courseId;
    String courseName = CoursesLogic.inst().getCourse(courseId).getName();
    String courseTimeZone = "UTC";
    String statusMessage = "";
    String[] submissionParams;
    InstructorCourseEditSaveAction courseEditSaveAction;
    RedirectResult redirectResult;

    gaeSimulation.loginAsInstructor(instructorId);

    ______TS("Not enough parameters");
    verifyAssumptionFailure();

    ______TS("Typical case: edit course name with same name");
    submissionParams =
        new String[] {
          Const.ParamsNames.COURSE_ID, courseId,
          Const.ParamsNames.COURSE_NAME, courseName,
          Const.ParamsNames.COURSE_TIME_ZONE, courseTimeZone
        };

    // execute the action
    courseEditSaveAction = getAction(submissionParams);
    redirectResult = getRedirectResult(courseEditSaveAction);

    // get updated results and compare
    statusMessage = Const.StatusMessages.COURSE_EDITED;
    assertEquals(statusMessage, redirectResult.getStatusMessage());
    assertEquals(
        Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE
            + "?error=false&user="******"&courseid="
            + courseId,
        redirectResult.getDestinationWithParams());

    ______TS("Typical case: edit course name with valid characters");
    String courseNameWithValidCharacters = courseName + " valid";
    submissionParams =
        new String[] {
          Const.ParamsNames.COURSE_ID, courseId,
          Const.ParamsNames.COURSE_NAME, courseNameWithValidCharacters,
          Const.ParamsNames.COURSE_TIME_ZONE, courseTimeZone
        };

    // execute the action
    courseEditSaveAction = getAction(submissionParams);
    redirectResult = getRedirectResult(courseEditSaveAction);

    // get updated results and compare
    statusMessage = Const.StatusMessages.COURSE_EDITED;
    assertEquals(statusMessage, redirectResult.getStatusMessage());
    assertEquals(
        Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE
            + "?error=false&user="******"&courseid="
            + courseId,
        redirectResult.getDestinationWithParams());

    ______TS("Failure case: edit course name with empty string");
    courseName = "";
    submissionParams =
        new String[] {
          Const.ParamsNames.COURSE_ID, courseId,
          Const.ParamsNames.COURSE_NAME, courseName,
          Const.ParamsNames.COURSE_TIME_ZONE, courseTimeZone
        };

    // execute the action
    courseEditSaveAction = getAction(submissionParams);
    redirectResult = getRedirectResult(courseEditSaveAction);

    // get updated results and compare
    statusMessage =
        getPopulatedErrorMessage(
            FieldValidator.SIZE_CAPPED_NON_EMPTY_STRING_ERROR_MESSAGE,
            courseName,
            FieldValidator.COURSE_NAME_FIELD_NAME,
            FieldValidator.REASON_EMPTY,
            FieldValidator.COURSE_NAME_MAX_LENGTH);
    assertEquals(statusMessage, redirectResult.getStatusMessage());
    assertEquals(
        Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE
            + "?error=true&user="******"&courseid="
            + courseId,
        redirectResult.getDestinationWithParams());

    ______TS("Failure case: edit course name with non-alphanumeric start character");
    courseName = "@#$@#$";
    submissionParams =
        new String[] {
          Const.ParamsNames.COURSE_ID, courseId,
          Const.ParamsNames.COURSE_NAME, courseName,
          Const.ParamsNames.COURSE_TIME_ZONE, courseTimeZone
        };

    // execute the action
    courseEditSaveAction = getAction(submissionParams);
    redirectResult = getRedirectResult(courseEditSaveAction);

    // get updated results and compare
    statusMessage =
        getPopulatedErrorMessage(
            FieldValidator.INVALID_NAME_ERROR_MESSAGE,
            courseName,
            FieldValidator.COURSE_NAME_FIELD_NAME,
            FieldValidator.REASON_START_WITH_NON_ALPHANUMERIC_CHAR);
    assertEquals(statusMessage, redirectResult.getStatusMessage());
    assertEquals(
        Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE
            + "?error=true&user="******"&courseid="
            + courseId,
        redirectResult.getDestinationWithParams());

    ______TS("Failure case: edit course name with name containing | and %");
    courseName = "normal|name%";
    submissionParams =
        new String[] {
          Const.ParamsNames.COURSE_ID, courseId,
          Const.ParamsNames.COURSE_NAME, courseName,
          Const.ParamsNames.COURSE_TIME_ZONE, courseTimeZone
        };

    // execute the action
    courseEditSaveAction = getAction(submissionParams);
    redirectResult = getRedirectResult(courseEditSaveAction);

    // get updated results and compare
    statusMessage =
        getPopulatedErrorMessage(
            FieldValidator.INVALID_NAME_ERROR_MESSAGE,
            courseName,
            FieldValidator.COURSE_NAME_FIELD_NAME,
            FieldValidator.REASON_CONTAINS_INVALID_CHAR);
    assertEquals(statusMessage, redirectResult.getStatusMessage());
    assertEquals(
        Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE
            + "?error=true&user="******"&courseid="
            + courseId,
        redirectResult.getDestinationWithParams());

    ______TS("Failure case: invalid time zone");
    courseName = CoursesLogic.inst().getCourse(courseId).getName();
    courseTimeZone = "InvalidTimeZone";
    submissionParams =
        new String[] {
          Const.ParamsNames.COURSE_ID, courseId,
          Const.ParamsNames.COURSE_NAME, courseName,
          Const.ParamsNames.COURSE_TIME_ZONE, courseTimeZone
        };

    courseEditSaveAction = getAction(submissionParams);
    redirectResult = getRedirectResult(courseEditSaveAction);

    statusMessage =
        getPopulatedErrorMessage(
            FieldValidator.COURSE_TIME_ZONE_ERROR_MESSAGE,
            courseTimeZone,
            FieldValidator.COURSE_TIME_ZONE_FIELD_NAME,
            FieldValidator.REASON_UNAVAILABLE_AS_CHOICE);
    assertEquals(statusMessage, redirectResult.getStatusMessage());
    assertEquals(
        Const.ActionURIs.INSTRUCTOR_COURSE_EDIT_PAGE
            + "?error=true&user="******"&courseid="
            + courseId,
        redirectResult.getDestinationWithParams());
  }