Esempio n. 1
0
 public void testNefariousMultimapPutAllMultimap() {
   Multimap<String, Integer> multimap = LinkedListMultimap.create();
   Multimap<String, Integer> constrained =
       MapConstraints.constrainedMultimap(multimap, TEST_CONSTRAINT);
   Multimap<String, Integer> onceIterable = Multimaps.forMap(onceIterableMap("foo", 1));
   constrained.putAll(onceIterable);
   assertEquals(ImmutableList.of(1), constrained.get("foo"));
 }
Esempio n. 2
0
 public void testNefariousMultimapGetAddAll() {
   Multimap<String, Integer> multimap = LinkedListMultimap.create();
   Multimap<String, Integer> constrained =
       MapConstraints.constrainedMultimap(multimap, TEST_CONSTRAINT);
   Collection<Integer> onceIterable = ConstraintsTest.onceIterableCollection(1);
   constrained.get("foo").addAll(onceIterable);
   assertEquals(ImmutableList.of(1), constrained.get("foo"));
 }
Esempio n. 3
0
 public void testConstrainedTypePreservingList() {
   ListMultimap<String, Integer> multimap =
       MapConstraints.constrainedListMultimap(
           LinkedListMultimap.<String, Integer>create(), TEST_CONSTRAINT);
   multimap.put("foo", 1);
   Map.Entry<String, Collection<Integer>> entry = multimap.asMap().entrySet().iterator().next();
   assertTrue(entry.getValue() instanceof List);
   assertFalse(multimap.entries() instanceof Set);
   assertFalse(multimap.get("foo") instanceof RandomAccess);
 }
Esempio n. 4
0
 public void testMultimapEntriesRemoveNefariousEntry() {
   Multimap<String, Integer> multimap = LinkedListMultimap.create();
   Multimap<String, Integer> constrained =
       MapConstraints.constrainedMultimap(multimap, TEST_CONSTRAINT);
   multimap.put("foo", 1);
   Map.Entry<String, Integer> nefariousEntry = nefariousMapEntry(TEST_KEY, TEST_VALUE);
   Collection<Map.Entry<String, Integer>> entries = constrained.entries();
   assertFalse(entries.remove(nefariousEntry));
   assertFalse(multimap.containsValue(TEST_VALUE));
   assertFalse(entries.removeAll(Collections.singleton(nefariousEntry)));
   assertFalse(multimap.containsValue(TEST_VALUE));
 }
Esempio n. 5
0
 public void testConstrainedMultimapLegal() {
   Multimap<String, Integer> multimap = LinkedListMultimap.create();
   Multimap<String, Integer> constrained =
       MapConstraints.constrainedMultimap(multimap, TEST_CONSTRAINT);
   multimap.put(TEST_KEY, TEST_VALUE);
   constrained.put("foo", 1);
   multimap.get("bar").add(2);
   constrained.get("baz").add(3);
   multimap.get("qux").addAll(Arrays.asList(4));
   constrained.get("zig").addAll(Arrays.asList(5));
   multimap.putAll("zag", Arrays.asList(6));
   constrained.putAll("bee", Arrays.asList(7));
   multimap.putAll(new ImmutableMultimap.Builder<String, Integer>().put("bim", 8).build());
   constrained.putAll(new ImmutableMultimap.Builder<String, Integer>().put("bop", 9).build());
   multimap.putAll(new ImmutableMultimap.Builder<String, Integer>().put("dig", 10).build());
   constrained.putAll(new ImmutableMultimap.Builder<String, Integer>().put("dag", 11).build());
   assertTrue(multimap.equals(constrained));
   assertTrue(constrained.equals(multimap));
   ASSERT
       .that(ImmutableList.copyOf(multimap.entries()))
       .is(ImmutableList.copyOf(constrained.entries()));
   ASSERT.that(constrained.asMap().get("foo")).has().item(1);
   assertNull(constrained.asMap().get("missing"));
   assertEquals(multimap.asMap(), constrained.asMap());
   assertEquals(multimap.values(), constrained.values());
   assertEquals(multimap.keys(), constrained.keys());
   assertEquals(multimap.keySet(), constrained.keySet());
   assertEquals(multimap.toString(), constrained.toString());
   assertEquals(multimap.hashCode(), constrained.hashCode());
   ASSERT
       .that(multimap.entries())
       .has()
       .allOf(
           Maps.immutableEntry(TEST_KEY, TEST_VALUE),
           Maps.immutableEntry("foo", 1),
           Maps.immutableEntry("bar", 2),
           Maps.immutableEntry("baz", 3),
           Maps.immutableEntry("qux", 4),
           Maps.immutableEntry("zig", 5),
           Maps.immutableEntry("zag", 6),
           Maps.immutableEntry("bee", 7),
           Maps.immutableEntry("bim", 8),
           Maps.immutableEntry("bop", 9),
           Maps.immutableEntry("dig", 10),
           Maps.immutableEntry("dag", 11))
       .inOrder();
   assertFalse(constrained.asMap().values() instanceof Serializable);
   Iterator<Collection<Integer>> iterator = constrained.asMap().values().iterator();
   iterator.next();
   iterator.next().add(12);
   assertTrue(multimap.containsEntry("foo", 12));
 }
