text:
package org.camunda.bpm.engine.rest.history;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response.Status;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.restassured.http.ContentType;
import io.restassured.response.Response;

import org.camunda.bpm.engine.BadUserRequestException;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;
import org.camunda.bpm.engine.impl.calendar.DateTimeUtil;
import org.camunda.bpm.engine.rest.AbstractRestServiceTest;
import org.camunda.bpm.engine.rest.exception.InvalidRequestException;
import org.camunda.bpm.engine.rest.helper.MockProvider;
import org.camunda.bpm.engine.rest.helper.variable.EqualsPrimitiveValue;
import org.camunda.bpm.engine.rest.util.OrderingBuilder;
import org.camunda.bpm.engine.rest.util.container.TestContainerRule;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import static io.restassured.RestAssured.expect;
import static io.restassured.RestAssured.given;
import static io.restassured.path.json.JsonPath.from;
import static org.fest.assertions.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

public class HistoricProcessInstanceRestServiceQueryTest extends AbstractRestServiceTest {

  protected static final String QUERY_PARAM_EXECUTED_JOB_BEFORE = "executedJobBefore";
  protected static final String QUERY_PARAM_EXECUTED_JOB_AFTER = "executedJobAfter";
  protected static final String QUERY_PARAM_EXECUTED_ACTIVITY_BEFORE = "executedActivityBefore";
  protected static final String QUERY_PARAM_EXECUTED_ACTIVITY_AFTER = "executedActivityAfter";
  protected static final String QUERY_PARAM_EXECUTED_ACTIVITY_IDS = "executedActivityIdIn";
  protected static final String QUERY_PARAM_ACTIVE_ACTIVITY_IDS = "activeActivityIdIn";

  @ClassRule
  public static TestContainerRule rule = new TestContainerRule();

  protected static final String HISTORIC_PROCESS_INSTANCE_RESOURCE_URL = TEST_RESOURCE_ROOT_PATH + "/history/process-instance";
  protected static final String HISTORIC_PROCESS_INSTANCE_COUNT_RESOURCE_URL = HISTORIC_PROCESS_INSTANCE_RESOURCE_URL + "/count";

  protected HistoricProcessInstanceQuery mockedQuery;

  @Before
  public void setUpRuntimeData() {
    mockedQuery = setUpMockHistoricProcessInstanceQuery(MockProvider.createMockHistoricProcessInstances());
  }

  private HistoricProcessInstanceQuery setUpMockHistoricProcessInstanceQuery(List<HistoricProcessInstance> mockedHistoricProcessInstances) {
    HistoricProcessInstanceQuery mockedhistoricProcessInstanceQuery = mock(HistoricProcessInstanceQuery.class);
    when(mockedhistoricProcessInstanceQuery.list()).thenReturn(mockedHistoricProcessInstances);
    when(mockedhistoricProcessInstanceQuery.count()).thenReturn((long) mockedHistoricProcessInstances.size());

    when(processEngine.getHistoryService().createHistoricProcessInstanceQuery()).thenReturn(mockedhistoricProcessInstanceQuery);

    return mockedhistoricProcessInstanceQuery;
  }

