Clean up Node interface (#60)

* NoteItem Remove @NonNull from private method parameters

* When creating node with null children treat as no children

* NodeItem use Lombok Getter/Setter

* Extract NodeTreeDraw

* Remove getData()

* Remove getChild()

* Remove getParent()

* Remove getChildByName()

* Merge NodeTreeDraw into Nodes

* Remove methodcound suppression

* [changelog] Updated
This commit is contained in:
Paul Campbell 2020-03-22 20:53:40 +00:00 committed by GitHub
parent 04e0e83748
commit 82f0c25b1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 207 additions and 357 deletions

View file

@ -9,16 +9,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
** Added
- Add kemitix-maven-tiles
- Add kemitix-maven-tiles 2.4.1
** Changed
- Replace Jenkins with Github Actions (#57)
- [checkstyle] suppress npath complexity issues
- [coverage] lower requirements
- Clean up changelog and readme, and remove external build dependencies (#38)
- Pinned pitest-junit5-plugin at 0.9 (#59)
- Moved: Node.drawTree to Nodes (#60)
** Removed
- Removed from Node: getChildByName, getParent, getChild, getData (#60
** Dependencies
- Bump kemitix-checkstyle-ruleset from 4.0.1 to 5.4.0 (#59)
- Bump kemitix-parent from 5.2.0 to 5.3.0 (#56)
- Bump lombok from 1.18.10 to 1.18.12 (#55)
- Bump assertj-core from 3.13.2 to 3.15.0 (#54)
- Bump junit from 4.12 to 4.13 (#53)
- Bump tiles-maven-plugin from 2.15 to 2.16 (#52)
- Bump hamcrest-core from 2.1 to 2.2 (#50)
- Bump lombok from 1.18.8 to 1.18.10 (#49)
- Bump assertj-core from 3.12.2 to 3.13.2 (#48)
@ -29,7 +42,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Bump lombok from 1.18.4 to 1.18.6 (#41)
- Bump tiles-maven-plugin from 2.12 to 2.13 (#40)
- Bump hamcrest-core from 1.3 to 2.1 (#37)
- Clean up changelog and readme, and remove external build dependencies (#38)
* [0.7.0] - 2017-02-18

View file

@ -58,13 +58,6 @@ public interface Node<T> {
*/
Optional<T> findData();
/**
* Fetch the data held within the node.
*
* @return the node's data, or throws an {@link EmptyNodeException}
*/
T getData();
/**
* Set the data held within the node.
*
@ -93,13 +86,6 @@ public interface Node<T> {
*/
Optional<Node<T>> findParent();
/**
* Fetch the parent node.
*
* @return the parent node, or throws an {@link OrphanedNodeException}
*/
Node<T> getParent();
/**
* Make the current node a direct child of the parent.
*
@ -157,15 +143,6 @@ public interface Node<T> {
*/
Optional<Node<T>> findChild(T child);
/**
* Fetches the node for the child if present.
*
* @param child the child's data to search for
*
* @return the child node if found
*/
Node<T> getChild(T child);
/**
* Checks if the node is an ancestor.
*
@ -202,25 +179,6 @@ public interface Node<T> {
*/
Optional<Node<T>> findChildByName(String name);
/**
* Returns the child with the given name. If one can't be found a
* NodeException is thrown.
*
* @param name the name of the child
*
* @return the node
*/
Node<T> getChildByName(String name);
/**
* Draw a representation of the tree.
*
* @param depth current depth for recursion
*
* @return a representation of the tree
*/
String drawTree(int depth);
/**
* Returns true if the Node has a name. Where a name supplier is used, the
* generated name is used.

View file

@ -21,7 +21,9 @@
package net.kemitix.node;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.val;
import java.util.*;
@ -38,15 +40,17 @@ import static net.kemitix.node.HeadTail.tail;
*
* @author Paul Campbell (pcampbell@kemitix.net)
*/
@SuppressWarnings("methodcount")
class NodeItem<T> implements Node<T> {
private final Set<Node<T>> children = new HashSet<>();
@Setter
private T data;
private Node<T> parent;
@Setter
@Getter
private String name;
/**
@ -57,14 +61,21 @@ class NodeItem<T> implements Node<T> {
* @param parent the parent of the node, or null for a root node
* @param children the children of the node - must not be null
*/
NodeItem(final T data, final String name, final Node<T> parent, @NonNull final Set<Node<T>> children) {
NodeItem(
final T data,
final String name,
final Node<T> parent,
final Set<Node<T>> children
) {
this.data = data;
this.name = name;
if (parent != null) {
doSetParent(parent);
}
if (children != null) {
this.children.addAll(children);
}
}
/**
* Sets the parent of a node without updating the parent in the process as {@link #setParent(Node)} does.
@ -75,34 +86,11 @@ class NodeItem<T> implements Node<T> {
this.parent = newParent;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(final String name) {
this.name = name;
}
@Override
public Optional<T> findData() {
return Optional.ofNullable(data);
}
@Override
public T getData() {
if (isEmpty()) {
throw new EmptyNodeException(getName());
}
return data;
}
@Override
public void setData(final T data) {
this.data = data;
}
@Override
public boolean isEmpty() {
return data == null;
@ -118,14 +106,6 @@ class NodeItem<T> implements Node<T> {
return Optional.ofNullable(parent);
}
@Override
public Node<T> getParent() {
if (parent == null) {
throw new OrphanedNodeException(getName());
}
return parent;
}
/**
* Make the current node a direct child of the parent.
*
@ -137,7 +117,7 @@ class NodeItem<T> implements Node<T> {
}
@SuppressWarnings("npathcomplexity")
private void doSetParent(@NonNull final Node<T> newParent) {
private void doSetParent(final Node<T> newParent) {
if (this.equals(newParent) || newParent.isDescendantOf(this)) {
throw new NodeException("Parent is a descendant");
}
@ -178,7 +158,7 @@ class NodeItem<T> implements Node<T> {
}
}
private void verifyChildIsNotAnAncestor(final @NonNull Node<T> child) {
private void verifyChildIsNotAnAncestor(final Node<T> child) {
if (this.equals(child) || isDescendantOf(child)) {
throw new NodeException("Child is an ancestor");
}
@ -237,11 +217,6 @@ class NodeItem<T> implements Node<T> {
.findFirst();
}
@Override
public Node<T> getChild(final T child) {
return findChild(child).orElseThrow(() -> new NodeException("Child not found"));
}
/**
* Checks if the node is an ancestor.
*
@ -323,33 +298,6 @@ class NodeItem<T> implements Node<T> {
.findAny();
}
@Override
public Node<T> getChildByName(final String named) {
final Optional<Node<T>> optional = findChildByName(named);
if (optional.isPresent()) {
return optional.get();
}
throw new NodeException("Named child not found");
}
@Override
@SuppressWarnings("movevariableinsideif")
public String drawTree(final int depth) {
final StringBuilder sb = new StringBuilder();
final String unnamed = "(unnamed)";
if (isNamed()) {
sb.append(formatByDepth(name, depth));
} else if (!children.isEmpty()) {
sb.append(formatByDepth(unnamed, depth));
}
getChildren().forEach(c -> sb.append(c.drawTree(depth + 1)));
return sb.toString();
}
private String formatByDepth(final String value, final int depth) {
return String.format("[%1$" + (depth + value.length()) + "s]\n", value);
}
@Override
public boolean isNamed() {
String currentName = getName();

View file

@ -123,4 +123,30 @@ public final class Nodes {
getImmutableChildren(source)
);
}
/**
* Draw a representation of the tree.
*
* @param depth current depth for recursion
* @return a representation of the tree
*/
@SuppressWarnings("movevariableinsideif")
public static <T> String drawTree(
final Node<T> node,
final int depth
) {
final StringBuilder sb = new StringBuilder();
final String unnamed = "(unnamed)";
if (node.isNamed()) {
sb.append(formatByDepth(node.getName(), depth));
} else if (!node.getChildren().isEmpty()) {
sb.append(formatByDepth(unnamed, depth));
}
node.getChildren().forEach(c -> sb.append(drawTree(c, depth + 1)));
return sb.toString();
}
private static String formatByDepth(final String value, final int depth) {
return String.format("[%1$" + (depth + value.length()) + "s]\n", value);
}
}

View file

@ -11,6 +11,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
@ -33,18 +34,6 @@ public class ImmutableNodeItemTest {
exception.expectMessage(IMMUTABLE_OBJECT);
}
@Test
public void getDataReturnsData() {
//given
val data = "this immutableNode data";
//when
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot(data));
//then
assertThat(immutableNode.getData()).as("can get the data from a immutableNode")
.
contains(data);
}
@Test
public void canCreateAnEmptyAndUnnamedNode() {
//when
@ -81,14 +70,15 @@ public class ImmutableNodeItemTest {
@Test
public void shouldContainImmutableCopyOfChild() {
//given
val parent = Nodes.unnamedRoot("root");
val child = Nodes.namedChild("child", "child", parent);
Node<String> parent = Nodes.unnamedRoot("root");
Node<String> child = Nodes.namedChild("child", "child", parent);
//when
immutableNode = Nodes.asImmutable(parent);
//then
val immutableChild = immutableNode.getChildByName("child");
assertThat(immutableChild).isNotSameAs(child);
assertThat(immutableChild.getName()).isEqualTo("child");
Optional<Node<String>> immutableChild =
immutableNode.findChildByName("child");
assertThat(immutableChild).isNotEqualTo(Optional.of(child));
assertThat(immutableChild.map(Node::getName)).contains("child");
}
@Test
@ -100,13 +90,14 @@ public class ImmutableNodeItemTest {
immutableNode = Nodes.asImmutable(parent);
//then
// get the immutable node's child's parent
val immutableChild = immutableNode.getChildByName("child");
final Optional<Node<String>> optionalParent = immutableChild.findParent();
if (optionalParent.isPresent()) {
val p = optionalParent.get();
assertThat(p).hasFieldOrPropertyWithValue("name", "root")
.hasFieldOrPropertyWithValue("data", "parent");
}
Optional<Node<String>> foundParent =
immutableNode.findChildByName("child")
.flatMap(Node::findParent);
assertThat(foundParent).isNotEmpty();
foundParent.ifPresent(p ->
assertThat(p)
.hasFieldOrPropertyWithValue("name", "root")
.hasFieldOrPropertyWithValue("data", "parent"));
}
@Test
@ -215,10 +206,9 @@ public class ImmutableNodeItemTest {
val result = immutableNode.findChild("child");
//then
assertThat(result.isPresent()).isTrue();
if (result.isPresent()) {
assertThat(result.get()
.getData()).contains("child");
}
result.map(resultNode ->
assertThat(resultNode.findData())
.contains("child"));
}
/**
@ -244,9 +234,10 @@ public class ImmutableNodeItemTest {
root.addChild(beta);
immutableNode = Nodes.asImmutable(root);
//when
val result = immutableNode.getChildByName("alpha");
Optional<Node<String>> result = immutableNode.findChildByName("alpha");
//then
assertThat(result.getName()).isEqualTo(alpha.getName());
assertThat(result.map(Node::getName))
.contains(alpha.getName());
}
@Test
@ -257,11 +248,10 @@ public class ImmutableNodeItemTest {
val beta = Nodes.namedRoot("beta data", "beta");
root.addChild(alpha);
root.addChild(beta);
exception.expect(NodeException.class);
exception.expectMessage("Named child not found");
immutableNode = Nodes.asImmutable(root);
//when
immutableNode.getChildByName("gamma");
//then
assertThat(immutableNode.findChildByName("gamma"))
.isEmpty();
}
@Test
@ -316,27 +306,6 @@ public class ImmutableNodeItemTest {
immutableNode.removeChild(null);
}
@Test
public void drawTreeIsCorrect() {
//given
val root = Nodes.namedRoot("root data", "root");
val bob = Nodes.namedChild("bob data", "bob", root);
val alice = Nodes.namedChild("alice data", "alice", root);
Nodes.namedChild("dave data", "dave", alice);
Nodes.unnamedChild("bob's child's data", bob); // has no name and no children so no included
val kim = Nodes.unnamedChild("kim data", root); // nameless mother
Nodes.namedChild("lucy data", "lucy", kim);
immutableNode = Nodes.asImmutable(root);
//when
val tree = immutableNode.drawTree(0);
//then
String[] lines = tree.split("\n");
assertThat(lines).contains("[root]", "[ alice]", "[ dave]", "[ (unnamed)]", "[ lucy]", "[ bob]");
assertThat(lines).containsSubsequence("[root]", "[ alice]", "[ dave]");
assertThat(lines).containsSubsequence("[root]", "[ (unnamed)]", "[ lucy]");
assertThat(lines).containsSubsequence("[root]", "[ bob]");
}
@Test
public void setDataShouldThrowException() {
//given
@ -355,28 +324,6 @@ public class ImmutableNodeItemTest {
immutableNode.createChild("child data", "child name");
}
@Test
public void canGetChildWhenFound() {
//given
val root = Nodes.unnamedRoot("data");
val child = Nodes.namedChild("child data", "child name", root);
immutableNode = Nodes.asImmutable(root);
//when
val found = immutableNode.getChild("child data");
//then
assertThat(found.getName()).isEqualTo(child.getName());
}
@Test
public void canGetChildWhenNotFound() {
//given
exception.expect(NodeException.class);
exception.expectMessage("Child not found");
immutableNode = Nodes.asImmutable(Nodes.unnamedRoot("data"));
//when
immutableNode.getChild("child data");
}
@Test
public void canSafelyHandleFindChildWhenAChildHasNoData() {
//given
@ -437,15 +384,16 @@ public class ImmutableNodeItemTest {
Nodes.namedChild("eight", "eight", n6);
val immutableRoot = Nodes.asImmutable(node);
//when
val result = immutableRoot.stream()
.collect(Collectors.toList());
val result = immutableRoot.stream().collect(Collectors.toList());
//then
assertThat(result).as("full tree")
.hasSize(9);
assertThat(result).as("full tree").hasSize(9);
// and
assertThat(immutableRoot.getChild("one")
.stream()
.collect(Collectors.toList())).as("sub-tree")
.hasSize(4);
assertThat(immutableRoot
.findChild("one")
.map(Node::stream)
.map(Stream::count)
)
.as("sub-tree")
.contains(4L);
}
}

View file

@ -0,0 +1,4 @@
package net.kemitix.node;
public interface IsNamedCategory {
}

View file

@ -27,27 +27,6 @@ public class NodeItemTest {
private Node<String> node;
@Test
public void getDataReturnsData() {
//given
val data = "this node data";
//when
node = Nodes.unnamedRoot(data);
//then
assertThat(node.getData()).as("can get the data from a node")
.contains(data);
}
@Test
public void getDataWhenEmptyThrowsException() throws Exception {
//given
node = Nodes.unnamedRoot(null);
assertThat(node.isEmpty()).isTrue();
exception.expect(EmptyNodeException.class);
//when
node.getData();
}
@Test
public void findDataWhenFullReturnsData() {
//given
@ -69,26 +48,6 @@ public class NodeItemTest {
assertThat(result).isEmpty();
}
@Test
public void getParentWhenRootThrowsException() {
//given
node = Nodes.unnamedRoot(null);
exception.expect(OrphanedNodeException.class);
//when
node.getParent();
}
@Test
public void getParentWhenChildReturnsRoot() {
//given
val root = Nodes.unnamedRoot("root");
node = Nodes.unnamedChild("child", root);
//when
val result = node.getParent();
//then
assertThat(result).isSameAs(root);
}
@Test
public void findParentWhenRootReturnsEmptyOptional() {
//given
@ -607,34 +566,6 @@ public class NodeItemTest {
assertThat(node.findData()).isEmpty();
}
@Test
public void getChildNamedFindsChild() {
//given
node = Nodes.namedRoot("root data", "root");
val alpha = Nodes.namedRoot("alpha data", "alpha");
val beta = Nodes.namedRoot("beta data", "beta");
node.addChild(alpha);
node.addChild(beta);
//when
val result = node.getChildByName("alpha");
//then
assertThat(result).isSameAs(alpha);
}
@Test
public void getChildNamedFindsNothing() {
//given
node = Nodes.namedRoot("root data", "root");
val alpha = Nodes.namedRoot("alpha data", "alpha");
val beta = Nodes.namedRoot("beta data", "beta");
node.addChild(alpha);
node.addChild(beta);
exception.expect(NodeException.class);
exception.expectMessage("Named child not found");
//when
node.getChildByName("gamma");
}
@Test
public void nodeNamesAreUniqueWithinAParent() {
//given
@ -656,23 +587,38 @@ public class NodeItemTest {
//when
node.insertInPath(four, "one", "two", "three");
//then
val three = four.getParent();
assertThat(four.getParent()).as("add node to a tree")
.isNotNull();
assertThat(three.getName()).isEqualTo("three");
val two = three.getParent();
assertThat(two.getName()).isEqualTo("two");
val one = two.getParent();
assertThat(one.getName()).isEqualTo("one");
assertThat(one.getParent()).isSameAs(node);
assertThat(node.getChildByName("one")
.getChildByName("two")
.getChildByName("three")
.getChildByName("four")).isSameAs(four);
assertThat(four.findParent())
.as("add node to a tree")
.isNotEmpty();
val three = four.findParent();
assertThat(three).isNotEmpty();
three.map(threeNode ->
assertThat(threeNode.getName())
.isEqualTo("three"));
val two = three.flatMap(Node::findParent);
assertThat(two).isNotEmpty();
two.map(twoNode ->
assertThat(twoNode.getName())
.isEqualTo("two"));
val one = two.flatMap(Node::findParent);
assertThat(one).isNotEmpty();
one.ifPresent(oneNode ->
SoftAssertions.assertSoftly(softly -> {
assertThat(oneNode.getName()).isEqualTo("one");
assertThat(oneNode.findParent()).contains(node);
}));
Optional<Node<String>> fourNode = node.findChildByName("one")
.flatMap(oneChild -> oneChild.findChildByName("two"))
.flatMap(twoChild -> twoChild.findChildByName("three"))
.flatMap(threeChild -> threeChild.findChildByName("four"));
assertThat(fourNode).isNotEmpty();
assertThat(fourNode).contains(four);
}
@Test
@SuppressWarnings("unchecked")
public void canPlaceInTreeUnderExistingNode() {
//given
node = Nodes.namedRoot(null, "root");
@ -682,15 +628,17 @@ public class NodeItemTest {
node.insertInPath(child); // as root/child
node.insertInPath(grandchild, "child"); // as root/child/grandchild
//then
assertThat(node.getChildByName("child")).as("child")
.isSameAs(child);
assertThat(node.getChildByName("child")
.getChildByName("grandchild")).as("grandchild")
.isSameAs(grandchild);
assertThat(node.findChildByName("child"))
.as("child")
.contains(child);
Optional<Node<String>> grandNode = node.findChildByName("child")
.flatMap(childNode -> childNode.findChildByName("grandchild"));
assertThat(grandNode)
.as("grandchild")
.contains(grandchild);
}
@Test
@SuppressWarnings("unchecked")
public void canPlaceInTreeAboveExistingNode() {
//given
node = Nodes.namedRoot(null, "root");
@ -700,12 +648,14 @@ public class NodeItemTest {
node.insertInPath(grandchild, "child");
node.insertInPath(child);
//then
assertThat(node.getChildByName("child")
.getData()).as("data in tree")
assertThat(node.findChildByName("child").flatMap(Node::findData))
.as("data in tree")
.contains("child data");
assertThat(node.getChildByName("child")
.getChildByName("grandchild")).as("grandchild")
.isSameAs(grandchild);
assertThat(
node.findChildByName("child").flatMap(childNode ->
childNode.findChildByName("grandchild")))
.as("grandchild")
.contains(grandchild);
}
@Test
@ -756,7 +706,6 @@ public class NodeItemTest {
}
@Test
@SuppressWarnings("unchecked")
public void placeNodeInTreeWhenEmptyChildWithTargetNameExists() {
//given
node = Nodes.unnamedRoot(null);
@ -764,17 +713,17 @@ public class NodeItemTest {
final Node<String> target = Nodes.namedRoot(null, "target");
node.addChild(child);
child.addChild(target);
val addMe = Nodes.namedRoot("I'm new", "target");
Node<String> addMe = Nodes.namedRoot("I'm new", "target");
assertThat(addMe.findParent()).isEmpty();
assertThat(child.getChildByName("target")
.isEmpty()).as("target starts empty")
.isTrue();
assertThat(child.findChildByName("target").flatMap(Node::findData))
.as("target starts empty")
.isEmpty();
//when
// addMe should replace target as the sole descendant of child
node.insertInPath(addMe, "child");
//then
assertThat(child.getChildByName("target")
.getData()).as("target now contains data")
assertThat(child.findChildByName("target").flatMap(Node::findData))
.as("target now contains data")
.contains("I'm new");
}
@ -789,14 +738,16 @@ public class NodeItemTest {
}
@Test
@Category(IsNamedCategory.class)
public void isNamedNull() {
//given
node = Nodes.unnamedRoot(null);
node = Nodes.namedRoot(null, null);
//then
assertThat(node.isNamed()).isFalse();
}
@Test
@Category(IsNamedCategory.class)
public void isNamedEmpty() {
//given
node = Nodes.namedRoot(null, "");
@ -805,6 +756,7 @@ public class NodeItemTest {
}
@Test
@Category(IsNamedCategory.class)
public void isNamedNamed() {
//given
node = Nodes.namedRoot(null, "named");
@ -826,26 +778,6 @@ public class NodeItemTest {
assertThat(child.findParent()).isEmpty();
}
@Test
public void drawTreeIsCorrect() {
//given
node = Nodes.namedRoot(null, "root");
val bob = Nodes.namedChild("bob data", "bob", node);
val alice = Nodes.namedChild("alice data", "alice", node);
Nodes.namedChild("dave data", "dave", alice);
Nodes.unnamedChild("bob's child's data", bob); // has no name and no children so no included
val kim = Nodes.unnamedChild("kim data", node); // nameless mother
Nodes.namedChild("lucy data", "lucy", kim);
//when
val tree = node.drawTree(0);
//then
String[] lines = tree.split("\n");
assertThat(lines).contains("[root]", "[ alice]", "[ dave]", "[ (unnamed)]", "[ lucy]", "[ bob]");
assertThat(lines).containsSubsequence("[root]", "[ alice]", "[ dave]");
assertThat(lines).containsSubsequence("[root]", "[ (unnamed)]", "[ lucy]");
assertThat(lines).containsSubsequence("[root]", "[ bob]");
}
@Test
public void canChangeNodeData() {
//given
@ -853,7 +785,7 @@ public class NodeItemTest {
//when
node.setData("updated");
//then
assertThat(node.getData()).contains("updated");
assertThat(node.findData()).contains("updated");
}
@Test
@ -869,27 +801,6 @@ public class NodeItemTest {
assertThat(node.getChildren()).containsExactly(child);
}
@Test
public void canGetChildWhenFound() {
//given
node = Nodes.unnamedRoot("data");
val child = Nodes.namedChild("child data", "child name", node);
//when
val found = node.getChild("child data");
//then
assertThat(found).isSameAs(child);
}
@Test
public void canGetChildWhenNotFound() {
//given
exception.expect(NodeException.class);
exception.expectMessage("Child not found");
node = Nodes.unnamedRoot("data");
//when
node.getChild("child data");
}
@Test
@SuppressWarnings("unchecked")
public void constructorWithNameSupplierAndParentBeChildOfParent() {
@ -969,4 +880,17 @@ public class NodeItemTest {
assertThat(resultChild1).containsExactlyInAnyOrder(root);
assertThat(resultChild3).containsExactlyInAnyOrder(child2, root);
}
@Test
public void whenNodeItemChildrenAreNullThenAsNoChildren() {
//when
NodeItem<String> nodeItem = new NodeItem<>(
"data",
"name",
null,
null);
//then
assertThat(nodeItem.getChildren())
.isEmpty();
}
}

View file

@ -0,0 +1,30 @@
package net.kemitix.node;
import lombok.val;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class NodeTreeDrawTest {
@Test
public void drawTreeIsCorrect() {
//given
final Node<String> node = Nodes.namedRoot(null, "root");
val bob = Nodes.namedChild("bob data", "bob", node);
val alice = Nodes.namedChild("alice data", "alice", node);
Nodes.namedChild("dave data", "dave", alice);
Nodes.unnamedChild("bob's child's data", bob); // has no name and no children so no included
val kim = Nodes.unnamedChild("kim data", node); // nameless mother
Nodes.namedChild("lucy data", "lucy", kim);
//when
val tree = Nodes.drawTree(node, 0);
//then
String[] lines = tree.split("\n");
assertThat(lines).contains("[root]", "[ alice]", "[ dave]", "[ (unnamed)]", "[ lucy]", "[ bob]");
assertThat(lines).containsSubsequence("[root]", "[ alice]", "[ dave]");
assertThat(lines).containsSubsequence("[root]", "[ (unnamed)]", "[ lucy]");
assertThat(lines).containsSubsequence("[root]", "[ bob]");
}
}

View file

@ -23,7 +23,7 @@ public class NodesTest {
public void shouldCreateUnnamedRoot() throws Exception {
val node = Nodes.unnamedRoot("data");
SoftAssertions softly = new SoftAssertions();
softly.assertThat(node.getData()).contains("data");
softly.assertThat(node.findData()).contains("data");
softly.assertThat(node.getName()).isEmpty();
softly.assertAll();
}
@ -32,7 +32,7 @@ public class NodesTest {
public void shouldCreateNamedRoot() throws Exception {
val node = Nodes.namedRoot("data", "name");
SoftAssertions softly = new SoftAssertions();
softly.assertThat(node.getData()).contains("data");
softly.assertThat(node.findData()).contains("data");
softly.assertThat(node.getName()).isEqualTo("name");
softly.assertAll();
}
@ -42,7 +42,7 @@ public class NodesTest {
val parent = Nodes.unnamedRoot("root");
val node = Nodes.unnamedChild("data", parent);
SoftAssertions softly = new SoftAssertions();
softly.assertThat(node.getData()).contains("data");
softly.assertThat(node.findData()).contains("data");
softly.assertThat(node.getName()).isEmpty();
softly.assertThat(node.findParent()).contains(parent);
softly.assertAll();
@ -53,7 +53,7 @@ public class NodesTest {
val parent = Nodes.unnamedRoot("root");
val node = Nodes.namedChild("data", "child", parent);
SoftAssertions softly = new SoftAssertions();
softly.assertThat(node.getData()).contains("data");
softly.assertThat(node.findData()).contains("data");
softly.assertThat(node.getName()).isEqualTo("child");
softly.assertThat(node.findParent()).contains(parent);
softly.assertAll();