Skip to content

Commit

Permalink
Add VirtualTreeGroup
Browse files Browse the repository at this point in the history
  • Loading branch information
kamil-sita committed Jun 14, 2024
1 parent bb03a10 commit 0fbb014
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 0 deletions.
19 changes: 19 additions & 0 deletions module-fx/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,25 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.11.1</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package place.sita.modulefx;

public class BadApiUsageException extends RuntimeException {

public BadApiUsageException() {
}

public BadApiUsageException(String message) {
super(message);
}

public BadApiUsageException(String message, Throwable cause) {
super(message, cause);
}

public BadApiUsageException(Throwable cause) {
super(cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package place.sita.modulefx.vtg;

public interface MessageListener {

void receive(Object message);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package place.sita.modulefx.vtg;

import place.sita.modulefx.BadApiUsageException;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class VirtualTreeGroup {

private final UUID id = UUID.randomUUID();
private VirtualTreeGroup parent;
private final List<VirtualTreeGroup> children = new ArrayList<>();
private final List<VirtualTreeGroupElement> group = new ArrayList<>();

public UUID id() {
return id;
}

public void addChild(VirtualTreeGroup node) {
if (node.parent != null) {
throw new BadApiUsageException("Node already has a parent");
}
node.parent = this;
children.add(node);
}

public void removeChild(UUID id) {
VirtualTreeGroup child = children.stream().filter(n -> n.id().equals(id)).findFirst().orElse(null);

if (child == null) {
throw new BadApiUsageException("Not a child of this group");
}

child.parent = null;
children.remove(child);
}

/**
* Passes message to all other connected nodes
*/
public void message(UUID senderId, Object message) {
for (VirtualTreeGroupElement element : group) {
if (element.getId().equals(senderId)) {
continue;
}
element.receive(message);
}

if (parent != null && !parent.id().equals(senderId)) {
parent.message(id, message);
}

for (VirtualTreeGroup child : children) {
if (!child.id().equals(senderId)) {
child.message(id, message);
}
}
}

public void addElement(VirtualTreeGroupElement element) {
group.add(element);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package place.sita.modulefx.vtg;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class VirtualTreeGroupElement {

private final UUID id = UUID.randomUUID();
private final List<MessageListener> listeners = new ArrayList<>();

public UUID getId() {
return id;
}

public void addListener(MessageListener listener) {
listeners.add(listener);
}

public void receive(Object message) {
for (MessageListener listener : listeners) {
listener.receive(message);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package place.sita.modulefx.vtg;

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import place.sita.modulefx.BadApiUsageException;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyString;

public class VirtualTreeGroupTest {

@Test
public void shouldReportAddingChildTwice() {
// given
VirtualTreeGroup group = new VirtualTreeGroup();
VirtualTreeGroup child = new VirtualTreeGroup();
group.addChild(child);

// when
assertThatThrownBy(() -> group.addChild(child))
// then
.isInstanceOf(BadApiUsageException.class)
.hasMessage("Node already has a parent");
}

@Test
public void shouldPassMessageToChildrenParentAndOtherElementsButNotSelf() {
// given
VirtualTreeGroup groupWithSelf = new VirtualTreeGroup();
VirtualTreeGroup parent = new VirtualTreeGroup();
VirtualTreeGroup child = new VirtualTreeGroup();
parent.addChild(groupWithSelf);
groupWithSelf.addChild(child);

MessageListener listenerInParent = Mockito.mock(MessageListener.class);
MessageListener otherListenerInMiddle = Mockito.mock(MessageListener.class);
MessageListener selfListenerInMiddle = Mockito.mock(MessageListener.class);
MessageListener listenerInChild = Mockito.mock(MessageListener.class);

VirtualTreeGroupElement parentElement = new VirtualTreeGroupElement();
parentElement.addListener(listenerInParent);
parent.addElement(parentElement);

VirtualTreeGroupElement otherElementInMiddle = new VirtualTreeGroupElement();
otherElementInMiddle.addListener(otherListenerInMiddle);
groupWithSelf.addElement(otherElementInMiddle);

VirtualTreeGroupElement selfElementInMiddle = new VirtualTreeGroupElement();
selfElementInMiddle.addListener(selfListenerInMiddle);
groupWithSelf.addElement(selfElementInMiddle);

VirtualTreeGroupElement childElement = new VirtualTreeGroupElement();
childElement.addListener(listenerInChild);
child.addElement(childElement);

// when
groupWithSelf.message(selfElementInMiddle.getId(), "message");

// then
Mockito.verify(listenerInParent).receive("message");
Mockito.verify(otherListenerInMiddle).receive("message");
Mockito.verify(selfListenerInMiddle, Mockito.never()).receive(anyString());
Mockito.verify(listenerInChild).receive("message");
}

@Test
public void shouldNotMessageRemovedChild() {
// given
VirtualTreeGroup group = new VirtualTreeGroup();
VirtualTreeGroup child = new VirtualTreeGroup();
group.addChild(child);

MessageListener listener = Mockito.mock(MessageListener.class);
VirtualTreeGroupElement element = new VirtualTreeGroupElement();
element.addListener(listener);
child.addElement(element);

// when
group.removeChild(child.id());
group.message(element.getId(), "message");

// then
Mockito.verify(listener, Mockito.never()).receive("message");
}

}

0 comments on commit 0fbb014

Please sign in to comment.