]> source.dussan.org Git - sonarqube.git/commitdiff
Add support of Multisets in KeyValueFormat
authorsimonbrandhof <simon.brandhof@gmail.com>
Fri, 25 Feb 2011 06:57:59 +0000 (07:57 +0100)
committersimonbrandhof <simon.brandhof@gmail.com>
Fri, 25 Feb 2011 07:50:01 +0000 (08:50 +0100)
sonar-plugin-api/src/main/java/org/sonar/api/utils/KeyValueFormat.java
sonar-plugin-api/src/test/java/org/sonar/api/utils/KeyValueFormatTest.java

index cd44e7a9ba75b057ccaa747758ec5aafb0f6259a..e2d198fc3877d6407b1dd41c6d20e54a43dc34bb 100644 (file)
  */
 package org.sonar.api.utils;
 
+import com.google.common.collect.LinkedHashMultiset;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multiset;
-import com.google.common.collect.SortedSetMultimap;
-import com.google.common.collect.TreeMultimap;
 import org.apache.commons.collections.Bag;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.math.NumberUtils;
@@ -35,28 +35,24 @@ import java.text.SimpleDateFormat;
 import java.util.*;
 
 /**
- * Util class to format key/value data. Output is a string representation ready to be
- * injected into the database
+ * Formats and parses key/value pairs with the string representation : "key1=value1;key2=value2". Conversion
+ * of fields is supported and can be extended.
  *
  * @since 1.10
  */
