@Test
  public void shouldCorrectlyIdentifyEmptyDatabase2() {
    populateDatabase("CREATE (n:Person {name:'Michal'})-[:FRIEND_OF]->(d:Person {name:'Daniela'})");

    try {
      assertEmpty(database);
      fail();
    } catch (AssertionError e) {
      // ok
    }

    try {
      assertEmpty(database, InclusionPolicies.all());
      fail();
    } catch (AssertionError e) {
      // ok
    }

    try {
      assertEmpty(
          database,
          InclusionPolicies.all()
              .with(
                  new BaseNodeInclusionPolicy() {
                    @Override
                    public boolean include(Node node) {
                      return !node.hasLabel(DynamicLabel.label("Person"));
                    }
                  }));
      fail();
    } catch (AssertionError e) {
      // ok
    }

    assertEmpty(
        database,
        InclusionPolicies.all()
            .with(
                new BaseNodeInclusionPolicy() {
                  @Override
                  public boolean include(Node node) {
                    return !node.hasLabel(DynamicLabel.label("Person"));
                  }
                })
            .with(
                new RelationshipInclusionPolicy.Adapter() {
                  @Override
                  public boolean include(Relationship relationship) {
                    return !relationship.getStartNode().hasLabel(DynamicLabel.label("Person"))
                        && !relationship.getEndNode().hasLabel(DynamicLabel.label("Person"));
                  }
                }));
  }
  @Test
  public void shouldCorrectlyIdentifyEmptyDatabase() {
    assertEmpty(database);
    assertSameGraph(database, null);
    assertSameGraph(database, "");
    assertSameGraph(database, " ");
    assertSameGraph(database, "", InclusionPolicies.all());

    populateDatabase("CREATE (n:Person {name:'Michal'})");

    assertSameGraph(database, " ", InclusionPolicies.all().with(IncludeNoNodes.getInstance()));
  }
  @Test
  public void clearGraphWithoutRuntimeShouldDeleteBasedOnRelInclusionPolicy() {
    try (Transaction tx = database.beginTx()) {
      String cypher =
          "CREATE "
              + "(purple:Purple {name:'Purple'})<-[:REL]-(red1:Red {name:'Red'})-[:REL]->(black1:Black {name:'Black'})-[:REL]->(green:Green {name:'Green'}),"
              + "(red2:Red {name:'Red'})-[:REL]->(black2:Black {name:'Black'}), (blue1:Blue)-[:REL2]->(blue2:Blue)";

      populateDatabase(cypher);
      tx.success();
    }

    InclusionPolicies inclusionPolicies =
        InclusionPolicies.all().with(new BlueNodeInclusionPolicy()).with(new Rel2InclusionPolicy());
    try (Transaction tx = database.beginTx()) {
      clearGraph(database, inclusionPolicies);
      tx.success();
    }

    try (Transaction tx = database.beginTx()) {
      assertEquals(6, count(at(database).getAllNodes()));
      assertEquals(4, count(at(database).getAllRelationships()));
      tx.success();
    }
  }
  @Test
  public void equalGraphsShouldPassSubgraphTestWithNodeRelInclusionPolicies() {
    String dbCypher =
        "CREATE "
            + "(blue:Blue {name:'Blue'})<-[:REL]-(red1:Red {name:'Red'})-[:REL]->(black1:Black {name:'Black'})-[:REL]->(green:Green {name:'Green'}),"
            + "(red2:Red {name:'Red'})-[:REL]->(black2:Black {name:'Black'}), (c1:ChangeSet)-[:NEXT]->(c2:ChangeSet)";
    populateDatabase(dbCypher);

    String assertCypher =
        "CREATE "
            + "(blue:Blue {name:'Blue'})<-[:REL]-(red1:Red {name:'Red'})-[:REL]->(black1:Black {name:'Black'})-[:REL]->(green:Green {name:'Green'}),"
            + "(red2:Red {name:'Red'})-[:REL]->(black2:Black {name:'Black'})";

    assertSubgraph(
        database,
        assertCypher,
        InclusionPolicies.all()
            .with(new ExcludeChangeSetNodeInclusionPolicy())
            .with(new ExcludeNextInclusionPolicy()));
  }
  @Test
  public void shouldFailWhenWrongArgumentsPassed() {
    try {
      assertEmpty(null);
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      assertEmpty(null, InclusionPolicies.all());
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      assertSameGraph(null, null);
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      assertSameGraph(null, null, InclusionPolicies.all());
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      assertSubgraph(database, null);
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      assertSubgraph(null, null);
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      assertSubgraph(null, null, InclusionPolicies.all());
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      assertSubgraph(database, "");
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      assertSubgraph(database, " ");
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      assertSubgraph(database, null, InclusionPolicies.all());
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      clearGraph(null);
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }

    try {
      clearGraph(null, InclusionPolicies.all());
      fail();
    } catch (IllegalArgumentException e) {
      // ok
    }
  }
