/** Randomly generate several searches and check the result */
  @Test
  public void randomTests() {
    KdTreeSearchN alg = createAlg();

    KdTree tree = StandardKdTreeSearch1Tests.createTreeA();
    alg.setTree(tree);

    List<double[]> data = new ArrayList<double[]>();
    flattenTree(tree.root, data);

    for (int i = 0; i < 100; i++) {
      int searchN = rand.nextInt(data.size() + 5) + 1;

      double[] target = data.get(rand.nextInt(data.size()));

      double maxDistance = rand.nextDouble() * 10;

      List<double[]> expected = findNeighbors(data, target, maxDistance, searchN);

      found.reset();
      alg.setMaxDistance(maxDistance);
      alg.findNeighbor(target, searchN, found);
      assertEquals(expected.size(), found.size);

      for (int j = 0; j < expected.size(); j++) {
        checkContains(expected.get(j));
      }
    }
  }
  /**
   * Try several searches and see if they all produce good results. Just fine the nearest-neighbor
   */
  @Test
  public void findClosest_basic_1() {
    KdTreeSearchN alg = createAlg();

    KdTree tree = StandardKdTreeSearch1Tests.createTreeA();
    alg.setTree(tree);
    alg.setMaxDistance(Double.MAX_VALUE);

    // the first decision will be incorrect and it will need to back track
    found.reset();
    alg.findNeighbor(new double[] {11, 8}, 1, found);
    assertEquals(1, found.size);
    assertTrue(found.data[0].node == tree.root.right.right);

    // the root will be the best
    found.reset();
    alg.findNeighbor(new double[] {1.001, 1.99999}, 1, found);
    assertTrue(found.data[0].node == tree.root);

    // a point on the left branch will be a perfect fit
    found.reset();
    alg.findNeighbor(new double[] {2, 0.8}, 1, found);
    assertTrue(found.data[0].node == tree.root.left.right);

    // a point way outside the tree's bounds
    found.reset();
    alg.findNeighbor(new double[] {-10000, 0.5}, 1, found);
    assertTrue(found.data[0].node == tree.root.left.left);
  }
  /** See if it can handle a null leaf */
  @Test
  public void findClosest_nullLeaf() {
    KdTreeSearchN alg = createAlg();

    KdTree tree = StandardKdTreeSearch1Tests.createTreeWithNull();
    alg.setTree(tree);
    alg.setMaxDistance(Double.MAX_VALUE);

    // the first decision will be incorrect and it will need to back track
    found.reset();
    alg.findNeighbor(new double[] {2, 3}, 1, found);
    assertTrue(found.get(0).node == tree.root);
  }
  /** Make sure the distance it returns is correct */
  @Test
  public void checkDistance() {
    KdTreeSearchN alg = createAlg();

    KdTree tree = StandardKdTreeSearch1Tests.createTreeA();
    alg.setTree(tree);
    alg.setMaxDistance(Double.MAX_VALUE);

    double[] pt = new double[] {11.5, 8.2};
    found.reset();
    alg.findNeighbor(pt, 1, found);

    assertEquals(1, found.size);
    double d0 = found.get(0).node.point[0] - pt[0];
    double d1 = found.get(0).node.point[1] - pt[1];

    assertEquals(d0 * d0 + d1 * d1, found.get(0).distance, 1e-8);
  }