-public final class KeyValueFormat<K extends Comparable, V extends Comparable> {
+public final class KeyValueFormat {
 
   public static final String PAIR_SEPARATOR = ";";
   public static final String FIELD_SEPARATOR = "=";
 
-  private Converter<K> keyConverter;
-  private Converter<V> valueConverter;
-
-  private KeyValueFormat(Converter<K> keyConverter, Converter<V> valueConverter) {
-    this.keyConverter = keyConverter;
-    this.valueConverter = valueConverter;
+  private KeyValueFormat() {
+    // only static methods
   }
 
   public static abstract class Converter<TYPE> {
-    abstract String toString(TYPE type);
+    abstract String format(TYPE type);
 
-    abstract TYPE fromString(String s);
+    abstract TYPE parse(String s);
   }
 
   public static final class StringConverter extends Converter<String> {
@@ -66,12 +62,12 @@ public final class KeyValueFormat<K extends Comparable, V extends Comparable> {
     }
 
     @Override
-    String toString(String s) {
+    String format(String s) {
       return s;
     }
 
     @Override
-    String fromString(String s) {
+    String parse(String s) {
       return s;
     }
   }
@@ -83,29 +79,29 @@ public final class KeyValueFormat<K extends Comparable, V extends Comparable> {
     }
 
     @Override
-    String toString(Integer s) {
+    String format(Integer s) {
       return (s == null ? "" : String.valueOf(s));
     }
 
     @Override
-    Integer fromString(String s) {
+    Integer parse(String s) {
       return StringUtils.isBlank(s) ? null : NumberUtils.toInt(s);
     }
   }
 
-  public static final class SeverityConverter extends Converter<RulePriority> {
-    static final SeverityConverter INSTANCE = new SeverityConverter();
+  public static final class PriorityConverter extends Converter<RulePriority> {
+    static final PriorityConverter INSTANCE = new PriorityConverter();
 
-    private SeverityConverter() {
+    private PriorityConverter() {
     }
 
     @Override
-    String toString(RulePriority s) {
+    String format(RulePriority s) {
       return (s == null ? "" : s.toString());
     }
 
     @Override
-    RulePriority fromString(String s) {
+    RulePriority parse(String s) {
       return StringUtils.isBlank(s) ? null : RulePriority.valueOf(s);
     }
   }
@@ -117,12 +113,12 @@ public final class KeyValueFormat<K extends Comparable, V extends Comparable> {
     }
 
     @Override
-    String toString(Double d) {
+    String format(Double d) {
       return (d == null ? "" : String.valueOf(d));
     }
 
     @Override
-    Double fromString(String s) {
+    Double parse(String s) {
       return StringUtils.isBlank(s) ? null : NumberUtils.toDouble(s);
     }
   }
@@ -139,12 +135,12 @@ public final class KeyValueFormat<K extends Comparable, V extends Comparable> {
     }
 
     @Override
-    String toString(Date d) {
+    String format(Date d) {
       return (d == null ? "" : dateFormat.format(d));
     }
 
     @Override
-    Date fromString(String s) {
+    Date parse(String s) {
       try {
         return StringUtils.isBlank(s) ? null : dateFormat.parse(s);
       } catch (ParseException e) {
@@ -159,95 +155,101 @@ public final class KeyValueFormat<K extends Comparable, V extends Comparable> {
     }
   }
 
-  public static <K extends Comparable, V extends Comparable> KeyValueFormat<K, V> create(Converter<K> keyConverter, Converter<V> valueConverter) {
-    return new KeyValueFormat<K, V>(keyConverter, valueConverter);
-  }
-
-  public static KeyValueFormat<String, String> createStringString() {
-    return new KeyValueFormat<String, String>(StringConverter.INSTANCE, StringConverter.INSTANCE);
-  }
-
-  public static KeyValueFormat<String, Date> createStringDate() {
-    return new KeyValueFormat<String, Date>(StringConverter.INSTANCE, new DateConverter());
-  }
-
-  public static KeyValueFormat<String, Date> createStringDateTime() {
-    return new KeyValueFormat<String, Date>(StringConverter.INSTANCE, new DateTimeConverter());
-  }
-
-  public static KeyValueFormat<Integer, String> createIntString() {
-    return new KeyValueFormat<Integer, String>(IntegerConverter.INSTANCE, StringConverter.INSTANCE);
+  public static <K, V> Map<K, V> parse(String data, Converter<K> keyConverter, Converter<V> valueConverter) {
+    Map<K, V> map = Maps.newLinkedHashMap();
+    if (data != null) {
+      String[] pairs = StringUtils.split(data, PAIR_SEPARATOR);
+      for (String pair : pairs) {
+        String[] keyValue = StringUtils.split(pair, FIELD_SEPARATOR);
+        String key = keyValue[0];
+        String value = (keyValue.length == 2 ? keyValue[1] : "");
+        map.put(keyConverter.parse(key), valueConverter.parse(value));
+      }
+    }
+    return map;
   }
 
-  public static KeyValueFormat<Integer, Integer> createIntInt() {
-    return new KeyValueFormat<Integer, Integer>(IntegerConverter.INSTANCE, IntegerConverter.INSTANCE);
+  public static Map<String, String> parse(String data) {
+    return parse(data, StringConverter.INSTANCE, StringConverter.INSTANCE);
   }
 
-  public static KeyValueFormat<Integer, Double> createIntDouble() {
-    return new KeyValueFormat<Integer, Double>(IntegerConverter.INSTANCE, DoubleConverter.INSTANCE);
+  /**
+   * @since 2.7
+   */
+  public static Map<String, Integer> parseStringInt(String data) {
+    return parse(data, StringConverter.INSTANCE, IntegerConverter.INSTANCE);
   }
 
-  public static KeyValueFormat<Integer, Date> createIntDate() {
-    return new KeyValueFormat<Integer, Date>(IntegerConverter.INSTANCE, new DateConverter());
+  /**
+   * @since 2.7
+   */
+  public static Map<String, Double> parseStringDouble(String data) {
+    return parse(data, StringConverter.INSTANCE, DoubleConverter.INSTANCE);
   }
 
-  public static KeyValueFormat<Integer, Date> createIntDateTime() {
-    return new KeyValueFormat<Integer, Date>(IntegerConverter.INSTANCE, new DateTimeConverter());
+  /**
+   * @since 2.7
+   */
+  public static Map<Integer, String> parseIntString(String data) {
+    return parse(data, IntegerConverter.INSTANCE, StringConverter.INSTANCE);
   }
 
-  public String toString(Map<K, V> map) {
-    return toString(map.entrySet());
+  /**
+   * @since 2.7
+   */
+  public static Map<Integer, Double> parseIntDouble(String data) {
+    return parse(data, IntegerConverter.INSTANCE, DoubleConverter.INSTANCE);
   }
 
-  public String toString(Multimap<K, V> multimap) {
-    return toString(multimap.entries());
+  /**
+   * @since 2.7
+   */
+  public static Map<Integer, Date> parseIntDate(String data) {
+    return parse(data, IntegerConverter.INSTANCE, new DateConverter());
   }
 
-  private String toString(Collection<Map.Entry<K, V>> entries) {
-    StringBuilder sb = new StringBuilder();
-    boolean first = true;
-    for (Map.Entry<K, V> entry : entries) {
-      if (!first) {
-        sb.append(PAIR_SEPARATOR);
-      }
-      sb.append(keyConverter.toString(entry.getKey()));
-      sb.append(FIELD_SEPARATOR);
-      if (entry.getValue() != null) {
-        sb.append(valueConverter.toString(entry.getValue()));
-      }
-      first = false;
-    }
-    return sb.toString();
+  /**
+   * @since 2.7
+   */
+  public static Map<Integer, Date> parseIntDateTime(String data) {
+    return parse(data, IntegerConverter.INSTANCE, new DateTimeConverter());
   }
 
-  public SortedMap<K, V> toSortedMap(String data) {
-    SortedMap<K, V> map = new TreeMap<K, V>();
+  /**
+   * Value of pairs is the occurrences of the same single key. A multiset is sometimes called a bag.
+   * For example parsing "foo=2;bar=1" creates a multiset with 3 elements : foo, foo and bar.
+   */
+  /**
+   * @since 2.7
+   */
+  public static <K> Multiset<K> parseMultiset(String data, Converter<K> keyConverter) {
+    Multiset<K> multiset = LinkedHashMultiset.create();// to keep the same order
     if (data != null) {
       String[] pairs = StringUtils.split(data, PAIR_SEPARATOR);
       for (String pair : pairs) {
         String[] keyValue = StringUtils.split(pair, FIELD_SEPARATOR);
         String key = keyValue[0];
-        String value = (keyValue.length == 2 ? keyValue[1] : "");
-        map.put(keyConverter.fromString(key), valueConverter.fromString(value));
+        String value = (keyValue.length == 2 ? keyValue[1] : "0");
+        multiset.add(keyConverter.parse(key), IntegerConverter.INSTANCE.parse(value));
       }
     }
-    return map;
+    return multiset;
   }
 
-  public SortedSetMultimap<K, V> toSortedMultimap(String data) {
-    SortedSetMultimap<K, V> map = TreeMultimap.create();
-    if (data != null) {
-      String[] pairs = StringUtils.split(data, PAIR_SEPARATOR);
-      for (String pair : pairs) {
-        String[] keyValue = StringUtils.split(pair, FIELD_SEPARATOR);
-        String key = keyValue[0];
-        String value = (keyValue.length == 2 ? keyValue[1] : "");
-        map.put(keyConverter.fromString(key), valueConverter.fromString(value));
-      }
-    }
-    return map;
+
+  /**
+   * @since 2.7
+   */
+  public static Multiset<Integer> parseIntegerMultiset(String data) {
+    return parseMultiset(data, IntegerConverter.INSTANCE);
   }
 
+  /**
+   * @since 2.7
+   */
+  public static Multiset<String> parseMultiset(String data) {
+    return parseMultiset(data, StringConverter.INSTANCE);
+  }
 
   /**
    * Transforms a string with the following format : "key1=value1;key2=value2..."
@@ -256,7 +258,7 @@ public final class KeyValueFormat<K extends Comparable, V extends Comparable> {
    * @param data        the input string
    * @param transformer the interface to implement
    * @return a Map of <key, value>
-   * @deprecated since 2.7. Use instance methods instead of static methods, for example KeyValueFormat.createIntString().parse(String)
+   * @deprecated since 2.7
    */
   @Deprecated
   public static <KEY, VALUE> Map<KEY, VALUE> parse(String data, Transformer<KEY, VALUE> transformer) {
@@ -271,53 +273,109 @@ public final class KeyValueFormat<K extends Comparable, V extends Comparable> {
     return map;
   }
 
-  /**
-   * Transforms a string with the following format : "key1=value1;key2=value2..."
-   * into a Map<String,String>
-   *
-   * @param data the string to parse
-   * @return a map
-   * @deprecated since 2.7. Use instance methods instead of static methods, for example KeyValueFormat.createIntString().parse(String)
-   */
-  @Deprecated
-  public static Map<String, String> parse(String data) {
-    Map<String, String> map = new HashMap<String, String>();
-    String[] pairs = StringUtils.split(data, PAIR_SEPARATOR);
-    for (String pair : pairs) {
-      String[] keyValue = StringUtils.split(pair, FIELD_SEPARATOR);
-      String key = keyValue[0];
-      String value = (keyValue.length == 2 ? keyValue[1] : "");
-      map.put(key, value);
-    }
-    return map;
-  }
-
-  /**
-   * Transforms a map<KEY,VALUE> into a string with the format : "key1=value1;key2=value2..."
-   *
-   * @param map the map to transform
-   * @return the formatted string
-   * @deprecated since 2.7. Use instance methods instead of static methods, for example KeyValueFormat.createIntString().parse(String)
-   */
-  @Deprecated
-  public static <KEY, VALUE> String format(Map<KEY, VALUE> map) {
+  private static <K, V> String formatEntries(Collection<Map.Entry<K, V>> entries, Converter<K> keyConverter, Converter<V> valueConverter) {
     StringBuilder sb = new StringBuilder();
     boolean first = true;
-    for (Map.Entry<?, ?> entry : map.entrySet()) {
+    for (Map.Entry<K, V> entry : entries) {
       if (!first) {
         sb.append(PAIR_SEPARATOR);
       }
-      sb.append(entry.getKey().toString());
+      sb.append(keyConverter.format(entry.getKey()));
       sb.append(FIELD_SEPARATOR);
       if (entry.getValue() != null) {
-        sb.append(entry.getValue());
+        sb.append(valueConverter.format(entry.getValue()));
       }
       first = false;
     }
+    return sb.toString();
+  }
 
+  private static <K> String formatEntries(Set<Multiset.Entry<K>> entries, Converter<K> keyConverter) {
+    StringBuilder sb = new StringBuilder();
+    boolean first = true;
+    for (Multiset.Entry<K> entry : entries) {
+      if (!first) {
+        sb.append(PAIR_SEPARATOR);
+      }
+      sb.append(keyConverter.format(entry.getElement()));
+      sb.append(FIELD_SEPARATOR);
+      sb.append(IntegerConverter.INSTANCE.format(entry.getCount()));
+      first = false;
+    }
     return sb.toString();
   }
 
+
+  /**
+   * @since 2.7
+   */
+  public static <K, V> String format(Map<K, V> map, Converter<K> keyConverter, Converter<V> valueConverter) {
+    return formatEntries(map.entrySet(), keyConverter, valueConverter);
+  }
+
+  /**
+   * @since 2.7
+   */
+  public static String format(Map<String, String> map) {
+    return format(map, StringConverter.INSTANCE, StringConverter.INSTANCE);
+  }
+
+  /**
+   * @since 2.7
+   */
+  public static String formatIntString(Map<Integer, String> map) {
+    return format(map, IntegerConverter.INSTANCE, StringConverter.INSTANCE);
+  }
+
+  /**
+   * @since 2.7
+   */
+  public static String formatIntDouble(Map<Integer, Double> map) {
+    return format(map, IntegerConverter.INSTANCE, DoubleConverter.INSTANCE);
+  }
+
+  /**
+   * @since 2.7
+   */
+  public static String formatIntDate(Map<Integer, Date> map) {
+    return format(map, IntegerConverter.INSTANCE, new DateConverter());
+  }
+
+  /**
+   * @since 2.7
+   */
+  public static String formatIntDateTime(Map<Integer, Date> map) {
+    return format(map, IntegerConverter.INSTANCE, new DateTimeConverter());
+  }
+
+  /**
+   * @since 2.7
+   */
+  public static String formatStringInt(Map<String, Integer> map) {
+    return format(map, StringConverter.INSTANCE, IntegerConverter.INSTANCE);
+  }
+
+  /**
+   * Limitation: there's currently no methods to parse into Multimap.
+   * @since 2.7
+   */
+  public static <K, V> String format(Multimap<K, V> map, Converter<K> keyConverter, Converter<V> valueConverter) {
+    return formatEntries(map.entries(), keyConverter, valueConverter);
+  }
+
+  /**
+   * @since 2.7
+   */
+  public static <K> String format(Multiset<K> multiset, Converter<K> keyConverter) {
+    return formatEntries(multiset.entrySet(), keyConverter);
+  }
+
+  public static String format(Multiset<String> multiset) {
+    return formatEntries(multiset.entrySet(), StringConverter.INSTANCE);
+  }
+
+
+
   /**
    * @since 1.11
    * @deprecated use Multiset from google collections instead of commons-collections bags
@@ -349,37 +407,13 @@ public final class KeyValueFormat<K extends Comparable, V extends Comparable> {
     return sb.toString();
   }
 
-  /**
-   * Transforms a Multiset<?> into a string with the format : "key1=count1;key2=count2..."
-   *
-   * @param set the set to transform
-   * @return the formatted string
-   * @deprecated since 2.7. Use instance methods instead of static methods, for example KeyValueFormat.createIntString().parse(String)
-   */
-  @Deprecated
-  public static String format(Multiset<?> set) {
-    StringBuilder sb = new StringBuilder();
-    if (set != null) {
-      boolean first = true;
-      for (Multiset.Entry<?> entry : set.entrySet()) {
-        if (!first) {
-          sb.append(PAIR_SEPARATOR);
-        }
-        sb.append(entry.getElement().toString());
-        sb.append(FIELD_SEPARATOR);
-        sb.append(entry.getCount());
-        first = false;
-      }
-    }
-    return sb.toString();
-  }
 
   /**
    * Transforms a Object... into a string with the format : "object1=object2;object3=object4..."
    *
    * @param objects the object list to transform
    * @return the formatted string
-   * @deprecated since 2.7. Use instance methods instead of static methods, for example KeyValueFormat.createIntString().parse(String)
+   * @deprecated since 2.7 because there's not the inverse method to parse.
    */
   @Deprecated
   public static String format(Object... objects) {
index 58b2fa9bf53b5b93fc98a2464f921ae0a80ee948..74d7cf28b0e3d9ffbe975d52bf8ca267a7959be1 100644 (file)
@@ -19,7 +19,9 @@
  */
 package org.sonar.api.utils;
 
+import com.google.common.collect.LinkedHashMultiset;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Multiset;
 import org.junit.Test;
 import org.sonar.api.rules.RulePriority;
 
@@ -27,7 +29,6 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Map;
-import java.util.SortedMap;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.nullValue;
@@ -40,7 +41,7 @@ public class KeyValueFormatTest {
     Map<String,String> map = Maps.newLinkedHashMap();
     map.put("lucky", "luke");
     map.put("aste", "rix");
-    String s = KeyValueFormat.createStringString().toString(map);
+    String s = KeyValueFormat.format(map);
     assertThat(s, is("lucky=luke;aste=rix"));// same order
   }
 
@@ -49,7 +50,7 @@ public class KeyValueFormatTest {
     Map<Integer,String> map = Maps.newLinkedHashMap();
     map.put(3, "three");
     map.put(5, "five");
-    String s = KeyValueFormat.createIntString().toString(map);
+    String s = KeyValueFormat.formatIntString(map);
     assertThat(s, is("3=three;5=five"));// same order
   }
 
@@ -58,7 +59,7 @@ public class KeyValueFormatTest {
     Map<Integer,Double> map = Maps.newLinkedHashMap();
     map.put(13, 2.0);
     map.put(5, 5.75);
-    String s = KeyValueFormat.createIntDouble().toString(map);
+    String s = KeyValueFormat.formatIntDouble(map);
     assertThat(s, is("13=2.0;5=5.75"));// same order
   }
 
@@ -67,14 +68,14 @@ public class KeyValueFormatTest {
     Map<Integer,Double> map = Maps.newLinkedHashMap();
     map.put(13, null);
     map.put(5, 5.75);
-    String s = KeyValueFormat.createIntDouble().toString(map);
+    String s = KeyValueFormat.formatIntDouble(map);
     assertThat(s, is("13=;5=5.75"));// same order
   }
 
   @Test
   public void shouldFormatBlank() {
     Map<Integer,String> map = Maps.newTreeMap();
-    String s = KeyValueFormat.createIntString().toString(map);
+    String s = KeyValueFormat.formatIntString(map);
     assertThat(s, is(""));
   }
 
@@ -84,13 +85,13 @@ public class KeyValueFormatTest {
     map.put(4, new SimpleDateFormat("yyyy-MM-dd").parse("2010-12-25"));
     map.put(20, new SimpleDateFormat("yyyy-MM-dd").parse("2009-05-28"));
     map.put(12, null);
-    String s = KeyValueFormat.createIntDate().toString(map);
+    String s = KeyValueFormat.formatIntDate(map);
     assertThat(s, is("4=2010-12-25;20=2009-05-28;12="));
   }
 
   @Test
   public void shouldParseStrings() throws ParseException {
-    SortedMap<String,String> map = KeyValueFormat.createStringString().toSortedMap("one=un;two=deux");
+    Map<String,String> map = KeyValueFormat.parse("one=un;two=deux");
     assertThat(map.size(), is(2));
     assertThat(map.get("one"), is("un"));
     assertThat(map.get("two"), is("deux"));
@@ -99,19 +100,19 @@ public class KeyValueFormatTest {
 
   @Test
   public void shouldParseBlank() throws ParseException {
-    SortedMap<String,String> map = KeyValueFormat.createStringString().toSortedMap("");
+    Map<String,String> map = KeyValueFormat.parse("");
     assertThat(map.size(), is(0));
   }
 
   @Test
   public void shouldParseNull() throws ParseException {
-    SortedMap<String,String> map = KeyValueFormat.createStringString().toSortedMap(null);
+    Map<String,String> map = KeyValueFormat.parse(null);
     assertThat(map.size(), is(0));
   }
 
   @Test
   public void shouldParseEmptyFields() throws ParseException {
-    SortedMap<Integer,Double> map = KeyValueFormat.createIntDouble().toSortedMap("4=4.2;2=;6=6.68");
+    Map<Integer,Double> map = KeyValueFormat.parseIntDouble("4=4.2;2=;6=6.68");
     assertThat(map.size(), is(3));
     assertThat(map.get(4), is(4.2));
     assertThat(map.get(2), nullValue());
@@ -119,11 +120,37 @@ public class KeyValueFormatTest {
   }
 
   @Test
-  public void shouldConvertSeverity() {
-    assertThat(KeyValueFormat.SeverityConverter.INSTANCE.toString(RulePriority.BLOCKER), is("BLOCKER"));
-    assertThat(KeyValueFormat.SeverityConverter.INSTANCE.toString(null), is(""));
+  public void shouldConvertPriority() {
+    assertThat(KeyValueFormat.PriorityConverter.INSTANCE.format(RulePriority.BLOCKER), is("BLOCKER"));
+    assertThat(KeyValueFormat.PriorityConverter.INSTANCE.format(null), is(""));
 
-    assertThat(KeyValueFormat.SeverityConverter.INSTANCE.fromString("MAJOR"), is(RulePriority.MAJOR));
-    assertThat(KeyValueFormat.SeverityConverter.INSTANCE.fromString(""), nullValue());
+    assertThat(KeyValueFormat.PriorityConverter.INSTANCE.parse("MAJOR"), is(RulePriority.MAJOR));
+    assertThat(KeyValueFormat.PriorityConverter.INSTANCE.parse(""), nullValue());
+  }
+
+  @Test
+  public void shouldFormatMultiset() {
+    Multiset<String> set = LinkedHashMultiset.create();
+    set.add("foo");
+    set.add("foo");
+    set.add("bar");
+    assertThat(KeyValueFormat.format(set), is("foo=2;bar=1"));
+  }
+
+  @Test
+  public void shouldParseMultiset() {
+    Multiset<String> multiset = KeyValueFormat.parseMultiset("foo=2;bar=1;none=");
+    assertThat(multiset.count("foo"), is(2));
+    assertThat(multiset.count("bar"), is(1));
+    assertThat(multiset.count("none"), is(0));
+    assertThat(multiset.contains("none"), is(false));
+  }
+
+  @Test
+  public void shouldKeepOrderWhenParsingMultiset() {
+    Multiset<String> multiset = KeyValueFormat.parseMultiset("foo=2;bar=1");
+
+    // first one is foo
+    assertThat(multiset.iterator().next(), is("foo"));
   }
 }