/** Integration test for {@link TimeTreeApi}. */
public class TimeTreeApiWithUUIDTest extends GraphAwareIntegrationTest {

  private final AtomicInteger counter = new AtomicInteger(0);
  private InclusionPolicies ignoreUuid =
      InclusionPolicies.all()
          .with(
              new NodePropertyInclusionPolicy() {
                @Override
                public boolean include(String s, Node node) {
                  return !s.equals("uuid");
                }
              });

  @Override
  protected void populateDatabase(GraphDatabaseService database) {
    super.populateDatabase(database);

    counter.set(0);
    database.registerTransactionEventHandler(
        new TransactionEventHandler.Adapter<Void>() {
          @Override
          public Void beforeCommit(TransactionData data) throws Exception {
            for (Node created : data.createdNodes()) {
              created.setProperty("uuid", "test-uuid-" + counter.incrementAndGet());
            }

            return null;
          }
        });
  }

  @Test
  public void trivialTreeShouldBeCreatedWhenFirstDayIsRequested() throws JSONException {
    // Given
    long dateInMillis = dateToMillis(2013, 5, 4);

    // When
    String result = httpClient.post(getUrl() + "single/" + dateInMillis, HttpStatus.SC_OK);

    // Then
    assertSameGraph(
        getDatabase(),
        "CREATE"
            + "(root:TimeTreeRoot {uuid:'test-uuid-1'}),"
            + "(root)-[:FIRST]->(year:Year {value:2013, uuid: 'test-uuid-2'}),"
            + "(root)-[:CHILD]->(year),"
            + "(root)-[:LAST]->(year),"
            + "(year)-[:FIRST]->(month:Month {value:5, uuid: 'test-uuid-3'}),"
            + "(year)-[:CHILD]->(month),"
            + "(year)-[:LAST]->(month),"
            + "(month)-[:FIRST]->(day:Day {value:4, uuid: 'test-uuid-4'}),"
            + "(month)-[:CHILD]->(day),"
            + "(month)-[:LAST]->(day)");

    assertEquals(
        "{\"id\":3,\"properties\":{\"value\":4,\"uuid\":\"test-uuid-4\"},\"labels\":[\"Day\"]}",
        result,
        true);
  }

