Skip to content

Commit

Permalink
Extract & test RecursiveTreeFilter
Browse files Browse the repository at this point in the history
  • Loading branch information
jj-sn authored and Agh42 committed Mar 20, 2020
1 parent 74a14a1 commit bd39272
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 50 deletions.
15 changes: 15 additions & 0 deletions sernet.gs.ui.rcp.main/RecursiveTreeFilterTest.launch
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/sernet.gs.ui.rcp.main/testSrc/sernet/verinice/bp/rcp/filter/RecursiveTreeFilterTest.java"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="sernet.verinice.bp.rcp.filter.RecursiveTreeFilterTest"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="sernet.gs.ui.rcp.main"/>
</launchConfiguration>
Original file line number Diff line number Diff line change
Expand Up @@ -316,54 +316,4 @@ private boolean scopeRequiresSecurityLevel(CnATreeElement element,
return true;
}
}

/**
* A viewer filter that can be used with tree structures. In order for an
* element to be selected (i.e. shown), the element itself or any descendant
* must match the delegate filter.
*/
private static class RecursiveTreeFilter extends ViewerFilter {

private final ViewerFilter delegateFilter;

RecursiveTreeFilter(ViewerFilter delegateFilter) {
this.delegateFilter = delegateFilter;
}

/**
* Override this method to specify whether an element's children are
* checked. For example, this can be used to abort the checks at a
* specific level of the tree.
*
* @param cnATreeElement
* the current element
* @return whether to check the elements of the given element
*/
protected boolean checkChildren(CnATreeElement cnATreeElement) {
return (cnATreeElement instanceof ItNetwork || cnATreeElement instanceof IBpGroup);
}

@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
CnATreeElement cnATreeElement = (CnATreeElement) element;
if (delegateFilter.select(viewer, parentElement, cnATreeElement)) {
return true;
}
if (checkChildren(cnATreeElement)) {
return containsMatchingChild(viewer, cnATreeElement);
}
return false;
}

