-
Notifications
You must be signed in to change notification settings - Fork 177
added category resolution on compare #159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
1d15505
7b8b206
ac8a359
8cf1557
316602f
4f03e4a
b459cf7
b8c3267
1944cae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package de.danielbechler.diff | ||
|
||
import de.danielbechler.diff.introspection.ObjectDiffProperty | ||
import de.danielbechler.diff.node.DiffNode | ||
import de.danielbechler.diff.node.Visit | ||
import de.danielbechler.diff.path.NodePath | ||
import spock.lang.Specification | ||
|
||
class CategoriesTestIT extends Specification{ | ||
|
||
def obj1 = new MyObject("aaa","aaa", "aaa") | ||
def obj2 = new MyObject("bbb","bbb", "bbb") | ||
def differ = ObjectDifferBuilder.startBuilding() | ||
.categories() | ||
.ofNode(NodePath.with("firstString")).toBe("cat1") | ||
.ofNode(NodePath.with("secondString")).toBe("cat1") | ||
.ofNode(NodePath.with("thirdString")).toBe("cat1") | ||
.and() | ||
.build() | ||
|
||
def node = differ.compare(obj1,obj2) | ||
|
||
def categoriesMapVisitor = new DiffNode.Visitor() { | ||
|
||
Map<String, Set<String>> mapCategories = new HashMap<>(); | ||
|
||
@Override | ||
void node(DiffNode node, Visit visit) { | ||
|
||
mapCategories.put(node.getPropertyName(), node.getCategories()) | ||
} | ||
} | ||
|
||
def categoriesAdderVisitor = new DiffNode.Visitor() { | ||
|
||
@Override | ||
void node(DiffNode node, Visit visit) { | ||
|
||
node.addCategories(Arrays.asList("addedWhileVisiting")) | ||
} | ||
} | ||
|
||
def "should return all categories"(){ | ||
given: | ||
node.visitChildren(categoriesMapVisitor) | ||
expect : | ||
categoriesMapVisitor.mapCategories.get("firstString") == ["cat1"] as Set | ||
categoriesMapVisitor.mapCategories.get("secondString") == ["cat1"] as Set | ||
categoriesMapVisitor.mapCategories.get("thirdString") == ["cat1", "catAnnotation"] as Set | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about doing this instead of using the mapVisitor? node.getChild("firstString").getCategories() == ["cat1"] as Set
... Or was there a specific reason for the visitor approach? |
||
|
||
def "should return categories added when visiting"(){ | ||
given: | ||
node.visitChildren(categoriesAdderVisitor) | ||
node.visitChildren(categoriesMapVisitor) | ||
expect : | ||
categoriesMapVisitor.mapCategories.get("firstString") == ["cat1", "addedWhileVisiting"] as Set | ||
categoriesMapVisitor.mapCategories.get("secondString") == ["cat1", "addedWhileVisiting"] as Set | ||
categoriesMapVisitor.mapCategories.get("thirdString") == ["cat1", "catAnnotation", "addedWhileVisiting"] as Set | ||
} | ||
|
||
def "categories should not be modifiable by a client directly"(){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this one would be better off as a simple unit test in |
||
|
||
when: | ||
node.visitChildren(new DiffNode.Visitor() { | ||
|
||
@Override | ||
void node(DiffNode node, Visit visit) { | ||
|
||
def cats = node.getCategories() | ||
cats.removeAll() | ||
} | ||
}) | ||
|
||
then : | ||
thrown UnsupportedOperationException | ||
} | ||
|
||
def "should throw exception when added a null collection"(){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here: better off as a unit test. |
||
|
||
when: | ||
node.visitChildren(new DiffNode.Visitor() { | ||
@Override | ||
void node(DiffNode node, Visit visit) { | ||
|
||
node.addCategories(null) | ||
} | ||
}) | ||
|
||
then : | ||
def ex = thrown(IllegalArgumentException) | ||
ex.message == "'additionalCategories' must not be null" | ||
} | ||
|
||
class MyObject{ | ||
|
||
def firstString | ||
def secondString | ||
def thirdString | ||
|
||
MyObject(firstString,secondString,thirdString) { | ||
|
||
this.firstString = firstString | ||
this.secondString = secondString | ||
this.thirdString = thirdString | ||
} | ||
|
||
def getFirstString() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By the way: these getters and setters are automatically generated by Groovy. The only ones you actually need are those for the thirdString due to the annotation. |
||
return firstString | ||
} | ||
|
||
void setFirstString(firstString) { | ||
this.firstString = firstString | ||
} | ||
|
||
def getSecondString() { | ||
return secondString | ||
} | ||
|
||
void setSecondString(secondString) { | ||
this.secondString = secondString | ||
} | ||
|
||
@ObjectDiffProperty(categories = ["catAnnotation"]) | ||
def getThirdString() { | ||
return thirdString | ||
} | ||
|
||
void setThirdString(thirdString) { | ||
this.thirdString = thirdString | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
|
||
import java.util.Collection; | ||
import java.util.LinkedList; | ||
import java.util.Set; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this file doesn't contain any actual changes anymore, could you please bring it back into its original condition, so it doesn't show up in the diff? |
||
|
||
import static de.danielbechler.diff.inclusion.Inclusion.DEFAULT; | ||
import static de.danielbechler.diff.inclusion.Inclusion.EXCLUDED; | ||
|
@@ -279,4 +280,5 @@ public ObjectDifferBuilder and() | |
{ | ||
return rootConfiguration; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,12 +32,7 @@ | |
import de.danielbechler.util.Assert; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.util.Collections; | ||
import java.util.LinkedHashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.TreeSet; | ||
import java.util.*; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer explicit imports here. |
||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
import static java.util.Collections.unmodifiableSet; | ||
|
@@ -67,6 +62,7 @@ public class DiffNode | |
private Class<?> valueType; | ||
private TypeInfo valueTypeInfo; | ||
private IdentityStrategy childIdentityStrategy; | ||
private final Set<String> additionalCategories = new TreeSet<String>(); | ||
|
||
public void setChildIdentityStrategy(final IdentityStrategy identityStrategy) | ||
{ | ||
|
@@ -573,7 +569,10 @@ public boolean isExcluded() | |
return false; | ||
} | ||
|
||
// TODO These categories should also contain the ones configured via CategoryService | ||
/** | ||
* Returns a {@link java.util.Set} of {@link java.lang.String} | ||
* @return | ||
*/ | ||
public final Set<String> getCategories() | ||
{ | ||
final Set<String> categories = new TreeSet<String>(); | ||
|
@@ -589,7 +588,9 @@ public final Set<String> getCategories() | |
categories.addAll(categoriesFromAccessor); | ||
} | ||
} | ||
return categories; | ||
categories.addAll(additionalCategories); | ||
|
||
return Collections.unmodifiableSet(categories); | ||
} | ||
|
||
/** | ||
|
@@ -732,6 +733,12 @@ else if (childCount() > 1) | |
return sb.toString(); | ||
} | ||
|
||
public void addCategories(final Collection<String> additionalCategories) | ||
{ | ||
Assert.notNull(additionalCategories, "additionalCategories"); | ||
this.additionalCategories.addAll(additionalCategories); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately there is no way to avoid making this method part of the public API, so people will eventually start (ab)using it. That's one of the reasons why I'd prefer a different name for the field, as mentioned above. Although I wouldn't even expose the field via getter or setter at all. If we can't avoid leaking this detail to the outside, let's make it a cool feature: let's say we call the method Calling it I imagine something like this: public final void addCategories(final Collection<String> additionalCategories)
{
Assert.notNull(additionalCategories, "additionalCategories");
this.additionalCategories.addAll(additionalCategories);
} In this example I changed the parameter type from |
||
|
||
/** | ||
* @return Returns the path to the first node in the hierarchy that represents the same object instance as | ||
* this one. (Only if {@link #isCircular()} returns <code>true</code>. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this to a new package
categories
, since all the other major configuration sections got their own one as well.