  @Test
  public void consecutiveDaysShouldBeCreatedWhenRequested() throws JSONException {

    // Given
    long startDateInMillis = dateToMillis(2013, 5, 4);
    long endDateInMillis = dateToMillis(2013, 5, 7);

    // When
    String result =
        httpClient.post(
            getUrl() + "range/" + startDateInMillis + "/" + endDateInMillis, HttpStatus.SC_OK);

    // Then
    assertSameGraph(
        getDatabase(),
        "CREATE"
            + "(root:TimeTreeRoot),"
            + "(root)-[:FIRST]->(year:Year {value:2013}),"
            + "(root)-[:CHILD]->(year),"
            + "(root)-[:LAST]->(year),"
            + "(year)-[:FIRST]->(month:Month {value:5}),"
            + "(year)-[:CHILD]->(month),"
            + "(year)-[:LAST]->(month),"
            + "(month)-[:CHILD]->(day4:Day {value:4}),"
            + "(month)-[:CHILD]->(day5:Day {value:5}),"
            + "(month)-[:CHILD]->(day6:Day {value:6}),"
            + "(month)-[:CHILD]->(day7:Day {value:7}),"
            + "(month)-[:FIRST]->(day4),"
            + "(month)-[:LAST]->(day7),"
            + "(day4)-[:NEXT]->(day5),"
            + "(day5)-[:NEXT]->(day6),"
            + "(day6)-[:NEXT]->(day7)",
        ignoreUuid);

    assertEquals(
        "[{\"id\":3,\"properties\":{\"value\":4,\"uuid\":\"test-uuid-4\"},\"labels\":[\"Day\"]},{\"id\":4,\"properties\":{\"value\":5,\"uuid\":\"test-uuid-5\"},\"labels\":[\"Day\"]},{\"id\":5,\"properties\":{\"value\":6,\"uuid\":\"test-uuid-6\"},\"labels\":[\"Day\"]},{\"id\":6,\"properties\":{\"value\":7,\"uuid\":\"test-uuid-7\"},\"labels\":[\"Day\"]}]",
        result,
        true);
  }

  @Test
  public void trivialTreeShouldBeCreatedWhenFirstDayIsRequestedWithCustomRoot()
      throws JSONException {
    // Given
    long dateInMillis = dateToMillis(2013, 5, 4);

    // When
    try (Transaction tx = getDatabase().beginTx()) {
      getDatabase().createNode(label("CustomRoot"));
      tx.success();
    }

    String result = httpClient.post(getUrl() + "0/single/" + dateInMillis, HttpStatus.SC_OK);

    // Then
    assertSameGraph(
        getDatabase(),
        "CREATE"
            + "(root:CustomRoot),"
            + "(root)-[:FIRST]->(year:Year {value:2013}),"
            + "(root)-[:CHILD]->(year),"
            + "(root)-[:LAST]->(year),"
            + "(year)-[:FIRST]->(month:Month {value:5}),"
            + "(year)-[:CHILD]->(month),"
            + "(year)-[:LAST]->(month),"
            + "(month)-[:FIRST]->(day:Day {value:4}),"
            + "(month)-[:CHILD]->(day),"
            + "(month)-[:LAST]->(day)",
        ignoreUuid);

    assertEquals(
        "{\"id\":3,\"properties\":{\"value\":4,\"uuid\":\"test-uuid-4\"},\"labels\":[\"Day\"]}",
        result,
        true);
  }

  @Test
  public void consecutiveDaysShouldBeCreatedWhenRequestedWithCustomRoot() throws JSONException {

    // Given
    long startDateInMillis = dateToMillis(2013, 5, 4);
    long endDateInMillis = dateToMillis(2013, 5, 7);

    // When
    try (Transaction tx = getDatabase().beginTx()) {
      getDatabase().createNode(label("CustomRoot"));
      tx.success();
    }

    String result =
        httpClient.post(
            getUrl() + "0/range/" + startDateInMillis + "/" + endDateInMillis, HttpStatus.SC_OK);

    // Then
    assertSameGraph(
        getDatabase(),
        "CREATE"
            + "(root:CustomRoot),"
            + "(root)-[:FIRST]->(year:Year {value:2013}),"
            + "(root)-[:CHILD]->(year),"
            + "(root)-[:LAST]->(year),"
            + "(year)-[:FIRST]->(month:Month {value:5}),"
            + "(year)-[:CHILD]->(month),"
            + "(year)-[:LAST]->(month),"
            + "(month)-[:CHILD]->(day4:Day {value:4}),"
            + "(month)-[:CHILD]->(day5:Day {value:5}),"
            + "(month)-[:CHILD]->(day6:Day {value:6}),"
            + "(month)-[:CHILD]->(day7:Day {value:7}),"
            + "(month)-[:FIRST]->(day4),"
            + "(month)-[:LAST]->(day7),"
            + "(day4)-[:NEXT]->(day5),"
            + "(day5)-[:NEXT]->(day6),"
            + "(day6)-[:NEXT]->(day7)",
        ignoreUuid);

    assertEquals(
        "[{\"id\":3,\"properties\":{\"value\":4,\"uuid\":\"test-uuid-4\"},\"labels\":[\"Day\"]},{\"id\":4,\"properties\":{\"value\":5,\"uuid\":\"test-uuid-5\"},\"labels\":[\"Day\"]},{\"id\":5,\"properties\":{\"value\":6,\"uuid\":\"test-uuid-6\"},\"labels\":[\"Day\"]},{\"id\":6,\"properties\":{\"value\":7,\"uuid\":\"test-uuid-7\"},\"labels\":[\"Day\"]}]",
        result,
        true);
  }

