@Test
  public void mount() {
    Node node_a = new DirectoryNode("node_a");
    assertThat(node_a.getName(), is("node_a"));
    Node node_b1 = new DirectoryNode("node_b1");
    assertThat(node_a.isReachable(node_a), is(true));
    assertThat(node_a.isReachable(node_b1), is(false));
    assertThat(node_b1.isReachable(node_a), is(false));

    // simple mount: a->b1
    try {
      node_a.mount(node_b1);
    } catch (NodeException e) {
      Assert.fail("Unexpected exception: " + e);
      return;
    }
    assertThat(node_a.numChildren(), is(1));
    assertThat(node_a.hasChild("node_b1"), is(true));
    assertThat(node_a.getChild("node_b1"), is(node_b1));
    assertThat(node_a.isReachable(node_b1), is(true));
    assertThat(node_b1.isReachable(node_a), is(false));

    // duplicate mount
    try {
      node_a.mount(node_b1);
      Assert.fail("Expected exception: DuplicateName.");
      return;
    } catch (NodeException e) {
      assertThat(e.getReason(), is(NodeException.Reason.DuplicateName));
    }

    // mount a second node: a->b2
    Node node_b2 = new DirectoryNode("node_b2");
    try {
      node_a.mount(node_b2);
    } catch (NodeException e) {
      Assert.fail("Unexpected exception: " + e);
      return;
    }
    assertThat(node_a.numChildren(), is(2));
    assertThat(node_a.hasChild("node_b2"), is(true));
    assertThat(node_a.isReachable(node_b2), is(true));
    assertThat(node_b1.isReachable(node_b2), is(false));

    // mount more nodes: b1->c1->d1, b2->c2
    Node node_c1 = new DirectoryNode("node_c1");
    Node node_d1 = new DirectoryNode("node_d1");
    Node node_c2 = new DirectoryNode("node_c2");
    try {
      node_c1.mount(node_d1);
      node_b1.mount(node_c1);
      node_b2.mount(node_c2);
    } catch (NodeException e) {
      Assert.fail("Unexpected exception: " + e);
      return;
    }
    assertThat(node_a.numChildren(), is(2));
    assertThat(node_a.hasChild("node_d1"), is(false));
    assertThat(node_a.isReachable(node_c1), is(true));
    assertThat(node_a.isReachable(node_d1), is(true));
    assertThat(node_a.isReachable(node_c2), is(true));
    assertThat(node_c2.isReachable(node_d1), is(false));

    // unmount
    Assert.assertTrue(node_a.unmount(node_b1));
    assertThat(node_a.numChildren(), is(1));
    assertThat(node_a.hasChild("node_b1"), is(false));
    assertThat(node_a.isReachable(node_d1), is(false));

    // re-mount at different location: a->b2->c2->b1->c1->d1
    try {
      node_c2.mount(node_b1);
    } catch (NodeException e) {
      Assert.fail("Unexpected exception: " + e);
      return;
    }
    assertThat(node_a.isReachable(node_d1), is(true));

    // cyclic mount
    try {
      node_d1.mount(node_a);
      Assert.fail("Expected exception: Cyclic.");
      return;
    } catch (NodeException e) {
      assertThat(e.getReason(), is(NodeException.Reason.Cyclic));
    }

    // multiple paths: add a->d1
    try {
      node_a.mount(node_d1);
    } catch (NodeException e) {
      Assert.fail("Unexpected exception: " + e);
      return;
    }
    assertThat(node_a.numChildren(), is(2));
    assertThat(node_a.hasChild("node_d1"), is(true));
  }