  @Test
  public void testEmptyQuery() {
    String queryKey = "";
    given()
      .queryParam("processDefinitionKey", queryKey)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);
  }

  @Test
  public void testNoParametersQuery() {
    expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).list();
    verifyNoMoreInteractions(mockedQuery);
  }

  @Test
  public void testNoParametersQueryAsPost() {
    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(EMPTY_JSON_OBJECT)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).list();
    verifyNoMoreInteractions(mockedQuery);
  }

  @Test
  public void testInvalidVariableRequests() {
    // invalid comparator
    String invalidComparator = "anInvalidComparator";
    String variableName = "varName";
    String variableValue = "varValue";
    String queryValue = variableName + "_" + invalidComparator + "_" + variableValue;

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.BAD_REQUEST.getStatusCode())
        .contentType(ContentType.JSON)
        .body("type", equalTo(InvalidRequestException.class.getSimpleName()))
        .body("message", containsString("Invalid variable comparator specified: " + invalidComparator))
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    // invalid format
    queryValue = "invalidFormattedVariableQuery";

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.BAD_REQUEST.getStatusCode())
        .contentType(ContentType.JSON)
        .body("type", equalTo(InvalidRequestException.class.getSimpleName()))
        .body("message", containsString("variable query parameter has to have format KEY_OPERATOR_VALUE"))
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);
  }

  @Test
  public void testInvalidSortingOptions() {
    executeAndVerifySorting("anInvalidSortByOption", "asc", Status.BAD_REQUEST);
    executeAndVerifySorting("definitionId", "anInvalidSortOrderOption", Status.BAD_REQUEST);
  }

  protected void executeAndVerifySorting(String sortBy, String sortOrder, Status expectedStatus) {
    given()
      .queryParam("sortBy", sortBy)
      .queryParam("sortOrder", sortOrder)
    .then()
      .expect()
        .statusCode(expectedStatus.getStatusCode())
    .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);
  }

  @Test
  public void testSortByParameterOnly() {
    given()
      .queryParam("sortBy", "definitionId")
    .then()
      .expect()
        .statusCode(Status.BAD_REQUEST.getStatusCode())
        .contentType(ContentType.JSON)
        .body("type", equalTo(InvalidRequestException.class.getSimpleName()))
        .body("message", containsString("Only a single sorting parameter specified. sortBy and sortOrder required"))
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);
  }

  @Test
  public void testSortOrderParameterOnly() {
    given()
      .queryParam("sortOrder", "asc")
    .then()
      .expect()
        .statusCode(Status.BAD_REQUEST.getStatusCode())
        .contentType(ContentType.JSON)
        .body("type", equalTo(InvalidRequestException.class.getSimpleName()))
        .body("message", containsString("Only a single sorting parameter specified. sortBy and sortOrder required"))
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);
  }

  @Test
  public void testSortingParameters() {
    InOrder inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("instanceId", "asc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceId();
    inOrder.verify(mockedQuery).asc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("instanceId", "desc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceId();
    inOrder.verify(mockedQuery).desc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("definitionId", "asc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessDefinitionId();
    inOrder.verify(mockedQuery).asc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("definitionId", "desc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessDefinitionId();
    inOrder.verify(mockedQuery).desc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("definitionKey", "desc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessDefinitionKey();
    inOrder.verify(mockedQuery).desc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("definitionName", "desc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessDefinitionName();
    inOrder.verify(mockedQuery).desc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("definitionVersion", "desc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessDefinitionVersion();
    inOrder.verify(mockedQuery).desc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("businessKey", "asc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceBusinessKey();
    inOrder.verify(mockedQuery).asc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("businessKey", "desc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceBusinessKey();
    inOrder.verify(mockedQuery).desc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("startTime", "asc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceStartTime();
    inOrder.verify(mockedQuery).asc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("startTime", "desc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceStartTime();
    inOrder.verify(mockedQuery).desc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("endTime", "asc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceEndTime();
    inOrder.verify(mockedQuery).asc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("endTime", "desc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceEndTime();
    inOrder.verify(mockedQuery).desc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("duration", "asc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceDuration();
    inOrder.verify(mockedQuery).asc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("duration", "desc", Status.OK);
    inOrder.verify(mockedQuery).orderByProcessInstanceDuration();
    inOrder.verify(mockedQuery).desc();

    inOrder = Mockito.inOrder(mockedQuery);
    executeAndVerifySorting("tenantId", "asc", Status.OK);
    inOrder.verify(mockedQuery).orderByTenantId();
    inOrder.verify(mockedQuery).asc();

  }

  @Test
  public void testSecondarySortingAsPost() {
    InOrder inOrder = Mockito.inOrder(mockedQuery);
    Map<String, Object> json = new HashMap<String, Object>();
    json.put("sorting", OrderingBuilder.create()
      .orderBy("instanceId").desc()
      .orderBy("startTime").asc()
      .getJson());
    given().contentType(POST_JSON_CONTENT_TYPE).body(json)
      .header("accept", MediaType.APPLICATION_JSON)
      .then().expect().statusCode(Status.OK.getStatusCode())
      .when().post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    inOrder.verify(mockedQuery).orderByProcessInstanceId();
    inOrder.verify(mockedQuery).desc();
    inOrder.verify(mockedQuery).orderByProcessInstanceStartTime();
    inOrder.verify(mockedQuery).asc();
  }

  @Test
  public void testSuccessfulPagination() {
    int firstResult = 0;
    int maxResults = 10;

    given()
      .queryParam("firstResult", firstResult)
      .queryParam("maxResults", maxResults)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).listPage(firstResult, maxResults);
  }

  @Test
  public void testMissingFirstResultParameter() {
    int maxResults = 10;

    given()
      .queryParam("maxResults", maxResults)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).listPage(0, maxResults);
  }

  @Test
  public void testMissingMaxResultsParameter() {
    int firstResult = 10;

    given()
      .queryParam("firstResult", firstResult)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).listPage(firstResult, Integer.MAX_VALUE);
  }

  @Test
  public void testQueryCount() {
    expect()
      .statusCode(Status.OK.getStatusCode())
      .body("count", equalTo(1))
    .when()
      .get(HISTORIC_PROCESS_INSTANCE_COUNT_RESOURCE_URL);

    verify(mockedQuery).count();
  }

  @Test
  public void testQueryCountForPost() {
    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(EMPTY_JSON_OBJECT)
    .then()
      .expect()
        .body("count", equalTo(1))
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_COUNT_RESOURCE_URL);

    verify(mockedQuery).count();
  }

  @Test
  public void testSimpleHistoricProcessQuery() {
    String processInstanceId = MockProvider.EXAMPLE_PROCESS_INSTANCE_ID;

    Response response = given()
        .queryParam("processInstanceId", processInstanceId)
      .then()
        .expect()
          .statusCode(Status.OK.getStatusCode())
        .when()
          .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).processInstanceId(processInstanceId);
    inOrder.verify(mockedQuery).list();

    String content = response.asString();
    List<String> instances = from(content).getList("");
    Assert.assertEquals("There should be one process instance returned.", 1, instances.size());
    Assert.assertNotNull("The returned process instance should not be null.", instances.get(0));

    String returnedProcessInstanceId = from(content).getString("[0].id");
    String returnedProcessInstanceBusinessKey = from(content).getString("[0].businessKey");
    String returnedProcessDefinitionId = from(content).getString("[0].processDefinitionId");
    String returnedProcessDefinitionKey = from(content).getString("[0].processDefinitionKey");
    String returnedProcessDefinitionName = from(content).getString("[0].processDefinitionName");
    int returnedProcessDefinitionVersion= from(content).getInt("[0].processDefinitionVersion");
    String returnedStartTime = from(content).getString("[0].startTime");
    String returnedEndTime = from(content).getString("[0].endTime");
    String returnedRemovalTime = from(content).getString("[0].removalTime");
    long returnedDurationInMillis = from(content).getLong("[0].durationInMillis");
    String returnedStartUserId = from(content).getString("[0].startUserId");
    String returnedStartActivityId = from(content).getString("[0].startActivityId");
    String returnedDeleteReason = from(content).getString("[0].deleteReason");
    String returnedRootProcessInstanceId = from(content).getString("[0].rootProcessInstanceId");
    String returnedSuperProcessInstanceId = from(content).getString("[0].superProcessInstanceId");
    String returnedSuperCaseInstanceId = from(content).getString("[0].superCaseInstanceId");
    String returnedCaseInstanceId = from(content).getString("[0].caseInstanceId");
    String returnedTenantId = from(content).getString("[0].tenantId");
    String returnedState = from(content).getString("[0].state");

    Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_ID, returnedProcessInstanceId);
    Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_BUSINESS_KEY, returnedProcessInstanceBusinessKey);
    Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_DEFINITION_ID, returnedProcessDefinitionId);
    Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_DEFINITION_KEY, returnedProcessDefinitionKey);
    Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_DEFINITION_NAME, returnedProcessDefinitionName);
    Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_DEFINITION_VERSION, returnedProcessDefinitionVersion);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_START_TIME, returnedStartTime);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_END_TIME, returnedEndTime);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_REMOVAL_TIME, returnedRemovalTime);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_DURATION_MILLIS, returnedDurationInMillis);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_START_USER_ID, returnedStartUserId);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_START_ACTIVITY_ID, returnedStartActivityId);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_DELETE_REASON, returnedDeleteReason);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_ROOT_PROCESS_INSTANCE_ID, returnedRootProcessInstanceId);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_SUPER_PROCESS_INSTANCE_ID, returnedSuperProcessInstanceId);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_SUPER_CASE_INSTANCE_ID, returnedSuperCaseInstanceId);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_CASE_INSTANCE_ID, returnedCaseInstanceId);
    Assert.assertEquals(MockProvider.EXAMPLE_TENANT_ID, returnedTenantId);
    Assert.assertEquals(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STATE, returnedState);
  }

  @Test
  public void testAdditionalParametersExcludingProcesses() {
    Map<String, String> stringQueryParameters = getCompleteStringQueryParameters();

    given()
      .queryParams(stringQueryParameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyStringParameterQueryInvocations();
  }

  @Test
  public void testAdditionalParametersExcludingProcessesAsPost() {
    Map<String, String> stringQueryParameters = getCompleteStringQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(stringQueryParameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyStringParameterQueryInvocations();
  }

  private Map<String, String> getCompleteStringQueryParameters() {
    Map<String, String> parameters = new HashMap<String, String>();

    parameters.put("processInstanceId", MockProvider.EXAMPLE_PROCESS_INSTANCE_ID);
    parameters.put("processInstanceBusinessKey", MockProvider.EXAMPLE_PROCESS_INSTANCE_BUSINESS_KEY);
    parameters.put("processInstanceBusinessKeyLike", MockProvider.EXAMPLE_PROCESS_INSTANCE_BUSINESS_KEY_LIKE);
    parameters.put("processDefinitionId", MockProvider.EXAMPLE_PROCESS_DEFINITION_ID);
    parameters.put("processDefinitionKey", MockProvider.EXAMPLE_PROCESS_DEFINITION_KEY);
    parameters.put("processDefinitionName", MockProvider.EXAMPLE_PROCESS_DEFINITION_NAME);
    parameters.put("processDefinitionNameLike", MockProvider.EXAMPLE_PROCESS_DEFINITION_NAME_LIKE);
    parameters.put("startedBy", "startedBySomeone");
    parameters.put("superProcessInstanceId", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_SUPER_PROCESS_INSTANCE_ID);
    parameters.put("subProcessInstanceId", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_SUB_PROCESS_INSTANCE_ID);
    parameters.put("superCaseInstanceId", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_SUPER_CASE_INSTANCE_ID);
    parameters.put("subCaseInstanceId", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_SUB_CASE_INSTANCE_ID);
    parameters.put("caseInstanceId", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_CASE_INSTANCE_ID);
    parameters.put("state", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STATE);
    parameters.put("incidentType", MockProvider.EXAMPLE_INCIDENT_TYPE);

    return parameters;
  }

  private void verifyStringParameterQueryInvocations() {
    Map<String, String> stringQueryParameters = getCompleteStringQueryParameters();

    verify(mockedQuery).processInstanceId(stringQueryParameters.get("processInstanceId"));
    verify(mockedQuery).processInstanceBusinessKey(stringQueryParameters.get("processInstanceBusinessKey"));
    verify(mockedQuery).processInstanceBusinessKeyLike(stringQueryParameters.get("processInstanceBusinessKeyLike"));
    verify(mockedQuery).processDefinitionId(stringQueryParameters.get("processDefinitionId"));
    verify(mockedQuery).processDefinitionKey(stringQueryParameters.get("processDefinitionKey"));
    verify(mockedQuery).processDefinitionName(stringQueryParameters.get("processDefinitionName"));
    verify(mockedQuery).processDefinitionNameLike(stringQueryParameters.get("processDefinitionNameLike"));
    verify(mockedQuery).startedBy(stringQueryParameters.get("startedBy"));
    verify(mockedQuery).superProcessInstanceId(stringQueryParameters.get("superProcessInstanceId"));
    verify(mockedQuery).subProcessInstanceId(stringQueryParameters.get("subProcessInstanceId"));
    verify(mockedQuery).superCaseInstanceId(stringQueryParameters.get("superCaseInstanceId"));
    verify(mockedQuery).subCaseInstanceId(stringQueryParameters.get("subCaseInstanceId"));
    verify(mockedQuery).caseInstanceId(stringQueryParameters.get("caseInstanceId"));
    verify(mockedQuery).incidentType(stringQueryParameters.get("incidentType"));

    verify(mockedQuery).list();
  }

  @Test
  public void testHistoricBeforeAndAfterStartTimeQuery() {
    given()
      .queryParam("startedBefore", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_BEFORE)
      .queryParam("startedAfter", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_AFTER)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyStartParameterQueryInvocations();
  }

  @Test
  public void testHistoricBeforeAndAfterStartTimeQueryAsPost() {
    Map<String, Date> parameters = getCompleteStartDateQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyStartParameterQueryInvocations();
  }

  @Test
  public void testHistoricBeforeAndAfterStartTimeAsStringQueryAsPost() {
    Map<String, String> parameters = getCompleteStartDateAsStringQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyStringStartParameterQueryInvocations();
  }

  private Map<String, Date> getCompleteStartDateQueryParameters() {
    Map<String, Date> parameters = new HashMap<String, Date>();

    parameters.put("startedAfter", DateTimeUtil.parseDate(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_AFTER));
    parameters.put("startedBefore", DateTimeUtil.parseDate(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_BEFORE));

    return parameters;
  }

  private Map<String, String> getCompleteStartDateAsStringQueryParameters() {
    Map<String, String> parameters = new HashMap<String, String>();

    parameters.put("startedAfter", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_AFTER);
    parameters.put("startedBefore", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_BEFORE);

    return parameters;
  }

  private void verifyStartParameterQueryInvocations() {
    Map<String, Date> startDateParameters = getCompleteStartDateQueryParameters();

    verify(mockedQuery).startedBefore(startDateParameters.get("startedBefore"));
    verify(mockedQuery).startedAfter(startDateParameters.get("startedAfter"));

    verify(mockedQuery).list();
  }

  private void verifyStringStartParameterQueryInvocations() {
    Map<String, String> startDateParameters = getCompleteStartDateAsStringQueryParameters();

    verify(mockedQuery).startedBefore(DateTimeUtil.parseDate(startDateParameters.get("startedBefore")));
    verify(mockedQuery).startedAfter(DateTimeUtil.parseDate(startDateParameters.get("startedAfter")));

    verify(mockedQuery).list();
  }

  @Test
  public void testHistoricAfterAndBeforeFinishTimeQuery() {
    given()
      .queryParam("finishedAfter", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_FINISHED_AFTER)
      .queryParam("finishedBefore", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_FINISHED_BEFORE)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyFinishedParameterQueryInvocations();
  }

  @Test
  public void testHistoricAfterAndBeforeFinishTimeQueryAsPost() {
    Map<String, Date> parameters = getCompleteFinishedDateQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyFinishedParameterQueryInvocations();
  }

  @Test
  public void testHistoricAfterAndBeforeFinishTimeAsStringQueryAsPost() {
    Map<String, String> parameters = getCompleteFinishedDateAsStringQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyStringFinishedParameterQueryInvocations();
  }

  private Map<String, Date> getCompleteFinishedDateQueryParameters() {
    Map<String, Date> parameters = new HashMap<String, Date>();

    parameters.put("finishedAfter", DateTimeUtil.parseDate(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_FINISHED_AFTER));
    parameters.put("finishedBefore", DateTimeUtil.parseDate(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_FINISHED_BEFORE));

    return parameters;
  }

  private Map<String, String> getCompleteFinishedDateAsStringQueryParameters() {
    Map<String, String> parameters = new HashMap<String, String>();

    parameters.put("finishedAfter", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_FINISHED_AFTER);
    parameters.put("finishedBefore", MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_FINISHED_BEFORE);

    return parameters;
  }

  private void verifyFinishedParameterQueryInvocations() {
    Map<String, Date> finishedDateParameters = getCompleteFinishedDateQueryParameters();

    verify(mockedQuery).finishedAfter(finishedDateParameters.get("finishedAfter"));
    verify(mockedQuery).finishedBefore(finishedDateParameters.get("finishedBefore"));

    verify(mockedQuery).list();
  }

  private void verifyStringFinishedParameterQueryInvocations() {
    Map<String, String> finishedDateParameters = getCompleteFinishedDateAsStringQueryParameters();

    verify(mockedQuery).finishedAfter(DateTimeUtil.parseDate(finishedDateParameters.get("finishedAfter")));
    verify(mockedQuery).finishedBefore(DateTimeUtil.parseDate(finishedDateParameters.get("finishedBefore")));

    verify(mockedQuery).list();
  }

  @Test
  public void testProcessQueryFinished() {
    given()
      .queryParam("finished", true)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).finished();
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testProcessQueryFinishedAsPost() {
    Map<String, Boolean> body = new HashMap<String, Boolean>();
    body.put("finished", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(body)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).finished();
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testProcessQueryUnfinished() {
    List<HistoricProcessInstance> mockedHistoricProcessInstances = MockProvider.createMockRunningHistoricProcessInstances();
    HistoricProcessInstanceQuery mockedhistoricProcessInstanceQuery = mock(HistoricProcessInstanceQuery.class);
    when(mockedhistoricProcessInstanceQuery.list()).thenReturn(mockedHistoricProcessInstances);
    when(processEngine.getHistoryService().createHistoricProcessInstanceQuery()).thenReturn(mockedhistoricProcessInstanceQuery);

    Response response = given()
        .queryParam("unfinished", true)
      .then()
        .expect()
          .statusCode(Status.OK.getStatusCode())
        .when()
          .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedhistoricProcessInstanceQuery);
    inOrder.verify(mockedhistoricProcessInstanceQuery).unfinished();
    inOrder.verify(mockedhistoricProcessInstanceQuery).list();

    String content = response.asString();
    List<String> instances = from(content).getList("");
    Assert.assertEquals("There should be one process instance returned.", 1, instances.size());
    Assert.assertNotNull("The returned process instance should not be null.", instances.get(0));

    String returnedProcessInstanceId = from(content).getString("[0].id");
    String returnedEndTime = from(content).getString("[0].endTime");

    Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_ID, returnedProcessInstanceId);
    Assert.assertEquals(null, returnedEndTime);
  }

  @Test
  public void testProcessQueryUnfinishedAsPost() {
    List<HistoricProcessInstance> mockedHistoricProcessInstances = MockProvider.createMockRunningHistoricProcessInstances();
    HistoricProcessInstanceQuery mockedhistoricProcessInstanceQuery = mock(HistoricProcessInstanceQuery.class);
    when(mockedhistoricProcessInstanceQuery.list()).thenReturn(mockedHistoricProcessInstances);
    when(processEngine.getHistoryService().createHistoricProcessInstanceQuery()).thenReturn(mockedhistoricProcessInstanceQuery);

    Map<String, Boolean> body = new HashMap<String, Boolean>();
    body.put("unfinished", true);

    Response response = given()
        .contentType(POST_JSON_CONTENT_TYPE)
        .body(body)
      .then()
        .expect()
          .statusCode(Status.OK.getStatusCode())
        .when()
          .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedhistoricProcessInstanceQuery);
    inOrder.verify(mockedhistoricProcessInstanceQuery).unfinished();
    inOrder.verify(mockedhistoricProcessInstanceQuery).list();

    String content = response.asString();
    List<String> instances = from(content).getList("");
    Assert.assertEquals("There should be one process instance returned.", 1, instances.size());
    Assert.assertNotNull("The returned process instance should not be null.", instances.get(0));

    String returnedProcessInstanceId = from(content).getString("[0].id");
    String returnedEndTime = from(content).getString("[0].endTime");

    Assert.assertEquals(MockProvider.EXAMPLE_PROCESS_INSTANCE_ID, returnedProcessInstanceId);
    Assert.assertEquals(null, returnedEndTime);
  }

  @Test
  public void testQueryWithIncidents() {
    given()
      .queryParam("withIncidents", true)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).withIncidents();
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryWithIncidentsAsPost() {
    Map<String, Boolean> body = new HashMap<String, Boolean>();
    body.put("withIncidents", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(body)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).withIncidents();
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryWithIncidentStatusOpen() {
    given()
      .queryParam("incidentStatus", "open")
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentStatus("open");
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryWithIncidentStatusOpenAsPost() {
    Map<String, String> body = new HashMap<String, String>();
    body.put("incidentStatus", "open");

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(body)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentStatus("open");
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryCountIncidentStatusOpenForPost() {
    Map<String,String> body = new HashMap<String, String>();
    body.put("incidentStatus", "open");
    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(body)
    .then()
      .expect()
        .body("count", equalTo(1))
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_COUNT_RESOURCE_URL);

    verify(mockedQuery).count();
    verify(mockedQuery).incidentStatus("open");
  }

  @Test
  public void testQueryWithIncidentStatusResolved() {
    given()
      .queryParam("incidentStatus", "resolved")
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentStatus("resolved");
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryWithIncidentStatusResolvedAsPost() {
    Map<String, String> body = new HashMap<String, String>();
    body.put("incidentStatus", "resolved");

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(body)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentStatus("resolved");
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryCountIncidentStatusResolvedForPost() {
    Map<String,String> body = new HashMap<String, String>();
    body.put("incidentStatus", "resolved");
    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(body)
    .then()
      .expect()
        .body("count", equalTo(1))
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_COUNT_RESOURCE_URL);

    verify(mockedQuery).count();
    verify(mockedQuery).incidentStatus("resolved");
  }

  @Test
  public void testQueryIncidentType() {
    given()
      .queryParam("incidentType", MockProvider.EXAMPLE_INCIDENT_TYPE)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentType(MockProvider.EXAMPLE_INCIDENT_TYPE);
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryIncidentTypeAsPost() {
    Map<String, String> body = new HashMap<String, String>();
    body.put("incidentType", MockProvider.EXAMPLE_INCIDENT_TYPE);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(body)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentType(MockProvider.EXAMPLE_INCIDENT_TYPE);
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryIncidentMessage() {
    given()
      .queryParam("incidentMessage", MockProvider.EXAMPLE_INCIDENT_MESSAGE)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentMessage(MockProvider.EXAMPLE_INCIDENT_MESSAGE);
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryIncidentMessageAsPost() {
    Map<String, String> body = new HashMap<String, String>();
    body.put("incidentMessage", MockProvider.EXAMPLE_INCIDENT_MESSAGE);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(body)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentMessage(MockProvider.EXAMPLE_INCIDENT_MESSAGE);
    inOrder.verify(mockedQuery).list();
  }
  @Test
  public void testQueryIncidentMessageLike() {
    given()
      .queryParam("incidentMessageLike", MockProvider.EXAMPLE_INCIDENT_MESSAGE_LIKE)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentMessageLike(MockProvider.EXAMPLE_INCIDENT_MESSAGE_LIKE);
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryIncidentMessageLikeAsPost() {
    Map<String, String> body = new HashMap<String, String>();
    body.put("incidentMessageLike", MockProvider.EXAMPLE_INCIDENT_MESSAGE_LIKE);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(body)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).incidentMessageLike(MockProvider.EXAMPLE_INCIDENT_MESSAGE_LIKE);
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryByProcessInstanceIds() {
    given()
      .queryParam("processInstanceIds", "firstProcessInstanceId,secondProcessInstanceId")
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyProcessInstanceIdSetInvovation();
  }

  @Test
  public void testQueryByProcessInstanceIdsAsPost() {
    Map<String, Set<String>> parameters = getCompleteProcessInstanceIdSetQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyProcessInstanceIdSetInvovation();
  }

  private Map<String, Set<String>> getCompleteProcessInstanceIdSetQueryParameters() {
    Map<String, Set<String>> parameters = new HashMap<String, Set<String>>();

    Set<String> processInstanceIds = new HashSet<String>();
    processInstanceIds.add("firstProcessInstanceId");
    processInstanceIds.add("secondProcessInstanceId");

    parameters.put("processInstanceIds", processInstanceIds);

    return parameters;
  }

  private void verifyProcessInstanceIdSetInvovation() {
    Map<String, Set<String>> parameters = getCompleteProcessInstanceIdSetQueryParameters();

    verify(mockedQuery).processInstanceIds(parameters.get("processInstanceIds"));
    verify(mockedQuery).list();
  }

  @Test
  public void testQueryByProcessDefinitionKeyNotIn() {
    given()
      .queryParam("processDefinitionKeyNotIn", "firstProcessInstanceKey,secondProcessInstanceKey")
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyProcessDefinitionKeyNotInListInvovation();
  }

  @Test
  public void testQueryByProcessDefinitionKeyNotInAsPost() {
    Map<String, List<String>> parameters = getCompleteProcessDefinitionKeyNotInListQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyProcessDefinitionKeyNotInListInvovation();
  }

  private Map<String, List<String>> getCompleteProcessDefinitionKeyNotInListQueryParameters() {
    Map<String, List<String>> parameters = new HashMap<String, List<String>>();

    List<String> processInstanceIds = new ArrayList<String>();
    processInstanceIds.add("firstProcessInstanceKey");
    processInstanceIds.add("secondProcessInstanceKey");

    parameters.put("processDefinitionKeyNotIn", processInstanceIds);

    return parameters;
  }

  private void verifyProcessDefinitionKeyNotInListInvovation() {
    Map<String, List<String>> parameters = getCompleteProcessDefinitionKeyNotInListQueryParameters();

    verify(mockedQuery).processDefinitionKeyNotIn(parameters.get("processDefinitionKeyNotIn"));
    verify(mockedQuery).list();
  }

  @Test
  public void testVariableParameters() {
    // equals
    String variableName = "varName";
    String variableValue = "varValue";
    String queryValue = variableName + "_eq_" + variableValue;

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).variableValueEquals(variableName, variableValue);

    // greater then
    queryValue = variableName + "_gt_" + variableValue;

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).variableValueGreaterThan(variableName, variableValue);

    // greater then equals
    queryValue = variableName + "_gteq_" + variableValue;

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).variableValueGreaterThanOrEqual(variableName, variableValue);

    // lower then
    queryValue = variableName + "_lt_" + variableValue;

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).variableValueLessThan(variableName, variableValue);

    // lower then equals
    queryValue = variableName + "_lteq_" + variableValue;

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).variableValueLessThanOrEqual(variableName, variableValue);

    // like
    queryValue = variableName + "_like_" + variableValue;

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).variableValueLike(variableName, variableValue);

    // not equals
    queryValue = variableName + "_neq_" + variableValue;

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).variableValueNotEquals(variableName, variableValue);
  }

  @Test
  public void testMultipleVariableParameters() {
    String variableName1 = "varName";
    String variableValue1 = "varValue";
    String variableParameter1 = variableName1 + "_eq_" + variableValue1;

    String variableName2 = "anotherVarName";
    String variableValue2 = "anotherVarValue";
    String variableParameter2 = variableName2 + "_neq_" + variableValue2;

    String queryValue = variableParameter1 + "," + variableParameter2;

    given()
      .queryParam("variables", queryValue)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).variableValueEquals(variableName1, variableValue1);
    verify(mockedQuery).variableValueNotEquals(variableName2, variableValue2);
  }

  @Test
  public void testMultipleVariableParametersAsPost() {
    String variableName = "varName";
    String variableValue = "varValue";
    String anotherVariableName = "anotherVarName";
    Integer anotherVariableValue = 30;

    Map<String, Object> variableJson = new HashMap<String, Object>();
    variableJson.put("name", variableName);
    variableJson.put("operator", "eq");
    variableJson.put("value", variableValue);

    Map<String, Object> anotherVariableJson = new HashMap<String, Object>();
    anotherVariableJson.put("name", anotherVariableName);
    anotherVariableJson.put("operator", "neq");
    anotherVariableJson.put("value", anotherVariableValue);

    List<Map<String, Object>> variables = new ArrayList<Map<String, Object>>();
    variables.add(variableJson);
    variables.add(anotherVariableJson);

    Map<String, Object> json = new HashMap<String, Object>();
    json.put("variables", variables);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(json)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).variableValueEquals(variableName, variableValue);
    verify(mockedQuery).variableValueNotEquals(eq(anotherVariableName), argThat(EqualsPrimitiveValue.numberValue(anotherVariableValue)));
  }

  @Test
  public void testTenantIdListParameter() {
    mockedQuery = setUpMockHistoricProcessInstanceQuery(createMockHistoricProcessInstancesTwoTenants());

    Response response = given()
      .queryParam("tenantIdIn", MockProvider.EXAMPLE_TENANT_ID_LIST)
    .then().expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).tenantIdIn(MockProvider.EXAMPLE_TENANT_ID, MockProvider.ANOTHER_EXAMPLE_TENANT_ID);
    verify(mockedQuery).list();

    String content = response.asString();
    List<String> executions = from(content).getList("");
    assertThat(executions).hasSize(2);

    String returnedTenantId1 = from(content).getString("[0].tenantId");
    String returnedTenantId2 = from(content).getString("[1].tenantId");

    assertThat(returnedTenantId1).isEqualTo(MockProvider.EXAMPLE_TENANT_ID);
    assertThat(returnedTenantId2).isEqualTo(MockProvider.ANOTHER_EXAMPLE_TENANT_ID);
  }

  @Test
  public void testTenantIdListPostParameter() {
    mockedQuery = setUpMockHistoricProcessInstanceQuery(createMockHistoricProcessInstancesTwoTenants());

    Map<String, Object> queryParameters = new HashMap<String, Object>();
    queryParameters.put("tenantIdIn", MockProvider.EXAMPLE_TENANT_ID_LIST.split(","));

    Response response = given()
        .contentType(POST_JSON_CONTENT_TYPE)
        .body(queryParameters)
    .expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).tenantIdIn(MockProvider.EXAMPLE_TENANT_ID, MockProvider.ANOTHER_EXAMPLE_TENANT_ID);
    verify(mockedQuery).list();

    String content = response.asString();
    List<String> executions = from(content).getList("");
    assertThat(executions).hasSize(2);

    String returnedTenantId1 = from(content).getString("[0].tenantId");
    String returnedTenantId2 = from(content).getString("[1].tenantId");

    assertThat(returnedTenantId1).isEqualTo(MockProvider.EXAMPLE_TENANT_ID);
    assertThat(returnedTenantId2).isEqualTo(MockProvider.ANOTHER_EXAMPLE_TENANT_ID);
  }

  @Test
  public void testWithoutTenantIdParameter() {
    mockedQuery = setUpMockHistoricProcessInstanceQuery(Collections.singletonList(MockProvider.createMockHistoricProcessInstance(null)));

    Response response = given()
      .queryParam("withoutTenantId", true)
      .then().expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).withoutTenantId();
    verify(mockedQuery).list();

    String content = response.asString();
    List<String> definitions = from(content).getList("");
    assertThat(definitions).hasSize(1);

    String returnedTenantId1 = from(content).getString("[0].tenantId");
    assertThat(returnedTenantId1).isEqualTo(null);
  }

  @Test
  public void testWithoutTenantIdPostParameter() {
    mockedQuery = setUpMockHistoricProcessInstanceQuery(Collections.singletonList(MockProvider.createMockHistoricProcessInstance(null)));

    Map<String, Object> queryParameters = new HashMap<String, Object>();
    queryParameters.put("withoutTenantId", true);

    Response response = given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(queryParameters)
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).withoutTenantId();
    verify(mockedQuery).list();

    String content = response.asString();
    List<String> definitions = from(content).getList("");
    assertThat(definitions).hasSize(1);

    String returnedTenantId1 = from(content).getString("[0].tenantId");
    assertThat(returnedTenantId1).isEqualTo(null);
  }

  private List<HistoricProcessInstance> createMockHistoricProcessInstancesTwoTenants() {
    return Arrays.asList(
        MockProvider.createMockHistoricProcessInstance(MockProvider.EXAMPLE_TENANT_ID),
        MockProvider.createMockHistoricProcessInstance(MockProvider.ANOTHER_EXAMPLE_TENANT_ID));
  }

  @Test
  public void testExecutedActivityBeforeAndAfterTimeQuery() {
    given()
      .queryParam(QUERY_PARAM_EXECUTED_ACTIVITY_BEFORE, MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_BEFORE)
      .queryParam(QUERY_PARAM_EXECUTED_ACTIVITY_AFTER, MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_AFTER)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyExecutedActivityParameterQueryInvocations();
  }

  @Test
  public void testExecutedActivityBeforeAndAfterTimeQueryAsPost() {
    Map<String, Date> parameters = getCompleteExecutedActivityDateQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyExecutedActivityParameterQueryInvocations();
  }

  @Test
  public void testExecutedActivityBeforeAndAfterTimeAsStringQueryAsPost() {
    Map<String, String> parameters = getCompleteExecutedActivityDateAsStringQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyStringExecutedActivityParameterQueryInvocations();
  }

  private void verifyExecutedActivityParameterQueryInvocations() {
    Map<String, Date> startDateParameters = getCompleteExecutedActivityDateQueryParameters();

    verify(mockedQuery).executedActivityBefore(startDateParameters.get(QUERY_PARAM_EXECUTED_ACTIVITY_BEFORE));
    verify(mockedQuery).executedActivityAfter(startDateParameters.get(QUERY_PARAM_EXECUTED_ACTIVITY_AFTER));

    verify(mockedQuery).list();
  }

  private void verifyStringExecutedActivityParameterQueryInvocations() {
    Map<String, String> startDateParameters = getCompleteExecutedActivityDateAsStringQueryParameters();

    verify(mockedQuery).executedActivityBefore(DateTimeUtil.parseDate(startDateParameters.get(QUERY_PARAM_EXECUTED_ACTIVITY_BEFORE)));
    verify(mockedQuery).executedActivityAfter(DateTimeUtil.parseDate(startDateParameters.get(QUERY_PARAM_EXECUTED_ACTIVITY_AFTER)));

    verify(mockedQuery).list();
  }

  private Map<String, Date> getCompleteExecutedActivityDateQueryParameters() {
    Map<String, Date> parameters = new HashMap<String, Date>();

    parameters.put(QUERY_PARAM_EXECUTED_ACTIVITY_BEFORE, DateTimeUtil.parseDate(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_BEFORE));
    parameters.put(QUERY_PARAM_EXECUTED_ACTIVITY_AFTER, DateTimeUtil.parseDate(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_AFTER));

    return parameters;
  }

  private Map<String, String> getCompleteExecutedActivityDateAsStringQueryParameters() {
    Map<String, String> parameters = new HashMap<String, String>();

    parameters.put(QUERY_PARAM_EXECUTED_ACTIVITY_AFTER, MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_AFTER);
    parameters.put(QUERY_PARAM_EXECUTED_ACTIVITY_BEFORE, MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_BEFORE);

    return parameters;
  }

  // ===================================================================================================================

  @Test
  public void testExecutedJobBeforeAndAfterTimeQuery() {
    given()
      .queryParam(QUERY_PARAM_EXECUTED_JOB_BEFORE, MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_BEFORE)
      .queryParam(QUERY_PARAM_EXECUTED_JOB_AFTER, MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_AFTER)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyExecutedJobParameterQueryInvocations();
  }

  @Test
  public void testExecutedJobBeforeAndAfterTimeQueryAsPost() {
    Map<String, Date> parameters = getCompleteExecutedJobDateQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyExecutedJobParameterQueryInvocations();
  }

  @Test
  public void testExecutedJobBeforeAndAfterTimeAsStringQueryAsPost() {
    Map<String, String> parameters = getCompleteExecutedJobDateAsStringQueryParameters();

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
      .then()
      .expect()
      .statusCode(Status.OK.getStatusCode())
      .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verifyStringExecutedJobParameterQueryInvocations();
  }

  @Test
  public void testExecutedActivityIdIn() {

    given()
      .queryParameter(QUERY_PARAM_EXECUTED_ACTIVITY_IDS, "1,2")
    .then().expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).executedActivityIdIn("1", "2");
  }

  @Test
  public void testExecutedActivityIdInAsPost() {
    Map<String, List<String>> parameters = new HashMap<String, List<String>>();
    parameters.put(QUERY_PARAM_EXECUTED_ACTIVITY_IDS, Arrays.asList("1", "2"));

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then().expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).executedActivityIdIn("1", "2");
  }

  @Test
  public void testActiveActivityIdIn() {

    given()
      .queryParameter(QUERY_PARAM_ACTIVE_ACTIVITY_IDS, "1,2")
    .then().expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).activeActivityIdIn("1", "2");
  }

  @Test
  public void testActiveActivityIdInAsPost() {
    Map<String, List<String>> parameters = new HashMap<String, List<String>>();
    parameters.put(QUERY_PARAM_ACTIVE_ACTIVITY_IDS, Arrays.asList("1", "2"));

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then().expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).activeActivityIdIn("1", "2");
  }

  @Test
  public void testQueryWithRootIncidents() {
    given()
      .queryParam("withRootIncidents", true)
    .then().expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    InOrder inOrder = inOrder(mockedQuery);
    inOrder.verify(mockedQuery).withRootIncidents();
    inOrder.verify(mockedQuery).list();
  }

  @Test
  public void testQueryWithRootIncidentsAsPost() {
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("withRootIncidents", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then().expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).withRootIncidents();
  }

  private void verifyExecutedJobParameterQueryInvocations() {
    Map<String, Date> startDateParameters = getCompleteExecutedJobDateQueryParameters();

    verify(mockedQuery).executedJobBefore(startDateParameters.get(QUERY_PARAM_EXECUTED_JOB_BEFORE));
    verify(mockedQuery).executedJobAfter(startDateParameters.get(QUERY_PARAM_EXECUTED_JOB_AFTER));

    verify(mockedQuery).list();
  }

  private void verifyStringExecutedJobParameterQueryInvocations() {
    Map<String, String> startDateParameters = getCompleteExecutedJobDateAsStringQueryParameters();

    verify(mockedQuery).executedJobBefore(DateTimeUtil.parseDate(startDateParameters.get(QUERY_PARAM_EXECUTED_JOB_BEFORE)));
    verify(mockedQuery).executedJobAfter(DateTimeUtil.parseDate(startDateParameters.get(QUERY_PARAM_EXECUTED_JOB_AFTER)));

    verify(mockedQuery).list();
  }

  private Map<String, Date> getCompleteExecutedJobDateQueryParameters() {
    Map<String, Date> parameters = new HashMap<String, Date>();

    parameters.put(QUERY_PARAM_EXECUTED_JOB_BEFORE, DateTimeUtil.parseDate(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_BEFORE));
    parameters.put(QUERY_PARAM_EXECUTED_JOB_AFTER, DateTimeUtil.parseDate(MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_AFTER));

    return parameters;
  }

  private Map<String, String> getCompleteExecutedJobDateAsStringQueryParameters() {
    Map<String, String> parameters = new HashMap<String, String>();

    parameters.put(QUERY_PARAM_EXECUTED_JOB_AFTER, MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_AFTER);
    parameters.put(QUERY_PARAM_EXECUTED_JOB_BEFORE, MockProvider.EXAMPLE_HISTORIC_PROCESS_INSTANCE_STARTED_BEFORE);

    return parameters;
  }

  @Test
  public void testQueryByActive() {
    given()
      .queryParam("active", true)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).active();
  }

  @Test
  public void testQueryByCompleted() {
    given()
      .queryParam("completed", true)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).completed();
  }

  @Test
  public void testQueryBySuspended() {
    given()
      .queryParam("suspended", true)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).suspended();
  }

  @Test
  public void testQueryByExternallyTerminated() {
    given()
      .queryParam("externallyTerminated", true)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).externallyTerminated();
  }

  @Test
  public void testQueryByInternallyTerminated() {
    given()
      .queryParam("internallyTerminated", true)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).internallyTerminated();
  }

  @Test
  public void testQueryByTwoStates() {
    String message = "expected exception";
    doThrow(new BadUserRequestException(message)).when(mockedQuery).completed();

    given()
      .queryParam("active", true)
      .queryParam("completed", true)
    .then()
      .statusCode(Status.BAD_REQUEST.getStatusCode())
      .contentType(ContentType.JSON)
      .body("type", equalTo(BadUserRequestException.class.getSimpleName()))
      .body("message", equalTo(message))
    .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).active();
  }

  @Test
  public void testQueryByActiveAsPost() {
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("active", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).active();
  }

  @Test
  public void testQueryByCompletedAsPost() {
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("completed", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).completed();
  }

  @Test
  public void testQueryBySuspendedAsPost() {
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("suspended", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).suspended();
  }

  @Test
  public void testQueryByExternallyTerminatedAsPost() {
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("externallyTerminated", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).externallyTerminated();
  }

  @Test
  public void testQueryByInternallyTerminatedAsPost() {
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("internallyTerminated", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then().expect()
      .statusCode(Status.OK.getStatusCode())
    .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).internallyTerminated();
  }

  @Test
  public void testQueryByTwoStatesAsPost() {
    String message = "expected exception";
    doThrow(new BadUserRequestException(message)).when(mockedQuery).completed();

    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("active", true);
    parameters.put("completed", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .statusCode(Status.BAD_REQUEST.getStatusCode())
      .contentType(ContentType.JSON)
      .body("type", equalTo(BadUserRequestException.class.getSimpleName()))
      .body("message", equalTo(message))
    .when()
      .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).active();
  }

  @Test
  public void testQueryByRootProcessInstances() {
    given()
      .queryParam("rootProcessInstances", true)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .get(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).rootProcessInstances();
  }

  @Test
  public void testQueryByRootProcessInstancesAsPost() {
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("rootProcessInstances", true);

    given()
      .contentType(POST_JSON_CONTENT_TYPE)
      .body(parameters)
    .then()
      .expect()
        .statusCode(Status.OK.getStatusCode())
      .when()
        .post(HISTORIC_PROCESS_INSTANCE_RESOURCE_URL);

    verify(mockedQuery).rootProcessInstances();
  }

}