Esempio n. 6
0
 public void testMultimapAsMapEntriesContainsNefariousEntry() {
   Multimap<String, Integer> multimap = LinkedListMultimap.create();
   Multimap<String, Integer> constrained =
       MapConstraints.constrainedMultimap(multimap, TEST_CONSTRAINT);
   multimap.put("foo", 1);
   Map.Entry<String, ? extends Collection<Integer>> nefariousEntry =
       nefariousMapEntry(TEST_KEY, Collections.singleton(TEST_VALUE));
   Set<Map.Entry<String, Collection<Integer>>> entries = constrained.asMap().entrySet();
   assertFalse(entries.contains(nefariousEntry));
   assertFalse(multimap.containsValue(TEST_VALUE));
   assertFalse(entries.containsAll(Collections.singleton(nefariousEntry)));
   assertFalse(multimap.containsValue(TEST_VALUE));
 }
Esempio n. 7
0
 public void testMultimapAsMapValuesToArray() {
   Multimap<String, Integer> multimap = LinkedListMultimap.create();
   Multimap<String, Integer> constrained =
       MapConstraints.constrainedMultimap(multimap, TEST_CONSTRAINT);
   multimap.put("foo", 1);
   @SuppressWarnings("unchecked")
   Collection<Integer> collection =
       (Collection<Integer>) constrained.asMap().values().toArray()[0];
   try {
     collection.add(TEST_VALUE);
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   assertFalse(multimap.containsValue(TEST_VALUE));
 }
Esempio n. 8
0
 public void testMultimapAsMapEntriesToArray() {
   Multimap<String, Integer> multimap = LinkedListMultimap.create();
   Multimap<String, Integer> constrained =
       MapConstraints.constrainedMultimap(multimap, TEST_CONSTRAINT);
   multimap.put("foo", 1);
   @SuppressWarnings("unchecked")
   Map.Entry<String, Collection<Integer>> entry =
       (Map.Entry<String, Collection<Integer>>) constrained.asMap().entrySet().toArray()[0];
   try {
     entry.setValue(Collections.<Integer>emptySet());
     fail("UnsupportedOperationException expected");
   } catch (UnsupportedOperationException expected) {
   }
   try {
     entry.getValue().add(TEST_VALUE);
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   assertFalse(multimap.containsValue(TEST_VALUE));
 }
  private void reportExceptions(List<Exception> exceptionList, List<Exception> ignoredExceptions) {
    Multimap<Class<? extends Exception>, Exception> exceptionMultimap = LinkedListMultimap.create();
    for (Exception exception : exceptionList) {
      exceptionMultimap.put(exception.getClass(), exception);
    }
    for (Exception exception : ignoredExceptions) {
      exceptionMultimap.put(exception.getClass(), exception);
    }

    for (Class<? extends Exception> exceptionType : exceptionMultimap.keySet()) {
      TestSetStats testSuiteData = new TestSetStats(false, false);
      for (Exception exception : exceptionMultimap.get(exceptionType)) {
        if (ignoredExceptions.contains(exception)) {
          testSuiteData.testSkipped(testCase(exception, ReportEntryType.skipped));
        } else {
          testSuiteData.testError(testCase(exception, ReportEntryType.error));
        }
      }
      reportTestSuite(exceptionType.getSimpleName(), testSuiteData);
    }
  }
Esempio n. 10
0
  private Map<FieldName, ? extends ClassificationMap<?>> evaluateRuleSet(
      ModelManagerEvaluationContext context) {
    RuleSetModel ruleSetModel = getModel();

    RuleSet ruleSet = ruleSetModel.getRuleSet();

    List<RuleSelectionMethod> ruleSelectionMethods = ruleSet.getRuleSelectionMethods();

    RuleSelectionMethod ruleSelectionMethod;

    // "If more than one method is included, the first method is used as the default method for
    // scoring"
    if (ruleSelectionMethods.size() > 0) {
      ruleSelectionMethod = ruleSelectionMethods.get(0);
    } else {
      throw new InvalidFeatureException(ruleSet);
    }

    // Both the ordering of keys and values is significant
    ListMultimap<String, SimpleRule> firedRules = LinkedListMultimap.create();

    List<Rule> rules = ruleSet.getRules();
    for (Rule rule : rules) {
      collectFiredRules(firedRules, rule, context);
    }

    RuleClassificationMap result = new RuleClassificationMap();

    RuleSelectionMethod.Criterion criterion = ruleSelectionMethod.getCriterion();

    Set<String> keys = firedRules.keySet();
    for (String key : keys) {
      List<SimpleRule> keyRules = firedRules.get(key);

      switch (criterion) {
        case FIRST_HIT:
          {
            SimpleRule winner = keyRules.get(0);

            // The first value of the first key
            if (result.getEntity() == null) {
              result.setEntity(winner);
            }

            result.put(key, winner.getConfidence());
          }
          break;
        case WEIGHTED_SUM:
          {
            SimpleRule winner = null;

            double totalWeight = 0;

            for (SimpleRule keyRule : keyRules) {

              if (winner == null || (winner.getWeight() < keyRule.getWeight())) {
                winner = keyRule;
              }

              totalWeight += keyRule.getWeight();
            }

            result.put(winner, key, totalWeight / firedRules.size());
          }
          break;
        case WEIGHTED_MAX:
          {
            SimpleRule winner = null;

            for (SimpleRule keyRule : keyRules) {

              if (winner == null || (winner.getWeight() < keyRule.getWeight())) {
                winner = keyRule;
              }
            }

            result.put(winner, key, winner.getConfidence());
          }
          break;
        default:
          throw new UnsupportedFeatureException(ruleSelectionMethod, criterion);
      }
    }

    return TargetUtil.evaluateClassification(result, context);
  }
Esempio n. 11
0
/**
 * Schema.
 *
 * <p>Wrapper around user-defined schema used internally.
 */
public class OptiqSchema {
  private final OptiqSchema parent;
  public final Schema schema;
  public final String name;
  /** Tables explicitly defined in this schema. Does not include tables in {@link #schema}. */
  public final Map<String, TableEntry> tableMap = new HashMap<String, TableEntry>();

  public final Map<String, TableEntry> tableMapInsensitive =
      new TreeMap<String, TableEntry>(String.CASE_INSENSITIVE_ORDER);
  private final Multimap<String, FunctionEntry> functionMap = LinkedListMultimap.create();
  private final Map<String, FunctionEntry> nullaryFunctionMapInsensitive =
      new TreeMap<String, FunctionEntry>(String.CASE_INSENSITIVE_ORDER);
  private final Map<String, OptiqSchema> subSchemaMap = new HashMap<String, OptiqSchema>();
  private final Map<String, OptiqSchema> subSchemaMapInsensitive =
      new TreeMap<String, OptiqSchema>(String.CASE_INSENSITIVE_ORDER);
  public final Map<String, Table> compositeTableMap;
  public final Multimap<String, Function> compositeFunctionMap;
  public final Map<String, OptiqSchema> compositeSubSchemaMap;

  public OptiqSchema(OptiqSchema parent, final Schema schema, String name) {
    this.parent = parent;
    this.schema = schema;
    this.name = name;
    assert (parent == null) == (this instanceof OptiqRootSchema);
    //noinspection unchecked
    this.compositeTableMap =
        CompositeMap.of(
            Maps.transformValues(
                tableMap,
                new com.google.common.base.Function<TableEntry, Table>() {
                  public Table apply(TableEntry input) {
                    return input.getTable();
                  }
                }),
            Maps.transformValues(
                Multimaps.filterEntries(
                        functionMap,
                        new Predicate<Map.Entry<String, FunctionEntry>>() {
                          public boolean apply(Map.Entry<String, FunctionEntry> entry) {
                            final Function function = entry.getValue().getFunction();
                            return function instanceof TableMacro
                                && function.getParameters().isEmpty();
                          }
                        })
                    .asMap(),
                new com.google.common.base.Function<Collection<FunctionEntry>, Table>() {
                  public Table apply(Collection<FunctionEntry> input) {
                    // At most one function with zero parameters.
                    final TableMacro tableMacro =
                        (TableMacro) input.iterator().next().getFunction();
                    return tableMacro.apply(ImmutableList.of());
                  }
                }),
            Compatible.INSTANCE.asMap(
                schema.getTableNames(),
                new com.google.common.base.Function<String, Table>() {
                  public Table apply(String input) {
                    return schema.getTable(input);
                  }
                }));
    // TODO: include schema's functions in this map.
    this.compositeFunctionMap =
        Multimaps.transformValues(
            functionMap,
            new com.google.common.base.Function<FunctionEntry, Function>() {
              public Function apply(FunctionEntry input) {
                return input.getFunction();
              }
            });
    //noinspection unchecked
    this.compositeSubSchemaMap =
        CompositeMap.of(
            subSchemaMap,
            Compatible.INSTANCE.asMap(
                schema.getSubSchemaNames(),
                new com.google.common.base.Function<String, OptiqSchema>() {
                  public OptiqSchema apply(String name) {
                    return add(name, schema.getSubSchema(name));
                  }
                }));
  }

  /** Defines a table within this schema. */
  public TableEntry add(String tableName, Table table) {
    final TableEntryImpl entry = new TableEntryImpl(this, tableName, table);
    tableMap.put(tableName, entry);
    tableMapInsensitive.put(tableName, entry);
    return entry;
  }

  private FunctionEntry add(String name, Function function) {
    final FunctionEntryImpl entry = new FunctionEntryImpl(this, name, function);
    functionMap.put(name, entry);
    if (function.getParameters().isEmpty()) {
      nullaryFunctionMapInsensitive.put(name, entry);
    }
    return entry;
  }

  public OptiqRootSchema root() {
    for (OptiqSchema schema = this; ; ) {
      if (schema.parent == null) {
        return (OptiqRootSchema) schema;
      }
      schema = schema.parent;
    }
  }

  /** Returns the path of an object in this schema. */
  public List<String> path(String name) {
    final List<String> list = new ArrayList<String>();
    if (name != null) {
      list.add(name);
    }
    for (OptiqSchema s = this; s != null; s = s.parent) {
      if (s.parent != null || !s.name.equals("")) {
        // Omit the root schema's name from the path if it's the empty string,
        // which it usually is.
        list.add(s.name);
      }
    }
    return ImmutableList.copyOf(Lists.reverse(list));
  }

  public final OptiqSchema getSubSchema(String schemaName, boolean caseSensitive) {
    return (caseSensitive ? subSchemaMap : subSchemaMapInsensitive).get(schemaName);
  }

  /** Adds a child schema of this schema. */
  public OptiqSchema add(String name, Schema schema) {
    final OptiqSchema optiqSchema = new OptiqSchema(this, schema, name);
    subSchemaMap.put(name, optiqSchema);
    subSchemaMapInsensitive.put(name, optiqSchema);
    return optiqSchema;
  }

  public final Table getTable(String tableName, boolean caseSensitive) {
    if (caseSensitive) {
      return compositeTableMap.get(tableName);
    } else {
      final TableEntry tableEntry = tableMapInsensitive.get(tableName);
      if (tableEntry != null) {
        return tableEntry.getTable();
      }
      final FunctionEntry entry = nullaryFunctionMapInsensitive.get(tableName);
      if (entry != null) {
        return ((TableMacro) entry.getFunction()).apply(ImmutableList.of());
      }
      for (String name : schema.getTableNames()) {
        if (name.equalsIgnoreCase(tableName)) {
          return schema.getTable(name);
        }
      }
      return null;
    }
  }

  public String getName() {
    return name;
  }

  public SchemaPlus plus() {
    return new SchemaPlusImpl();
  }

  public static OptiqSchema from(SchemaPlus plus) {
    return ((SchemaPlusImpl) plus).optiqSchema();
  }

  /**
   * Entry in a schema, such as a table or sub-schema.
   *
   * <p>Each object's name is a property of its membership in a schema; therefore in principle it
   * could belong to several schemas, or even the same schema several times, with different names.
   * In this respect, it is like an inode in a Unix file system.
   *
   * <p>The members of a schema must have unique names.
   */
  public abstract static class Entry {
    public final OptiqSchema schema;
    public final String name;

    public Entry(OptiqSchema schema, String name) {
      Linq4j.requireNonNull(schema);
      Linq4j.requireNonNull(name);
      this.schema = schema;
      this.name = name;
    }

    /** Returns this object's path. For example ["hr", "emps"]. */
    public final List<String> path() {
      return schema.path(name);
    }
  }

  /** Membership of a table in a schema. */
  public abstract static class TableEntry extends Entry {
    public TableEntry(OptiqSchema schema, String name) {
      super(schema, name);
    }

    public abstract Table getTable();
  }

  /** Membership of a function in a schema. */
  public abstract static class FunctionEntry extends Entry {
    public FunctionEntry(OptiqSchema schema, String name) {
      super(schema, name);
    }

    public abstract Function getFunction();

    /**
     * Whether this represents a materialized view. (At a given point in time, it may or may not be
     * materialized as a table.)
     */
    public abstract boolean isMaterialization();
  }

  /** Implementation of {@link SchemaPlus} based on an {@code OptiqSchema}. */
  private class SchemaPlusImpl implements SchemaPlus {
    public OptiqSchema optiqSchema() {
      return OptiqSchema.this;
    }

    public SchemaPlus getParentSchema() {
      return parent == null ? null : parent.plus();
    }

    public String getName() {
      return OptiqSchema.this.getName();
    }

    public boolean isMutable() {
      return schema.isMutable();
    }

    public Expression getExpression(SchemaPlus parentSchema, String name) {
      return schema.getExpression(parentSchema, name);
    }

    public Table getTable(String name) {
      return compositeTableMap.get(name);
    }

    public Set<String> getTableNames() {
      return compositeTableMap.keySet();
    }

    public Collection<Function> getFunctions(String name) {
      return compositeFunctionMap.get(name);
    }

    public Set<String> getFunctionNames() {
      return compositeFunctionMap.keySet();
    }

    public SchemaPlus getSubSchema(String name) {
      final OptiqSchema subSchema = OptiqSchema.this.getSubSchema(name, true);
      return subSchema == null ? null : subSchema.plus();
    }

    public Set<String> getSubSchemaNames() {
      return subSchemaMap.keySet();
    }

    public SchemaPlus add(String name, Schema schema) {
      final OptiqSchema optiqSchema = OptiqSchema.this.add(name, schema);
      return optiqSchema.plus();
    }

    public <T> T unwrap(Class<T> clazz) {
      if (clazz.isInstance(this)) {
        return clazz.cast(this);
      }
      if (clazz.isInstance(OptiqSchema.this)) {
        return clazz.cast(OptiqSchema.this);
      }
      if (clazz.isInstance(OptiqSchema.this.schema)) {
        return clazz.cast(OptiqSchema.this.schema);
      }
      throw new ClassCastException("not a " + clazz);
    }

    public void add(String name, Table table) {
      OptiqSchema.this.add(name, table);
    }

    public void add(String name, net.hydromatic.optiq.Function function) {
      OptiqSchema.this.add(name, function);
    }
  }

  /**
   * Implementation of {@link net.hydromatic.optiq.jdbc.OptiqSchema.TableEntry} where all properties
   * are held in fields.
   */
  public static class TableEntryImpl extends TableEntry {
    private final Table table;

    /** Creates a TableEntryImpl. */
    public TableEntryImpl(OptiqSchema schema, String name, Table table) {
      super(schema, name);
      assert table != null;
      this.table = table;
    }

    public Table getTable() {
      return table;
    }
  }

  /** Implementation of {@link FunctionEntry} where all properties are held in fields. */
  public static class FunctionEntryImpl extends FunctionEntry {
    private final Function function;

    /** Creates a FunctionEntryImpl. */
    public FunctionEntryImpl(OptiqSchema schema, String name, Function function) {
      super(schema, name);
      this.function = function;
    }

    public Function getFunction() {
      return function;
    }

    public boolean isMaterialization() {
      return function instanceof MaterializedViewTable.MaterializedViewTableMacro;
    }
  }
}
Esempio n. 12
0
 @SuppressWarnings("unchecked")
 public void testConstrainedMultimapIllegal() {
   Multimap<String, Integer> multimap = LinkedListMultimap.create();
   Multimap<String, Integer> constrained =
       MapConstraints.constrainedMultimap(multimap, TEST_CONSTRAINT);
   try {
     constrained.put(TEST_KEY, 1);
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.put("foo", TEST_VALUE);
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   try {
     constrained.put(TEST_KEY, TEST_VALUE);
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.get(TEST_KEY).add(1);
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.get("foo").add(TEST_VALUE);
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   try {
     constrained.get(TEST_KEY).add(TEST_VALUE);
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.get(TEST_KEY).addAll(Arrays.asList(1));
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.get("foo").addAll(Arrays.asList(1, TEST_VALUE));
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   try {
     constrained.get(TEST_KEY).addAll(Arrays.asList(1, TEST_VALUE));
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.putAll(TEST_KEY, Arrays.asList(1));
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.putAll("foo", Arrays.asList(1, TEST_VALUE));
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   try {
     constrained.putAll(TEST_KEY, Arrays.asList(1, TEST_VALUE));
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.putAll(
         new ImmutableMultimap.Builder<String, Integer>().put(TEST_KEY, 2).put("foo", 1).build());
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.putAll(
         new ImmutableMultimap.Builder<String, Integer>()
             .put("bar", TEST_VALUE)
             .put("foo", 1)
             .build());
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   try {
     constrained.putAll(
         new ImmutableMultimap.Builder<String, Integer>()
             .put(TEST_KEY, TEST_VALUE)
             .put("foo", 1)
             .build());
     fail("TestKeyException expected");
   } catch (TestKeyException expected) {
   }
   try {
     constrained.entries().add(Maps.immutableEntry(TEST_KEY, 1));
     fail("UnsupportedOperationException expected");
   } catch (UnsupportedOperationException expected) {
   }
   try {
     constrained
         .entries()
         .addAll(Arrays.asList(Maps.immutableEntry("foo", 1), Maps.immutableEntry(TEST_KEY, 2)));
     fail("UnsupportedOperationException expected");
   } catch (UnsupportedOperationException expected) {
   }
   assertTrue(multimap.isEmpty());
   assertTrue(constrained.isEmpty());
   constrained.put("foo", 1);
   try {
     constrained.asMap().get("foo").add(TEST_VALUE);
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   try {
     constrained.asMap().values().iterator().next().add(TEST_VALUE);
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   try {
     ((Collection<Integer>) constrained.asMap().values().toArray()[0]).add(TEST_VALUE);
     fail("TestValueException expected");
   } catch (TestValueException expected) {
   }
   ASSERT
       .that(ImmutableList.copyOf(multimap.entries()))
       .is(ImmutableList.copyOf(constrained.entries()));
   assertEquals(multimap.asMap(), constrained.asMap());
   assertEquals(multimap.values(), constrained.values());
   assertEquals(multimap.keys(), constrained.keys());
   assertEquals(multimap.keySet(), constrained.keySet());
   assertEquals(multimap.toString(), constrained.toString());
   assertEquals(multimap.hashCode(), constrained.hashCode());
 }