Author: hlship
Date: Mon May 31 17:34:54 2010
New Revision: 949814
URL: http://svn.apache.org/viewvc?rev=949814&view=rev
Log:
Fill in some edge cases and get code coverage to 100%
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java?rev=949814&r1=949813&r2=949814&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/AbstractFlow.java
Mon May 31 17:34:54 2010
@@ -43,12 +43,9 @@ abstract class AbstractFlow<T> implement
{
List<T> result = new ArrayList<T>();
- Flow<T> current = flow;
-
- while (!current.isEmpty())
+ for (T value : flow)
{
- result.add(current.first());
- current = current.rest();
+ result.add(value);
}
return result;
@@ -102,11 +99,11 @@ abstract class AbstractFlow<T> implement
/** Subclasses may override this for efficiency. */
public Flow<T> each(Worker<? super T> worker)
{
- Flow<T> cursor = this;
- while (!cursor.isEmpty())
+ Defense.notNull(worker, "worker");
+
+ for (T value : this)
{
- worker.work(cursor.first());
- cursor = cursor.rest();
+ worker.work(value);
}
return this;
@@ -152,16 +149,25 @@ abstract class AbstractFlow<T> implement
public Flow<T> reverse()
{
+ if (isEmpty())
+ return F.emptyFlow();
+
return new ArrayFlow<T>(this).reverse();
}
public Flow<T> sort()
{
+ if (isEmpty())
+ return F.emptyFlow();
+
return new ArrayFlow<T>(this).sort();
}
public Flow<T> sort(Comparator<? super T> comparator)
{
+ if (isEmpty())
+ return F.emptyFlow();
+
return new ArrayFlow<T>(this).sort(comparator);
}
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java?rev=949814&r1=949813&r2=949814&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/F.java
Mon May 31 17:34:54 2010
@@ -24,7 +24,8 @@ import java.util.Collection;
*/
public class F
{
- private final static Flow<?> EMPTY_FLOW = new EmptyFlow();
+ @SuppressWarnings("unchecked")
+ final static Flow<?> EMPTY_FLOW = new EmptyFlow();
@SuppressWarnings("unchecked")
static <T> Flow<T> emptyFlow()
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java?rev=949814&r1=949813&r2=949814&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/func/MappedFlow.java
Mon May 31 17:34:54 2010
@@ -35,6 +35,9 @@ class MappedFlow<T, X> extends AbstractF
// Guarded by this
private Flow<X> rest;
+ // Guarded by this
+ private boolean empty;
+
public MappedFlow(Mapper<T, X> mapper, Flow<T> mappedFlow)
{
this.mapper = mapper;
@@ -48,9 +51,11 @@ class MappedFlow<T, X> extends AbstractF
return first;
}
- public boolean isEmpty()
+ public synchronized boolean isEmpty()
{
- return false;
+ resolve();
+
+ return empty;
}
public synchronized Flow<X> rest()
@@ -65,16 +70,17 @@ class MappedFlow<T, X> extends AbstractF
if (resolved)
return;
- // The mappedFlow should never be empty
-
- first = mapper.map(mappedFlow.first());
-
- Flow<T> mappedRest = mappedFlow.rest();
-
- if (mappedRest.isEmpty())
+ if (mappedFlow.isEmpty())
+ {
+ empty = true;
rest = F.emptyFlow();
+ }
else
- rest = new MappedFlow<T, X>(mapper, mappedRest);
+ {
+ first = mapper.map(mappedFlow.first());
+
+ rest = new MappedFlow<T, X>(mapper, mappedFlow.rest());
+ }
mappedFlow = null;
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java?rev=949814&r1=949813&r2=949814&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/func/FuncTest.java
Mon May 31 17:34:54 2010
@@ -17,6 +17,7 @@ package org.apache.tapestry5.func;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
@@ -26,6 +27,7 @@ import org.testng.annotations.Test;
public class FuncTest extends TestUtils
{
+
private Mapper<String, Integer> stringToLength = new Mapper<String,
Integer>()
{
public Integer map(String input)
@@ -50,6 +52,8 @@ public class FuncTest extends TestUtils
};
};
+ private Flow<Integer> filteredEmpty = F.flow(1, 3, 5, 7).filter(evenp);
+
@Test
public void map()
{
@@ -116,6 +120,35 @@ public class FuncTest extends TestUtils
}
@Test
+ public void each_on_non_array_flow()
+ {
+ List<String> source = Arrays.asList("Mary", "had", "a", "little",
"lamb");
+
+ final StringBuffer buffer = new StringBuffer();
+
+ Worker<String> worker = new Worker<String>()
+ {
+ public void work(String value)
+ {
+ if (buffer.length() > 0)
+ buffer.append(" ");
+
+ buffer.append(value);
+ }
+ };
+
+ F.flow(source).filter(new Predicate<String>()
+ {
+ public boolean accept(String object)
+ {
+ return object.contains("a");
+ }
+ }).each(worker);
+
+ assertEquals(buffer.toString(), "Mary had a lamb");
+ }
+
+ @Test
public void flow_each()
{
Flow<String> flow = F.flow("Mary", "had", "a", "little", "lamb");
@@ -431,4 +464,128 @@ public class FuncTest extends TestUtils
{
assertTrue(F.flow().rest().isEmpty());
}
+
+ @Test
+ public void list_of_empty_flow_is_empty()
+ {
+ assertTrue(filteredEmpty.isEmpty());
+ assertSame(filteredEmpty.toList(), Collections.EMPTY_LIST);
+ }
+
+ @Test
+ public void operations_on_empty_list_yield_empty()
+ {
+ assertSame(filteredEmpty.reverse(), F.EMPTY_FLOW);
+ assertSame(filteredEmpty.sort(), F.EMPTY_FLOW);
+ assertSame(filteredEmpty.sort(new Comparator<Integer>()
+ {
+ public int compare(Integer o1, Integer o2)
+ {
+ unreachable();
+
+ return 0;
+ }
+ }), F.EMPTY_FLOW);
+ }
+
+ @Test
+ public void sort_non_array_flow()
+ {
+ assertListsEquals(filteredEmpty.append(7, 3, 9).sort().toList(), 3, 7,
9);
+ }
+
+ @Test
+ public void reverse_non_array_flow()
+ {
+ assertListsEquals(filteredEmpty.append(1, 2, 3).reverse().toList(), 3,
2, 1);
+ }
+
+ @Test(expectedExceptions = UnsupportedOperationException.class)
+ public void remove_on_flow_iterator_is_not_supported()
+ {
+ Flow<Integer> flow = F.flow(1, 2, 3).filter(evenp);
+
+ Iterator<Integer> it = flow.iterator();
+
+ assertTrue(it.hasNext());
+ assertEquals(it.next(), new Integer(2));
+
+ it.remove();
+ }
+
+ @Test
+ public void sort_with_comparator_on_non_array_flow()
+ {
+ Flow<String> flow = F.flow("Mary", "had", "a", "little", "lamb");
+
+ List<String> result = flow.filter(new Predicate<String>()
+ {
+ public boolean accept(String object)
+ {
+ return object.contains("a");
+ }
+ }).sort(new Comparator<String>()
+ {
+ public int compare(String o1, String o2)
+ {
+ return o1.length() - o2.length();
+
+ };
+ }).toList();
+
+ assertListsEquals(result, "a", "had", "Mary", "lamb");
+ }
+
+ @Test
+ public void map_of_filtered_empty_is_empty()
+ {
+ assertTrue(filteredEmpty.map(new Mapper<Integer, Integer>()
+ {
+ public Integer map(Integer value)
+ {
+ unreachable();
+
+ return value;
+ }
+ }).isEmpty());
+ }
+
+ @Test
+ public void each_on_empty_flow()
+ {
+ Flow<Integer> flow = F.emptyFlow();
+
+ assertSame(flow.each(new Worker<Integer>()
+ {
+ public void work(Integer value)
+ {
+ unreachable();
+ }
+ }), flow);
+ }
+
+ @Test
+ public void remove_on_empty_flow()
+ {
+ Flow<Integer> flow = F.emptyFlow();
+
+ assertSame(flow.remove(evenp), flow);
+ }
+
+ @Test
+ public void reduce_on_empty_flow()
+ {
+ Flow<Integer> flow = F.emptyFlow();
+ Integer initial = 99;
+
+ assertSame(flow.reduce(new Reducer<Integer, Integer>()
+ {
+ public Integer reduce(Integer accumulator, Integer value)
+ {
+ unreachable();
+
+ return null;
+ }
+ }, initial), initial);
+ }
}