private boolean containsMatchingChild(Viewer viewer, CnATreeElement cnATreeElement) {
ITreeContentProvider provider = (ITreeContentProvider) ((StructuredViewer) viewer)
.getContentProvider();
for (Object child : provider.getChildren(cnATreeElement)) {
if (select(viewer, cnATreeElement, child)) {
return true;
}
}
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*******************************************************************************
* Copyright (c) 2020 Jonas Jordan
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package sernet.verinice.bp.rcp.filter;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;

import sernet.verinice.model.bp.IBpGroup;
import sernet.verinice.model.bp.elements.ItNetwork;
import sernet.verinice.model.common.CnATreeElement;

/**
* A viewer filter that can be used with tree structures. In order for an
* element to be selected (i.e. shown), the element itself or any descendant
* must match the delegate filter.
*/
class RecursiveTreeFilter extends ViewerFilter {

private final ViewerFilter delegateFilter;

RecursiveTreeFilter(ViewerFilter delegateFilter) {
this.delegateFilter = delegateFilter;
}

/**
* Override this method to specify whether an element's children are
* checked. For example, this can be used to abort the checks at a specific
* level of the tree.
*
* @param cnATreeElement
* the current element
* @return whether to check the elements of the given element
*/
protected boolean checkChildren(CnATreeElement cnATreeElement) {
return (cnATreeElement instanceof ItNetwork || cnATreeElement instanceof IBpGroup);
}

@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
CnATreeElement cnATreeElement = (CnATreeElement) element;
if (delegateFilter.select(viewer, parentElement, cnATreeElement)) {
return true;
}
if (checkChildren(cnATreeElement)) {
return containsMatchingChild(viewer, cnATreeElement);
}
return false;
}

private boolean containsMatchingChild(Viewer viewer, CnATreeElement cnATreeElement) {
ITreeContentProvider provider = (ITreeContentProvider) ((StructuredViewer) viewer)
.getContentProvider();
for (Object child : provider.getChildren(cnATreeElement)) {
if (select(viewer, cnATreeElement, child)) {
return true;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/*******************************************************************************
* Copyright (c) 2020 Jonas Jordan
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package sernet.verinice.bp.rcp.filter;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.junit.Assert;
import org.junit.Test;

import sernet.verinice.model.bp.elements.BpRequirement;
import sernet.verinice.model.bp.groups.BpRequirementGroup;

/**
* Test the {@Link RecursiveTreeFilter}.
*/
public class RecursiveTreeFilterTest {

@Test
public void positiveRoot() {
ViewerFilter delegateFilterMock = mock(ViewerFilter.class);
Viewer viewerMock = mock(Viewer.class);

Object parentMock = mock(Object.class);

BpRequirementGroup elementMock = mock(BpRequirementGroup.class);
when(delegateFilterMock.select(viewerMock, parentMock, elementMock)).thenReturn(true);

RecursiveTreeFilter sut = new RecursiveTreeFilter(delegateFilterMock);

Assert.assertTrue(sut.select(viewerMock, parentMock, elementMock));
verify(delegateFilterMock, times(1)).select(viewerMock, parentMock, elementMock);
}

@Test
public void negativeRootNoChildren() {
ViewerFilter delegateFilterMock = mock(ViewerFilter.class);
StructuredViewer viewerMock = mock(StructuredViewer.class);
ITreeContentProvider treeContentProviderMock = mock(ITreeContentProvider.class);
when(viewerMock.getContentProvider()).thenReturn(treeContentProviderMock);

Object parentMock = mock(Object.class);

BpRequirementGroup rootMock = mock(BpRequirementGroup.class);
when(delegateFilterMock.select(viewerMock, parentMock, rootMock)).thenReturn(false);
when(treeContentProviderMock.getChildren(rootMock)).thenReturn(new Object[0]);

RecursiveTreeFilter sut = new RecursiveTreeFilter(delegateFilterMock);

Assert.assertFalse(sut.select(viewerMock, parentMock, rootMock));
verify(delegateFilterMock, times(1)).select(viewerMock, parentMock, rootMock);
}

@Test
public void negativeRootPositiveChild() {
ViewerFilter delegateFilterMock = mock(ViewerFilter.class);
ITreeContentProvider treeContentProviderMock = mock(ITreeContentProvider.class);

StructuredViewer viewerMock = mock(StructuredViewer.class);
when(viewerMock.getContentProvider()).thenReturn(treeContentProviderMock);

Object parentMock = mock(Object.class);

BpRequirementGroup rootMock = mock(BpRequirementGroup.class);
when(delegateFilterMock.select(viewerMock, parentMock, rootMock)).thenReturn(false);

BpRequirement negativeChild = mock(BpRequirement.class);
when(delegateFilterMock.select(viewerMock, rootMock, negativeChild)).thenReturn(true);

BpRequirement positiveChild = mock(BpRequirement.class);
when(delegateFilterMock.select(viewerMock, rootMock, positiveChild)).thenReturn(true);

when(treeContentProviderMock.getChildren(rootMock))
.thenReturn(new Object[] { negativeChild, positiveChild });

RecursiveTreeFilter sut = new RecursiveTreeFilter(delegateFilterMock);

Assert.assertTrue(sut.select(viewerMock, parentMock, rootMock));
verify(delegateFilterMock, times(1)).select(viewerMock, parentMock, rootMock);
verify(delegateFilterMock, times(1)).select(viewerMock, rootMock, negativeChild);
}

@Test
public void negativeRootNegativeChildren() {
ViewerFilter delegateFilterMock = mock(ViewerFilter.class);
ITreeContentProvider treeContentProviderMock = mock(ITreeContentProvider.class);

StructuredViewer viewerMock = mock(StructuredViewer.class);
when(viewerMock.getContentProvider()).thenReturn(treeContentProviderMock);

Object parentMock = mock(Object.class);

BpRequirementGroup rootMock = mock(BpRequirementGroup.class);
when(delegateFilterMock.select(viewerMock, parentMock, rootMock)).thenReturn(false);

BpRequirement negativeChild1 = mock(BpRequirement.class);
when(delegateFilterMock.select(viewerMock, rootMock, negativeChild1)).thenReturn(false);

BpRequirement negativeChild2 = mock(BpRequirement.class);
when(delegateFilterMock.select(viewerMock, rootMock, negativeChild2)).thenReturn(false);

when(treeContentProviderMock.getChildren(rootMock))
.thenReturn(new Object[] { negativeChild1, negativeChild2 });

RecursiveTreeFilter sut = new RecursiveTreeFilter(delegateFilterMock);

Assert.assertFalse(sut.select(viewerMock, parentMock, rootMock));
verify(delegateFilterMock, times(1)).select(viewerMock, parentMock, rootMock);
}

@Test
public void negativeRootPositveGrandChild() {
ViewerFilter delegateFilterMock = mock(ViewerFilter.class);
ITreeContentProvider treeContentProviderMock = mock(ITreeContentProvider.class);

StructuredViewer viewerMock = mock(StructuredViewer.class);
when(viewerMock.getContentProvider()).thenReturn(treeContentProviderMock);

Object parentMock = mock(Object.class);

BpRequirementGroup rootMock = mock(BpRequirementGroup.class);
when(delegateFilterMock.select(viewerMock, null, rootMock)).thenReturn(false);

BpRequirementGroup negativeChild = mock(BpRequirementGroup.class);
when(delegateFilterMock.select(viewerMock, rootMock, negativeChild)).thenReturn(false);

BpRequirement positiveGrandChild = mock(BpRequirement.class);
when(delegateFilterMock.select(viewerMock, negativeChild, positiveGrandChild))
.thenReturn(true);

when(treeContentProviderMock.getChildren(rootMock))
.thenReturn(new Object[] { negativeChild });

when(treeContentProviderMock.getChildren(negativeChild))
.thenReturn(new Object[] { positiveGrandChild });

RecursiveTreeFilter sut = new RecursiveTreeFilter(delegateFilterMock);

Assert.assertTrue(sut.select(viewerMock, parentMock, rootMock));
verify(delegateFilterMock, times(1)).select(viewerMock, parentMock, rootMock);
verify(delegateFilterMock, times(1)).select(viewerMock, rootMock, negativeChild);
}

@Test
public void negativeRootNegativeDescendants() {
ViewerFilter delegateFilterMock = mock(ViewerFilter.class);
ITreeContentProvider treeContentProviderMock = mock(ITreeContentProvider.class);

StructuredViewer viewerMock = mock(StructuredViewer.class);
when(viewerMock.getContentProvider()).thenReturn(treeContentProviderMock);

Object parentMock = mock(Object.class);

BpRequirementGroup rootMock = mock(BpRequirementGroup.class);
when(delegateFilterMock.select(viewerMock, null, rootMock)).thenReturn(false);

BpRequirementGroup negativeChild = mock(BpRequirementGroup.class);
when(delegateFilterMock.select(viewerMock, rootMock, negativeChild)).thenReturn(false);

BpRequirement negativeGrandChild = mock(BpRequirement.class);
when(delegateFilterMock.select(viewerMock, negativeChild, negativeGrandChild))
.thenReturn(false);

when(treeContentProviderMock.getChildren(rootMock))
.thenReturn(new Object[] { negativeChild });

when(treeContentProviderMock.getChildren(negativeChild))
.thenReturn(new Object[] { negativeGrandChild });

RecursiveTreeFilter sut = new RecursiveTreeFilter(delegateFilterMock);

Assert.assertFalse(sut.select(viewerMock, parentMock, rootMock));
verify(delegateFilterMock, times(1)).select(viewerMock, parentMock, rootMock);
verify(delegateFilterMock, times(1)).select(viewerMock, rootMock, negativeChild);
verify(delegateFilterMock, times(1)).select(viewerMock, negativeChild, negativeGrandChild);
}
}

0 comments on commit bd39272

Please sign in to comment.