text:
package main

// Generated from setup.sql
const (
	NEEDS_INIT = `SELECT name FROM sqlite_master WHERE type='table' and name=?;`
)

var (
	CREATE_INDEX = map[string]string{
		"uploads":            `CREATE INDEX uploadsindex ON uploads(track);`,
		"points_of_interest": `CREATE INDEX POIsindex ON points_of_interest(track);`,
		"trackpoints":        `CREATE INDEX trackpointindex ON trackpoints(track);`,
	}
	CREATE_TABLE = map[string]string{
		"trackpoints":        `CREATE TABLE trackpoints ( track     INTEGER NOT NULL, time      TIMESTAMP NOT NULL, latitude  REAL NOT NULL, longitude REAL NOT NULL, "elevation/m" REAL NOT NULL,  "height/m"    REAL NOT NULL,  "heartrate/bpm" INTEGER, "cadence/rpm"   INTEGER, unknown TEXT, FOREIGN KEY(track) REFERENCES tracks(id) ON DELETE CASCADE );`,
		"uploads":            `CREATE TABLE uploads ( track INTEGER NOT NULL, url   TEXT, FOREIGN KEY(track) REFERENCES tracks(id) ON DELETE CASCADE );`,
		"points_of_interest": `CREATE TABLE points_of_interest ( track       INTEGER, time        TIMESTAMP NOT NULL, latitude    REAL NOT NULL, longitude   REAL NOT NULL, description TEXT, FOREIGN KEY(track) REFERENCES tracks(id) ON DELETE SET NULL );`,
		"tracks":             `CREATE TABLE tracks ( id   INTEGER PRIMARY KEY, time TIMESTAMP NOT NULL, name TEXT,  "distance/m" INTEGER NOT NULL, "duration/s" INTEGER NOT NULL, "ascent/m"  INTEGER NOT NULL, "descent/m" INTEGER NOT NULL, unknown TEXT );`,
	}
	INSERT = map[string]string{
		"POI":        `INSERT INTO points_of_interest(track, time, latitude, longitude) VALUES (?, ?, ?, ?);`,
		"trackpoint": `INSERT INTO trackpoints VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);`,
		"track":      `INSERT INTO tracks(time, name, "distance/m", "duration/s",  "ascent/m", "descent/m", unknown) VALUES (?, ?, ?, ?, ?, ?, ?);`,
	}
)

