Skip to content

Commit

Permalink
Node.replaceIf
Browse files Browse the repository at this point in the history
- Closes #708
- Node.replaceIf(Predicate, Node)
  • Loading branch information
mP1 committed Dec 21, 2023
1 parent dffed97 commit 7fce410
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 3 deletions.
26 changes: 26 additions & 0 deletions src/main/java/walkingkooka/tree/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
* A node is part of a tree holding branches and leaves all of which are nodes.
Expand Down Expand Up @@ -135,6 +138,29 @@ default N setChild(final NAME name, final N child) {
.orElse(this.appendChild(child));
}

/**
* Conditionally replaces any nodes that a matched by the {@link Predicate} and then mapped by the {@link Function mapper}.
*/
default N replaceIf(final Predicate<N> predicate,
final Function<N, N> mapper) {
Objects.requireNonNull(predicate, "predicate");
Objects.requireNonNull(mapper, "mapper");

N result = (N) this;
if (predicate.test(result)) {
result = mapper.apply(result);
} else {
result = result.setChildren(
this.children()
.stream()
.map(n -> n.replaceIf(predicate, mapper))
.collect(Collectors.toList())
);
}

return result;
}

/**
* Appends a new child.
*/
Expand Down
70 changes: 70 additions & 0 deletions src/main/java/walkingkooka/tree/NodeTesting.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.junit.jupiter.api.Test;
import walkingkooka.collect.list.Lists;
import walkingkooka.naming.Name;
import walkingkooka.predicate.Predicates;
import walkingkooka.reflect.MethodAttributes;
import walkingkooka.tree.select.NodeSelector;
import walkingkooka.tree.select.NodeSelectorTesting;
Expand All @@ -30,6 +31,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;

import static org.junit.jupiter.api.Assertions.assertNotSame;
Expand Down Expand Up @@ -171,6 +173,58 @@ default void testSetChildNodeNullNodeFails() {
);
}

// replaceIf........................................................................................................

@Test
default void testReplaceIfNullPredicateFails() {
final N node = this.createNode();

assertThrows(
NullPointerException.class,
() -> node.replaceIf(
null,
Function.identity() // mapper
)
);
}

@Test
default void testReplaceIfNullMapperFails() {
final N node = this.createNode();

assertThrows(
NullPointerException.class,
() -> node.replaceIf(
Predicates.fake(),
null // mapper
)
);
}

@Test
default void tetReplaceIfNeverPredicate() {
final N node = this.createNode();
assertSame(
node,
node.replaceIf(
Predicates.never(),
Function.identity()
)
);
}

@Test
default void tetReplaceIfIdentityMapper() {
final N node = this.createNode();
assertSame(
node,
node.replaceIf(
Predicates.always(),
Function.identity()
)
);
}