  @Test
  public void trivialTreeShouldBeCreatedWhenTodayIsRequested() throws JSONException {
    // Given
    DateTime now = DateTime.now(DateTimeZone.UTC);

    // When
    String result = httpClient.post(getUrl() + "now", HttpStatus.SC_OK);

    // Then
    assertSameGraph(
        getDatabase(),
        "CREATE"
            + "(root:TimeTreeRoot),"
            + "(root)-[:FIRST]->(year:Year {value:"
            + now.getYear()
            + "}),"
            + "(root)-[:CHILD]->(year),"
            + "(root)-[:LAST]->(year),"
            + "(year)-[:FIRST]->(month:Month {value:"
            + now.getMonthOfYear()
            + "}),"
            + "(year)-[:CHILD]->(month),"
            + "(year)-[:LAST]->(month),"
            + "(month)-[:FIRST]->(day:Day {value:"
            + now.getDayOfMonth()
            + "}),"
            + "(month)-[:CHILD]->(day),"
            + "(month)-[:LAST]->(day)",
        ignoreUuid);

    assertEquals(
        "{\"id\":3,\"properties\":{\"value\":"
            + now.getDayOfMonth()
            + ",\"uuid\":\"test-uuid-4\"},\"labels\":[\"Day\"]}",
        result,
        true);
  }

  @Test
  public void trivialTreeShouldBeCreatedWhenTodayIsRequestedWithCustomRoot() throws JSONException {
    // Given
    DateTime now = DateTime.now(DateTimeZone.UTC);

    // When
    try (Transaction tx = getDatabase().beginTx()) {
      getDatabase().createNode(label("CustomRoot"));
      tx.success();
    }

    String result = httpClient.post(getUrl() + "/0/now", HttpStatus.SC_OK);

    // Then
    assertSameGraph(
        getDatabase(),
        "CREATE"
            + "(root:CustomRoot),"
            + "(root)-[:FIRST]->(year:Year {value:"
            + now.getYear()
            + "}),"
            + "(root)-[:CHILD]->(year),"
            + "(root)-[:LAST]->(year),"
            + "(year)-[:FIRST]->(month:Month {value:"
            + now.getMonthOfYear()
            + "}),"
            + "(year)-[:CHILD]->(month),"
            + "(year)-[:LAST]->(month),"
            + "(month)-[:FIRST]->(day:Day {value:"
            + now.getDayOfMonth()
            + "}),"
            + "(month)-[:CHILD]->(day),"
            + "(month)-[:LAST]->(day)",
        ignoreUuid);

    assertEquals(
        "{\"id\":3,\"properties\":{\"value\":"
            + now.getDayOfMonth()
            + ",\"uuid\":\"test-uuid-4\"},\"labels\":[\"Day\"]}",
        result,
        true);
  }

  private long dateToMillis(int year, int month, int day) {
    return dateToDateTime(year, month, day).getMillis();
  }

  private DateTime dateToDateTime(int year, int month, int day) {
    return new DateTime(year, month, day, 0, 0, DateTimeZone.UTC);
  }

  private String getUrl() {
    return baseUrl() + "/timetree/";
  }
}