redpajama_set_name: RedPajamaGithub


text:
from enum import Enum

from .utilities import wmask
from .bitstring import (bitstring, bit0, bit1, zeros)

class SRType(Enum):
    SRType_None = 0
    SRType_LSL = 1
    SRType_LSR = 2
    SRType_ASR = 3
    SRType_ROR = 4
    SRType_RRX = 5

def Align(value, alignment):
    assert alignment != 0
    if isinstance(value, bitstring):
        mask = ~bitstring(alignment - 1, value.width)
    else:
        mask = ~(alignment - 1)
    return value & mask

##
# @return (bits(N), bit, bit)
def AddWithCarry(x, y, carry_in):
    assert x.width == y.width
    unsigned_sum = x.unsigned + y.unsigned + carry_in.unsigned
    signed_sum = x.signed + y.signed + carry_in.unsigned
    result = bitstring(unsigned_sum, x.width) # same value as signed_sum<N-1:0>
    carry_out = bit0 if result.unsigned == unsigned_sum else bit1
    overflow = bit0 if result.signed == signed_sum else bit1
    return (result, carry_out, overflow)

def LSL_C(x, shift):
    assert shift > 0
    ext_x = x % zeros(shift)
    result = ext_x[0:x.width]
    carry_out = ext_x[x.width]
    return result, carry_out