@Test
default void testPropertiesNeverReturnNull() throws Exception {
this.allPropertiesNeverReturnNullCheck(this.createNode(),
Expand Down Expand Up @@ -232,6 +286,22 @@ default void replaceAndCheck(final N node, final N replaceWith, final N result)
this.checkEquals(result.pointer(), node.pointer(), () -> "pointer for\n" + node + "\n" + result);
}

// replaceIf........................................................................................................

default void replaceIfAndCheck(final N node,
final Predicate<N> predicate,
final Function<N, N> mapper,
final N result) {
this.checkEquals(
result,
node.replaceIf(
predicate,
mapper
),
() -> node + " replaceIf " + predicate + " " + mapper
);
}

// appendChild......................................................................................................

default N appendChildAndCheck(final N parent, final N child) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ public final List<Expression> children() {
@Override
public final Expression setChildren(final List<Expression> children) {
Objects.requireNonNull(children, "children");
throw new UnsupportedOperationException();

if(false == children.isEmpty()) {
throw new UnsupportedOperationException();
}

return this;
}

@Override final Expression setChild(final Expression newChild) {
Expand Down
174 changes: 172 additions & 2 deletions src/test/java/walkingkooka/tree/expression/ExpressionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,172 @@
package walkingkooka.tree.expression;

import org.junit.jupiter.api.Test;
import walkingkooka.reflect.ClassTesting2;
import walkingkooka.naming.Name;
import walkingkooka.reflect.ClassTesting;
import walkingkooka.reflect.JavaVisibility;
import walkingkooka.text.Indentation;
import walkingkooka.text.LineEnding;
import walkingkooka.text.printer.IndentingPrinter;
import walkingkooka.text.printer.Printers;
import walkingkooka.tree.NodeTesting;

public final class ExpressionTest implements ClassTesting2<Expression> {
public final class ExpressionTest implements NodeTesting<Expression, FunctionExpressionName, Name, Object>,
ClassTesting<Expression> {

@Override
public void testParentWithoutChild() {
// nop
}

@Override
public void testSetSameAttributes() {
// nop
}

@Override
public void testTypeNaming() {
// nop
}

// replaceIf........................................................................................................

@Test
public void testReplaceIfChild() {
final Expression left = Expression.value(123);
final Expression right = Expression.value(456);

final Expression expression = Expression.add(
left,
right
);

final Expression replacement = Expression.value(789);

this.replaceIfAndCheck(
expression,
(e) -> e.equals(left),
(e) -> replacement,
Expression.add(
replacement,
right
)
);
}

@Test
public void testReplaceIfChild2() {
final Expression left = Expression.value(123);
final Expression right = Expression.value(456);

final Expression expression = Expression.add(
left,
right
);

final Expression replacement = Expression.value(789);

this.replaceIfAndCheck(
expression,
(e) -> e.equals(right),
(e) -> replacement,
Expression.add(
left,
replacement
)
);
}

@Test
public void testReplaceIfBothChildren() {
final Expression left = Expression.value(111);
final Expression right = Expression.value(222);

final Expression expression = Expression.add(
left,
right
);

final Expression replacement1 = Expression.value(333);
final Expression replacement2 = Expression.value(444);

this.replaceIfAndCheck(
expression,
(e) -> e.equals(left) || e.equals(right),
(e) -> e.equals(left) ?
replacement1 :
e.equals(right) ? replacement2 :
e,
Expression.add(
replacement1,
replacement2
)
);
}

@Test
public void testReplaceIfGrandChild() {
final Expression child1 = Expression.value(111);
final Expression grandChild1 = Expression.value(222);
final Expression grandChild2 = Expression.value(333);

final Expression root = Expression.add(
child1,
Expression.add(
grandChild1,
grandChild2
)
);

final Expression replacement = Expression.value(444);

this.replaceIfAndCheck(
root,
(e) -> e.equals(grandChild2),
(e) -> replacement,
Expression.add(
child1,
Expression.add(
grandChild1,
replacement
)
)
);
}

@Test
public void testReplaceIfChildAndGrandChild() {
final Expression child1 = Expression.value(111);
final Expression grandChild1 = Expression.value(222);
final Expression grandChild2 = Expression.value(333);

final Expression root = Expression.add(
child1,
Expression.add(
grandChild1,
grandChild2
)
);

final Expression replacement1 = Expression.value(444);
final Expression replacement2 = Expression.value(555);

this.replaceIfAndCheck(
root,
(e) -> e.equals(child1) || e.equals(grandChild2),
(e) -> e.equals(child1) ?
replacement1 :
e.equals(grandChild2) ?
replacement2 :
e,
Expression.add(
replacement1,
Expression.add(
grandChild1,
replacement2
)
)
);
}

// TreePrinting......................................................................................................

Expand Down Expand Up @@ -68,4 +226,16 @@ public Class<Expression> type() {
public JavaVisibility typeVisibility() {
return JavaVisibility.PUBLIC;
}

// NodeTesting......................................................................................................

@Override
public Expression createNode() {
return Expression.value(123);
}

@Override
public String typeNamePrefix() {
return "";
}
}

0 comments on commit 7fce410

Please sign in to comment.