Evaluate all queries when --task--invalid option is used

To verify task validity, this change runs all queries defined for a task,
no matter what the tasks state is; this makes it possible to detect some
additional configuration problems which may not be detected when running
normally.

Change-Id: I6aeb2727599758c3666d5f64d03178607ed1e717
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
index 219ebd8..2a56c4e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
@@ -152,6 +152,9 @@
         TaskAttribute task = new TaskAttribute(def.name);
         task.subTasks = getSubTasks(c, path, def);
         task.status = getStatus(c, def, task);
+        if (options.onlyInvalid && !isValidQueries(c, def)) {
+          task.status = Status.INVALID;
+        }
         boolean groupApplicable = task.status != null;
 
         if (groupApplicable || !options.onlyApplicable) {
@@ -160,7 +163,7 @@
               task.applicable = applicable;
             }
             if (def.inProgress != null) {
-              task.inProgress = match(c, def.inProgress);
+              task.inProgress = matchOrNull(c, def.inProgress);
             }
             task.hint = getHint(task.status, def);
             tasks.add(task);
@@ -268,6 +271,17 @@
     return new Branch.NameKey(allUsers.get(), RefNames.refsUsers(acct.getId()));
   }
 
+  protected boolean isValidQueries(ChangeData c, Task task) {
+    try {
+      match(c, task.inProgress);
+      match(c, task.fail);
+      match(c, task.pass);
+      return true;
+    } catch (OrmException | QueryParseException e) {
+      return false;
+    }
+  }
+
   protected Status getStatus(ChangeData c, Task task, TaskAttribute a) throws OrmException {
     try {
       return getStatusWithExceptions(c, task, a);
@@ -367,6 +381,19 @@
     return ((Matchable) cqb.parse(query)).match(c);
   }
 
+  protected Boolean matchOrNull(ChangeData c, String query) {
+    if (query != null) {
+      try {
+        if (query.equalsIgnoreCase("true")) {
+          return true;
+        }
+        return ((Matchable) cqb.parse(query)).match(c);
+      } catch (OrmException | QueryParseException e) {
+      }
+    }
+    return null;
+  }
+
   protected static boolean isAllNull(Object... vals) {
     for (Object val : vals) {
       if (val != null) {
diff --git a/src/main/resources/Documentation/task.md b/src/main/resources/Documentation/task.md
index ebafbd1..35ede41 100644
--- a/src/main/resources/Documentation/task.md
+++ b/src/main/resources/Documentation/task.md
@@ -290,9 +290,12 @@
 
 This switch is meant as a debug switch to help find mis-configured tasks,
 it causes only invalid tasks and the tasks in the tree hierarchy above them
-to be output. If all tasks are properly configured, this switch should not
-output anything. This switch is particularly useful in combination with
-the **\-\-@PLUGIN@\-\-preview** switch.
+to be output. To verify task validity, this change runs all queries defined
+for a task, no matter what the tasks state is; this makes it possible to
+detect some additional configuration problems which may not be detected when
+running normally. If all tasks are properly configured, this switch should
+not output anything. This switch is particularly useful in combination
+with the **\-\-@PLUGIN@\-\-preview** switch.
 
 When tasks are appended to changes, they will have a "task" section under
 the plugins section like below:
diff --git a/src/main/resources/Documentation/task_states.md b/src/main/resources/Documentation/task_states.md
index f417b6d..b7e6142 100644
--- a/src/main/resources/Documentation/task_states.md
+++ b/src/main/resources/Documentation/task_states.md
@@ -191,9 +191,21 @@
 [task "Subtask INVALID"]
   applicable = is:open
 
-[external "external missing"]
-  user = mfick
-  file = missing
+[task "NA Bad PASS query"]
+  applicable = -is:open
+  fail = True
+  pass = has:bad
+
+[task "NA Bad FAIL query"]
+  applicable = -is:open
+  pass = True
+  fail = has:bad
+
+[task "NA Bad INPROGRESS query"]
+  applicable = -is:open
+  fail = True
+  in-progress = has:bad
+
 ```
 
 `task/special.config` file in project `All-Users` on ref `refs/users/self`.
diff --git a/test/all b/test/all
index 5fc731c..98f28d2 100644
--- a/test/all
+++ b/test/all
@@ -320,6 +320,21 @@
                      "applicable" : true,
                      "name" : "Subtask INVALID",
                      "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad PASS query",
+                     "status" : "FAIL"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad FAIL query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad INPROGRESS query",
+                     "status" : "FAIL"
                   }
                ]
             },
@@ -395,6 +410,21 @@
                      "applicable" : true,
                      "name" : "Subtask INVALID",
                      "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad PASS query",
+                     "status" : "FAIL"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad FAIL query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad INPROGRESS query",
+                     "status" : "FAIL"
                   }
                ]
             }
diff --git a/test/invalid b/test/invalid
index c85c7a5..432b711 100644
--- a/test/invalid
+++ b/test/invalid
@@ -103,6 +103,21 @@
                      "applicable" : true,
                      "name" : "Subtask INVALID",
                      "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad PASS query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad FAIL query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad INPROGRESS query",
+                     "status" : "INVALID"
                   }
                ]
             },
@@ -168,6 +183,21 @@
                      "applicable" : true,
                      "name" : "Subtask INVALID",
                      "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad PASS query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad FAIL query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad INPROGRESS query",
+                     "status" : "INVALID"
                   }
                ]
             }
diff --git a/test/preview b/test/preview
index 9a2efde..202fb09 100644
--- a/test/preview
+++ b/test/preview
@@ -64,6 +64,21 @@
                      "applicable" : true,
                      "name" : "Subtask INVALID",
                      "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad PASS query",
+                     "status" : "FAIL"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad FAIL query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad INPROGRESS query",
+                     "status" : "FAIL"
                   }
                ]
             },
@@ -169,6 +184,21 @@
                      "applicable" : true,
                      "name" : "Subtask INVALID",
                      "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad PASS query",
+                     "status" : "FAIL"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad FAIL query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad INPROGRESS query",
+                     "status" : "FAIL"
                   }
                ]
             }
diff --git a/test/preview.invalid b/test/preview.invalid
index ca56c48..c3c98e9 100644
--- a/test/preview.invalid
+++ b/test/preview.invalid
@@ -64,6 +64,21 @@
                      "applicable" : true,
                      "name" : "Subtask INVALID",
                      "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad PASS query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad FAIL query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad INPROGRESS query",
+                     "status" : "INVALID"
                   }
                ]
             },
@@ -129,6 +144,21 @@
                      "applicable" : true,
                      "name" : "Subtask INVALID",
                      "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad PASS query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad FAIL query",
+                     "status" : "INVALID"
+                  },
+                  {
+                     "applicable" : false,
+                     "name" : "NA Bad INPROGRESS query",
+                     "status" : "INVALID"
                   }
                ]
             }