def LSL(x, shift):
    return x << shift

def LSR_C(x, shift):
    assert shift > 0
    ext_x = x.zero_extend(shift + x.width)
    result = ext_x[shift:shift+x.width]
    carry_out = ext_x[shift-1]
    return result, carry_out

def LSR(x, shift):
    return x >> shift

def ASR_C(x, shift):
    assert shift > 0
    ext_x = x.sign_extend(shift + x.width)
    result = ext_x[shift:shift+x.width]
    carry_out = ext_x[shift-1]
    return result, carry_out

def ASR(x, shift):
    assert shift >= 0
    if shift == 0:
        result = c
    else:
        result, _ = ASR_C(x, shift)
    return result

def ROR_C(x, shift):
    assert shift != 0
    m = shift % x.width
    result = LSR(x, m) | (LSL(x, x.width - m))
    carry_out = result[x.width-1]
    return result, carry_out

def ROR(x, shift):
    if shift == 0:
        result = x
    else:
        result, _ = ROR_C(x, shift)
    return result

def RRX_C(x, carry_in):
    result = carry_in % x[1:x.width]
    carry_out = x[0]
    return result, carry_out

def RRX(x, carry_in):
    result, _ = RRX_C(x, carry_in)
    return result

def Shift_C(value, type, amount, carry_in):
    assert not (type == SRType.SRType_RRX and amount != 1)

    if amount == 0 or type == SRType.SRType_None:
        result, carry_out = value, carry_in
    else:
        if type == SRType.SRType_LSL:
            result, carry_out = LSL_C(value, amount)
        elif type == SRType.SRType_LSR:
            result, carry_out = LSR_C(value, amount)
        elif type == SRType.SRType_ASR:
            result, carry_out = ASR_C(value, amount)
        elif type == SRType.SRType_ROR:
            result, carry_out = ROR_C(value, amount)
        elif type == SRType.SRType_RRX:
            result, carry_out = RRX_C(value, carry_in)

    return result, carry_out

