Merge "Update Soy templates to use the ! operator instead of 'not'."
diff --git a/java/com/google/gitiles/GitilesView.java b/java/com/google/gitiles/GitilesView.java
index 9bb43a9..f5be973 100644
--- a/java/com/google/gitiles/GitilesView.java
+++ b/java/com/google/gitiles/GitilesView.java
@@ -32,6 +32,7 @@
 import com.google.common.collect.LinkedListMultimap;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Multimaps;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.util.ArrayList;
@@ -299,6 +300,12 @@
       return this;
     }
 
+    @CanIgnoreReturnValue
+    public Builder removeParam(String key) {
+      params.removeAll(key);
+      return this;
+    }
+
     public Builder putAllParams(Map<String, String[]> params) {
       for (Map.Entry<String, String[]> e : params.entrySet()) {
         this.params.putAll(e.getKey(), Arrays.asList(e.getValue()));
diff --git a/java/com/google/gitiles/LogSoyData.java b/java/com/google/gitiles/LogSoyData.java
index 0c57e69..4292bc9 100644
--- a/java/com/google/gitiles/LogSoyData.java
+++ b/java/com/google/gitiles/LogSoyData.java
@@ -71,7 +71,10 @@
     this.view = checkNotNull(ViewFilter.getView(req));
     checkNotNull(pretty);
     Config config = access.getConfig();
-    fields = config.getBoolean("logFormat", pretty, "verbose", false) || pretty.equals("fuller") ? VERBOSE_FIELDS : FIELDS;
+    fields =
+        config.getBoolean("logFormat", pretty, "verbose", false) || pretty.equals("fuller")
+            ? VERBOSE_FIELDS
+            : FIELDS;
     variant = firstNonNull(config.getString("logFormat", pretty, "variant"), pretty);
   }
 
@@ -120,7 +123,9 @@
     ObjectId prev = paginator.getPreviousStart();
     if (prev != null) {
       GitilesView.Builder prevView = copyAndCanonicalizeView(revision);
-      if (!prevView.getRevision().getId().equals(prev)) {
+      if (prevView.getRevision().getId().equals(prev)) {
+        prevView.removeParam(LogServlet.START_PARAM);
+      } else {
         prevView.replaceParam(LogServlet.START_PARAM, prev.name());
       }
       data.put("previousUrl", prevView.toUrl());
diff --git a/javatests/com/google/gitiles/LogServletTest.java b/javatests/com/google/gitiles/LogServletTest.java
index 4ef7a4d..d875e0e 100644
--- a/javatests/com/google/gitiles/LogServletTest.java
+++ b/javatests/com/google/gitiles/LogServletTest.java
@@ -15,6 +15,7 @@
 package com.google.gitiles;
 
 import static com.google.common.truth.Truth.assertThat;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
 
 import com.google.gitiles.CommitJsonData.Commit;
 import com.google.gitiles.CommitJsonData.Log;
@@ -30,6 +31,10 @@
 @RunWith(JUnit4.class)
 public class LogServletTest extends ServletTest {
   private static final TypeToken<Log> LOG = new TypeToken<Log>() {};
+  private static final String MAIN = "main";
+  private static final String AUTHOR_METADATA_ELEMENT = "<th class=\"Metadata-title\">author</th>";
+  private static final String COMMITTER_METADATA_ELEMENT =
+      "<th class=\"Metadata-title\">committer</th>";
 
   @Test
   public void basicLog() throws Exception {
@@ -136,4 +141,125 @@
     assertThat(jsonCommit.committer.time).isEqualTo(df.format(commit.getCommitterIdent()));
     assertThat(jsonCommit.message).isEqualTo(commit.getFullMessage());
   }
+
+  @Test
+  public void verifyPreviousButtonAction() throws Exception {
+    repo.branch(MAIN).commit().add("foo", "contents").create();
+    RevCommit grandParent = repo.branch(MAIN).commit().add("foo", "contents").create();
+    RevCommit parent =
+        repo.branch(MAIN).commit().parent(grandParent).add("foo", "contents").create();
+    RevCommit main = repo.branch(MAIN).commit().parent(parent).create();
+
+    int numCommitsPerPage = 2;
+    String path =
+        "/repo/+log/" + grandParent.toObjectId().getName() + ".." + main.toObjectId().getName();
+    FakeHttpServletResponse res =
+        buildResponse(
+            path,
+            "format=html" + "&n=" + numCommitsPerPage + "&s=" + parent.toObjectId().getName(),
+            SC_OK);
+
+    assertThat(res.getActualBodyString())
+        .contains(
+            "<a class=\"LogNav-prev\""
+                + " href=\"/b/repo/+log/"
+                + grandParent.toObjectId().getName()
+                + ".."
+                + main.toObjectId().getName()
+                + "/?format=html"
+                + "&amp;n=2"
+                + "\">");
+  }
+
+  @Test
+  public void verifyNextButtonAction() throws Exception {
+    repo.branch(MAIN).commit().add("foo", "contents").create();
+    RevCommit grandParent = repo.branch(MAIN).commit().add("foo", "contents").create();
+    RevCommit parent =
+        repo.branch(MAIN).commit().parent(grandParent).add("foo", "contents").create();
+    RevCommit main = repo.branch(MAIN).commit().parent(parent).create();
+
+    int numCommitsPerPage = 1;
+    String path =
+        "/repo/+log/" + grandParent.toObjectId().getName() + ".." + main.toObjectId().getName();
+    FakeHttpServletResponse res =
+        buildResponse(path, "format=html" + "&n=" + numCommitsPerPage, SC_OK);
+
+    assertThat(res.getActualBodyString())
+        .contains(
+            "<a class=\"LogNav-next\""
+                + " href=\"/b/repo/+log/"
+                + grandParent.toObjectId().getName()
+                + ".."
+                + main.toObjectId().getName()
+                + "/?format=html"
+                + "&amp;n=1"
+                + "&amp;s="
+                + parent.toObjectId().getName()
+                + "\">");
+  }
+
+  @Test
+  public void prettyDefaultUsesDefaultCssClass() throws Exception {
+    RevCommit parent = repo.branch(MAIN).commit().add("foo", "contents").create();
+    RevCommit main = repo.branch(MAIN).commit().parent(parent).create();
+
+    String path =
+        "/repo/+log/" + parent.toObjectId().getName() + ".." + main.toObjectId().getName();
+    FakeHttpServletResponse res = buildResponse(path, "format=html", SC_OK);
+
+    assertThat(res.getActualBodyString())
+        .contains("<li class=\"CommitLog-item CommitLog-item--default\">");
+    assertThat(res.getActualBodyString()).doesNotContain(AUTHOR_METADATA_ELEMENT);
+    assertThat(res.getActualBodyString()).doesNotContain(COMMITTER_METADATA_ELEMENT);
+  }
+
+  @Test
+  public void prettyExplicitlyDefaultUsesDefaultCssClass() throws Exception {
+    testPrettyHtmlOutput(
+        "default", /* shouldShowAuthor= */ false, /* shouldShowCommitter= */ false);
+  }
+
+  @Test
+  public void prettyOnelineUsesOnelineCssClass() throws Exception {
+    testPrettyHtmlOutput(
+        "oneline", /* shouldShowAuthor= */ false, /* shouldShowCommitter= */ false);
+  }
+
+  @Test
+  public void prettyCustomTypeUsesCustomCssClass() throws Exception {
+    testPrettyHtmlOutput(
+        "aCustomPrettyType", /* shouldShowAuthor= */ false, /* shouldShowCommitter= */ false);
+  }
+
+  @Test
+  public void prettyFullerUsesFullerCssClass() throws Exception {
+    testPrettyHtmlOutput("fuller", /* shouldShowAuthor= */ true, /* shouldShowCommitter= */ true);
+  }
+
+  private void testPrettyHtmlOutput(
+      String prettyType, boolean shouldShowAuthor, boolean shouldShowCommitter) throws Exception {
+    RevCommit parent = repo.branch(MAIN).commit().add("foo", "contents").create();
+    RevCommit main = repo.branch(MAIN).commit().parent(parent).create();
+
+    String path =
+        "/repo/+log/" + parent.toObjectId().getName() + ".." + main.toObjectId().getName();
+    FakeHttpServletResponse res =
+        buildResponse(path, "format=html" + "&pretty=" + prettyType, SC_OK);
+
+    assertThat(res.getActualBodyString())
+        .contains("<li class=\"CommitLog-item CommitLog-item--" + prettyType + "\">");
+
+    if (shouldShowAuthor) {
+      assertThat(res.getActualBodyString()).contains(AUTHOR_METADATA_ELEMENT);
+    } else {
+      assertThat(res.getActualBodyString()).doesNotContain(AUTHOR_METADATA_ELEMENT);
+    }
+
+    if (shouldShowCommitter) {
+      assertThat(res.getActualBodyString()).contains(COMMITTER_METADATA_ELEMENT);
+    } else {
+      assertThat(res.getActualBodyString()).doesNotContain(COMMITTER_METADATA_ELEMENT);
+    }
+  }
 }
diff --git a/javatests/com/google/gitiles/doc/DocServletTest.java b/javatests/com/google/gitiles/doc/DocServletTest.java
index 2a9c2c5..110f481 100644
--- a/javatests/com/google/gitiles/doc/DocServletTest.java
+++ b/javatests/com/google/gitiles/doc/DocServletTest.java
@@ -158,7 +158,6 @@
     repo.branch("master").commit().add("index.md", markdown).create();
 
     String html = buildHtml("/repo/+/master/index.md");
-    System.out.println(html);
     assertThat(html)
         .contains(
             "<ul><li><p>one</p><div class=\"aside\">remember this</div>"