def Shift(value, type, amount, carry_in):
    result, _ = Shift_C(value, type, amount , carry_in)
    return result

def DecodeImmShift(type, imm5):
    if type == '00':
        shift_t = SRType.SRType_LSL
        shift_n = imm5.unsigned
    elif type == '01':
        shift_t = SRType.SRType_LSR
        shift_n = 32 if imm5 == '00000' else imm5.unsigned
    elif type == '10':
        shift_t = SRType.SRType_ASR
        shift_n = 32 if imm5 == '00000' else imm5.unsigned
    elif type == '11':
        if imm5 == '00000':
            shift_t = SRType.SRType_RRX
            shift_n = 1
        else:
            shift_t = SRType.SRType_ROR
            shift_n = imm5.unsigned
    else:
        raise ValueError("unknown type value %s" % type)
    return shift_t, shift_n

# @param carry_in Either passed through unchanged or not used. Does not affect result imm32.
def ThumbExpandImm_C(imm12, carry_in):
    if imm12[10:12] == '00':
        imm12_8 = imm12[8:10]
        imm12_0 = imm12[0:8]
        if imm12_8 == '00':
            imm32 = imm12_0.zero_extend(32)
        elif imm12_8 == '01':
            imm32 = bitstring('00000000') % imm12_0 % bitstring('00000000') % imm12_0
        elif imm12_8 == '10':
            imm32 = imm12_0 % bitstring('00000000') % imm12_0 % bitstring('00000000')
        elif imm12_8 == '11':
            imm32 = imm12_0 % imm12_0 % imm12_0 % imm12_0
        carry_out = carry_in
    else:
        unrotated_value = (bit1 % imm12[0:7]).zero_extend(32)
        imm32, carry_out = ROR_C(unrotated_value, imm12[7:12].unsigned)
    return imm32, carry_out

def ThumbExpandImm(imm12):
    # Carry in param to this call is ignored.
    imm32, _ = ThumbExpandImm_C(imm12, bit0)
    return imm32


text:
{-# language CPP #-}
-- | = Name
--
-- VK_NV_shader_image_footprint - device extension
--
-- == VK_NV_shader_image_footprint
--
-- [__Name String__]
--     @VK_NV_shader_image_footprint@
--
-- [__Extension Type__]
--     Device extension
--
-- [__Registered Extension Number__]
--     205
--
-- [__Revision__]
--     2
--
-- [__Extension and Version Dependencies__]
--
--     -   Requires support for Vulkan 1.0
--
--     -   Requires @VK_KHR_get_physical_device_properties2@ to be enabled
--         for any device-level functionality
--
-- [__Contact__]
--
--     -   Pat Brown
--         <https://github.com/KhronosGroup/Vulkan-Docs/issues/new?body=[VK_NV_shader_image_footprint] @nvpbrown%0A*Here describe the issue or question you have about the VK_NV_shader_image_footprint extension* >
--
-- == Other Extension Metadata
--
-- [__Last Modified Date__]
--     2018-09-13
--
-- [__IP Status__]
--     No known IP claims.
--
-- [__Interactions and External Dependencies__]
--
--     -   This extension requires
--         <https://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/NV/SPV_NV_shader_image_footprint.html SPV_NV_shader_image_footprint>
--
--     -   This extension provides API support for
--         <https://github.com/KhronosGroup/GLSL/blob/master/extensions/nv/GLSL_NV_shader_texture_footprint.txt GL_NV_shader_texture_footprint>
--
-- [__Contributors__]
--
--     -   Pat Brown, NVIDIA
--
--     -   Chris Lentini, NVIDIA
--
--     -   Daniel Koch, NVIDIA
--
--     -   Jeff Bolz, NVIDIA
--
-- == Description
--
-- This extension adds Vulkan support for the
-- <https://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/NV/SPV_NV_shader_image_footprint.html SPV_NV_shader_image_footprint>
-- SPIR-V extension. That SPIR-V extension provides a new instruction
-- @OpImageSampleFootprintNV@ allowing shaders to determine the set of
-- texels that would be accessed by an equivalent filtered texture lookup.
--
-- Instead of returning a filtered texture value, the instruction returns a
-- structure that can be interpreted by shader code to determine the
-- footprint of a filtered texture lookup. This structure includes integer
-- values that identify a small neighborhood of texels in the image being
-- accessed and a bitfield that indicates which texels in that neighborhood
-- would be used. The structure also includes a bitfield where each bit
-- identifies whether any texel in a small aligned block of texels would be
-- fetched by the texture lookup. The size of each block is specified by an
-- access /granularity/ provided by the shader. The minimum granularity
-- supported by this extension is 2x2 (for 2D textures) and 2x2x2 (for 3D
-- textures); the maximum granularity is 256x256 (for 2D textures) or
-- 64x32x32 (for 3D textures). Each footprint query returns the footprint
-- from a single texture level. When using minification filters that
-- combine accesses from multiple mipmap levels, shaders must perform
-- separate queries for the two levels accessed ("fine" and "coarse"). The
-- footprint query also returns a flag indicating if the texture lookup
-- would access texels from only one mipmap level or from two neighboring
-- levels.
--
-- This extension should be useful for multi-pass rendering operations that
-- do an initial expensive rendering pass to produce a first image that is
-- then used as a texture for a second pass. If the second pass ends up
-- accessing only portions of the first image (e.g., due to visibility),
-- the work spent rendering the non-accessed portion of the first image was
-- wasted. With this feature, an application can limit this waste using an
-- initial pass over the geometry in the second image that performs a
-- footprint query for each visible pixel to determine the set of pixels
-- that it needs from the first image. This pass would accumulate an
-- aggregate footprint of all visible pixels into a separate "footprint
-- image" using shader atomics. Then, when rendering the first image, the
-- application can kill all shading work for pixels not in this aggregate
-- footprint.
--
-- This extension has a number of limitations. The
-- @OpImageSampleFootprintNV@ instruction only supports for two- and
-- three-dimensional textures. Footprint evaluation only supports the
-- CLAMP_TO_EDGE wrap mode; results are undefined for all other wrap modes.
-- Only a limited set of granularity values and that set does not support
-- separate coverage information for each texel in the original image.
--
-- When using SPIR-V generated from the OpenGL Shading Language, the new
-- instruction will be generated from code using the new
-- @textureFootprint*NV@ built-in functions from the
-- @GL_NV_shader_texture_footprint@ shading language extension.
--
-- == New Structures
--
-- -   Extending
--     'Vulkan.Core11.Promoted_From_VK_KHR_get_physical_device_properties2.PhysicalDeviceFeatures2',
--     'Vulkan.Core10.Device.DeviceCreateInfo':
--
--     -   'PhysicalDeviceShaderImageFootprintFeaturesNV'
--
-- == New Enum Constants
--
-- -   'NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME'
--
-- -   'NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION'
--
-- -   Extending 'Vulkan.Core10.Enums.StructureType.StructureType':
--
--     -   'Vulkan.Core10.Enums.StructureType.STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV'
--
-- == New SPIR-V Capability
--
-- -   <https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#spirvenv-capabilities-table-ImageFootprintNV ImageFootprintNV>
--
-- == Issues
--
-- (1) The footprint returned by the SPIR-V instruction is a structure that
-- includes an anchor, an offset, and a mask that represents a 8x8 or 4x4x4
-- neighborhood of texel groups. But the bits of the mask are not stored in
-- simple pitch order. Why is the footprint built this way?
--
-- __RESOLVED__: We expect that applications using this feature will want
-- to use a fixed granularity and accumulate coverage information from the
-- returned footprints into an aggregate "footprint image" that tracks the
-- portions of an image that would be needed by regular texture filtering.
-- If an application is using a two-dimensional image with 4x4 pixel
-- granularity, we expect that the footprint image will use 64-bit texels
-- where each bit in an 8x8 array of bits corresponds to coverage for a 4x4
-- block in the original image. Texel (0,0) in the footprint image would
-- correspond to texels (0,0) through (31,31) in the original image.
--
-- In the usual case, the footprint for a single access will fully
-- contained in a 32x32 aligned region of the original texture, which
-- corresponds to a single 64-bit texel in the footprint image. In that
-- case, the implementation will return an anchor coordinate pointing at
-- the single footprint image texel, an offset vector of (0,0), and a mask
-- whose bits are aligned with the bits in the footprint texel. For this
-- case, the shader can simply atomically OR the mask bits into the
-- contents of the footprint texel to accumulate footprint coverage.
--
-- In the worst case, the footprint for a single access spans multiple
-- 32x32 aligned regions and may require updates to four separate footprint
-- image texels. In this case, the implementation will return an anchor
-- coordinate pointing at the lower right footprint image texel and an
-- offset will identify how many "columns" and "rows" of the returned 8x8
-- mask correspond to footprint texels to the left and above the anchor
-- texel. If the anchor is (2,3), the 64 bits of the returned mask are
-- arranged spatially as follows, where each 4x4 block is assigned a bit
-- number that matches its bit number in the footprint image texels:
--
-- >     +-------------------------+-------------------------+
-- >     | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- |
-- >     | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- |
-- >     | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- |
-- >     | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- |
-- >     | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- |
-- >     | -- -- -- -- -- -- 46 47 | 40 41 42 43 44 45 -- -- |
-- >     | -- -- -- -- -- -- 54 55 | 48 49 50 51 52 53 -- -- |
-- >     | -- -- -- -- -- -- 62 63 | 56 57 58 59 60 61 -- -- |
-- >     +-------------------------+-------------------------+
-- >     | -- -- -- -- -- -- 06 07 | 00 01 02 03 04 05 -- -- |
-- >     | -- -- -- -- -- -- 14 15 | 08 09 10 11 12 13 -- -- |
-- >     | -- -- -- -- -- -- 22 23 | 16 17 18 19 20 21 -- -- |
-- >     | -- -- -- -- -- -- 30 31 | 24 25 26 27 28 29 -- -- |
-- >     | -- -- -- -- -- -- 38 39 | 32 33 34 35 36 37 -- -- |
-- >     | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- |
-- >     | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- |
-- >     | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- |
-- >     +-------------------------+-------------------------+
--
-- To accumulate coverage for each of the four footprint image texels, a
-- shader can AND the returned mask with simple masks derived from the x
-- and y offset values and then atomically OR the updated mask bits into
-- the contents of the corresponding footprint texel.
--
-- >     uint64_t returnedMask = (uint64_t(footprint.mask.x) | (uint64_t(footprint.mask.y) link:https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html# 32));
-- >     uint64_t rightMask    = ((0xFF [^] footprint.offset.x) * 0x0101010101010101UL);
-- >     uint64_t bottomMask   = 0xFFFFFFFFFFFFFFFFUL >> (8 * footprint.offset.y);
-- >     uint64_t bottomRight  = returnedMask & bottomMask & rightMask;
-- >     uint64_t bottomLeft   = returnedMask & bottomMask & (~rightMask);
-- >     uint64_t topRight     = returnedMask & (~bottomMask) & rightMask;
-- >     uint64_t topLeft      = returnedMask & (~bottomMask) & (~rightMask);
--
-- (2) What should an application do to ensure maximum performance when
-- accumulating footprints into an aggregate footprint image?
--
-- __RESOLVED__: We expect that the most common usage of this feature will
-- be to accumulate aggregate footprint coverage, as described in the
-- previous issue. Even if you ignore the anisotropic filtering case where
-- the implementation may return a granularity larger than that requested
-- by the caller, each shader invocation will need to use atomic functions
-- to update up to four footprint image texels for each level of detail
-- accessed. Having each active shader invocation perform multiple atomic
-- operations can be expensive, particularly when neighboring invocations
-- will want to update the same footprint image texels.
--
-- Techniques can be used to reduce the number of atomic operations
-- performed when accumulating coverage include:
--
-- -   Have logic that detects returned footprints where all components of
--     the returned offset vector are zero. In that case, the mask returned
--     by the footprint function is guaranteed to be aligned with the
--     footprint image texels and affects only a single footprint image
--     texel.
--
-- -   Have fragment shaders communicate using built-in functions from the
--     @VK_NV_shader_subgroup_partitioned@ extension or other shader
--     subgroup extensions. If you have multiple invocations in a subgroup
--     that need to update the same texel (x,y) in the footprint image,
--     compute an aggregate footprint mask across all invocations in the
--     subgroup updating that texel and have a single invocation perform an
--     atomic operation using that aggregate mask.
--
-- -   When the returned footprint spans multiple texels in the footprint
--     image, each invocation need to perform four atomic operations. In
--     the previous issue, we had an example that computed separate masks
--     for "topLeft", "topRight", "bottomLeft", and "bottomRight". When the
--     invocations in a subgroup have good locality, it might be the case
--     the "top left" for some invocations might refer to footprint image
--     texel (10,10), while neighbors might have their "top left" texels at
--     (11,10), (10,11), and (11,11). If you compute separate masks for
--     even\/odd x and y values instead of left\/right or top\/bottom, the
--     "odd\/odd" mask for all invocations in the subgroup hold coverage
--     for footprint image texel (11,11), which can be updated by a single
--     atomic operation for the entire subgroup.
--
-- == Examples
--
-- TBD
--
-- == Version History
--
-- -   Revision 2, 2018-09-13 (Pat Brown)
--
--     -   Add issue (2) with performance tips.
--
-- -   Revision 1, 2018-08-12 (Pat Brown)
--
--     -   Initial draft
--
-- == See Also
--
-- 'PhysicalDeviceShaderImageFootprintFeaturesNV'
--
-- == Document Notes
--
-- For more information, see the
-- <https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VK_NV_shader_image_footprint Vulkan Specification>
--
-- This page is a generated document. Fixes and changes should be made to
-- the generator scripts, not directly.
module Vulkan.Extensions.VK_NV_shader_image_footprint  ( PhysicalDeviceShaderImageFootprintFeaturesNV(..)
                                                       , NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION
                                                       , pattern NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION
                                                       , NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME
                                                       , pattern NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME
                                                       ) where

import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.Ptr (nullPtr)
import Foreign.Ptr (plusPtr)
import Vulkan.CStruct (FromCStruct)
import Vulkan.CStruct (FromCStruct(..))
import Vulkan.CStruct (ToCStruct)
import Vulkan.CStruct (ToCStruct(..))
import Vulkan.Zero (Zero(..))
import Data.String (IsString)
import Data.Typeable (Typeable)
import Foreign.Storable (Storable)
import Foreign.Storable (Storable(peek))
import Foreign.Storable (Storable(poke))
import qualified Foreign.Storable (Storable(..))
import GHC.Generics (Generic)
import Foreign.Ptr (Ptr)
import Data.Kind (Type)
import Vulkan.Core10.FundamentalTypes (bool32ToBool)
import Vulkan.Core10.FundamentalTypes (boolToBool32)
import Vulkan.Core10.FundamentalTypes (Bool32)
import Vulkan.Core10.Enums.StructureType (StructureType)
import Vulkan.Core10.Enums.StructureType (StructureType(STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV))
-- | VkPhysicalDeviceShaderImageFootprintFeaturesNV - Structure describing
-- shader image footprint features that can be supported by an
-- implementation
--
-- = Members
--
-- This structure describes the following feature:
--
-- = Description
--
-- See
-- <https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#textures-footprint Texel Footprint Evaluation>
-- for more information.
--
-- If the 'PhysicalDeviceShaderImageFootprintFeaturesNV' structure is
-- included in the @pNext@ chain of the
-- 'Vulkan.Core11.Promoted_From_VK_KHR_get_physical_device_properties2.PhysicalDeviceFeatures2'
-- structure passed to
-- 'Vulkan.Core11.Promoted_From_VK_KHR_get_physical_device_properties2.getPhysicalDeviceFeatures2',
-- it is filled in to indicate whether each corresponding feature is
-- supported. 'PhysicalDeviceShaderImageFootprintFeaturesNV' /can/ also be
-- used in the @pNext@ chain of 'Vulkan.Core10.Device.DeviceCreateInfo' to
-- selectively enable these features.
--
-- == Valid Usage (Implicit)
--
-- = See Also
--
-- <https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VK_NV_shader_image_footprint VK_NV_shader_image_footprint>,
-- 'Vulkan.Core10.FundamentalTypes.Bool32',
-- 'Vulkan.Core10.Enums.StructureType.StructureType'
data PhysicalDeviceShaderImageFootprintFeaturesNV = PhysicalDeviceShaderImageFootprintFeaturesNV
  { -- | #features-imageFootprint# @imageFootprint@ specifies whether the
    -- implementation supports the @ImageFootprintNV@ SPIR-V capability.
    imageFootprint :: Bool }
  deriving (Typeable, Eq)
#if defined(GENERIC_INSTANCES)
deriving instance Generic (PhysicalDeviceShaderImageFootprintFeaturesNV)
#endif
deriving instance Show PhysicalDeviceShaderImageFootprintFeaturesNV

instance ToCStruct PhysicalDeviceShaderImageFootprintFeaturesNV where
  withCStruct x f = allocaBytes 24 $ \p -> pokeCStruct p x (f p)
  pokeCStruct p PhysicalDeviceShaderImageFootprintFeaturesNV{..} f = do
    poke ((p `plusPtr` 0 :: Ptr StructureType)) (STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV)
    poke ((p `plusPtr` 8 :: Ptr (Ptr ()))) (nullPtr)
    poke ((p `plusPtr` 16 :: Ptr Bool32)) (boolToBool32 (imageFootprint))
    f
  cStructSize = 24
  cStructAlignment = 8
  pokeZeroCStruct p f = do
    poke ((p `plusPtr` 0 :: Ptr StructureType)) (STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV)
    poke ((p `plusPtr` 8 :: Ptr (Ptr ()))) (nullPtr)
    poke ((p `plusPtr` 16 :: Ptr Bool32)) (boolToBool32 (zero))
    f

instance FromCStruct PhysicalDeviceShaderImageFootprintFeaturesNV where
  peekCStruct p = do
    imageFootprint <- peek @Bool32 ((p `plusPtr` 16 :: Ptr Bool32))
    pure $ PhysicalDeviceShaderImageFootprintFeaturesNV
             (bool32ToBool imageFootprint)

instance Storable PhysicalDeviceShaderImageFootprintFeaturesNV where
  sizeOf ~_ = 24
  alignment ~_ = 8
  peek = peekCStruct
  poke ptr poked = pokeCStruct ptr poked (pure ())

instance Zero PhysicalDeviceShaderImageFootprintFeaturesNV where
  zero = PhysicalDeviceShaderImageFootprintFeaturesNV
           zero

type NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION = 2

-- No documentation found for TopLevel "VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION"
pattern NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION :: forall a . Integral a => a
pattern NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION = 2

type NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME = "VK_NV_shader_image_footprint"

-- No documentation found for TopLevel "VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME"
pattern NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME :: forall a . (Eq a, IsString a) => a
pattern NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME = "VK_NV_shader_image_footprint"


text:
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.sql.tree;

import com.google.common.collect.ImmutableList;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkArgument;

public class DereferenceExpression
        extends Expression
{
    private final Expression base;
    private final String fieldName;

    public DereferenceExpression(Expression base, String fieldName)
    {
        this(Optional.empty(), base, fieldName);
    }

    public DereferenceExpression(NodeLocation location, Expression base, String fieldName)
    {
        this(Optional.of(location), base, fieldName);
    }

    private DereferenceExpression(Optional<NodeLocation> location, Expression base, String fieldName)
    {
        super(location);
        checkArgument(base != null, "base is null");
        checkArgument(fieldName != null, "fieldName is null");
        this.base = base;
        this.fieldName = fieldName.toLowerCase();
    }

    @Override
    public <R, C> R accept(AstVisitor<R, C> visitor, C context)
    {
        return visitor.visitDereferenceExpression(this, context);
    }

    @Override
    public List<Node> getChildren()
    {
        return ImmutableList.of(base);
    }

    public Expression getBase()
    {
        return base;
    }

    public String getFieldName()
    {
        return fieldName;
    }

    /**
     * If this DereferenceExpression looks like a QualifiedName, return QualifiedName.
     * Otherwise return null
     */
    public static QualifiedName getQualifiedName(DereferenceExpression expression)
    {
        List<String> parts = tryParseParts(expression.base, expression.fieldName);
        return parts == null ? null : QualifiedName.of(parts);
    }

    public static Expression from(QualifiedName name)
    {
        Expression result = null;

        for (String part : name.getParts()) {
            if (result == null) {
                result = new Identifier(part);
            }
            else {
                result = new DereferenceExpression(result, part);
            }
        }

        return result;
    }

    private static List<String> tryParseParts(Expression base, String fieldName)
    {
        if (base instanceof Identifier) {
            return ImmutableList.of(((Identifier) base).getName(), fieldName);
        }
        else if (base instanceof DereferenceExpression) {
            QualifiedName baseQualifiedName = getQualifiedName((DereferenceExpression) base);
            if (baseQualifiedName != null) {
                List<String> newList = new ArrayList<>(baseQualifiedName.getParts());
                newList.add(fieldName);
                return newList;
            }
        }
        return null;
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        DereferenceExpression that = (DereferenceExpression) o;
        return Objects.equals(base, that.base) &&
                Objects.equals(fieldName, that.fieldName);
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(base, fieldName);
    }
}


text:
namespace edda {

template<typename T>
class ndarray_iterator
    : public thrust::iterator_adaptor<
        ndarray_iterator<T>, // the first template parameter is the name of the iterator we're creating
        Iterator                   // the second template parameter is the name of the iterator we're adapting
                                   // we can use the default for the additional template parameters
      >
{
  public:
    // shorthand for the name of the iterator_adaptor we're deriving from
    typedef thrust::iterator_adaptor<
      repeat_iterator<Iterator>,
      Iterator
    > super_t;
    __host__ __device__
    repeat_iterator(const Iterator &x, int n) : super_t(x), begin(x), n(n) {}
    // befriend thrust::iterator_core_access to allow it access to the private interface below
    friend class thrust::iterator_core_access;
  private:
    // repeat each element of the adapted range n times
    unsigned int n;
    // used to keep track of where we began
    const Iterator begin;
    // it is private because only thrust::iterator_core_access needs access to it
    __host__ __device__
    typename super_t::reference dereference() const
    {
      return *(begin + (this->base() - begin) / n);
    }
};

#endif // NDARRAY_ITERATOR


text:
#pragma once

#include <string>
#include "uifacet.h"

namespace aft {
namespace ui {
// Forward reference
class Element;

/**
 *  Interface of basic Element interactions.
 *
 *  Since element delegates are meant to be shared, subclasses that implement ElementDelegate
 *  must provide per-element storage. The Element class can be queried for properties and facets.
 *  Element also has storage for the string representation of the element's value.
 */
class ElementDelegate {
public:
    /** Flush an element */
    virtual void flush(const Element* element) = 0;
    /** Get the value for this element.
     *  @return The value of this element.
     */
    virtual const std::string& getValue(const Element* element) const = 0;
    /** Set the value for this element. */
    virtual void setValue(Element* element, const std::string& value) = 0;

    /** Get the focus state of the element. */
    virtual bool getFocus(Element* element) const = 0;
    /** Change focus state within element. */
    virtual bool setFocus(Element* element, bool hasFocus = true) = 0;
    /** Get facet by name and category */
    virtual bool getFacet(Element* element, const std::string& name, UIFacetCategory category,
                          UIFacet& facet) const = 0;
    /** Set a facet on an element */
    virtual bool setFacet(Element* element, const UIFacet& facet) = 0;

    /** Get user input from element */
    virtual bool input(Element* element, std::string& value) = 0;
    /** Output the element to the user interface
     *  TODO add bool to just output value
     */
    virtual bool output(const Element* element, bool showValue = false) = 0;
};

class BaseElementDelegate : public ElementDelegate {
public:
    BaseElementDelegate();
    virtual ~BaseElementDelegate() = default;

    virtual void flush(const Element* element) override;
    virtual const std::string& getValue(const Element* element) const override;
    virtual void setValue(Element* element, const std::string& value) override;
    virtual bool getFocus(Element* element) const override;
    virtual bool setFocus(Element* element, bool hasFocus = true) override;
    virtual bool getFacet(Element* element, const std::string& name, UIFacetCategory category,
                          UIFacet& facet) const override;
    virtual bool setFacet(Element* element, const UIFacet& facet) override;

    virtual bool input(Element* element, std::string& value) override;
    virtual bool output(const Element* element, bool showValue = false) override;
};

}
}