### Question:
HashObjectFunnels { public static Funnel<RevTree> treeFunnel() { return TreeFunnel.INSTANCE; }  static Funnel<RevCommit> commitFunnel(); static Funnel<RevTree> treeFunnel(); static Funnel<Object> valueFunnel(); static Funnel<RevFeature> featureFunnel(); static Funnel<RevTag> tagFunnel(); static Funnel<RevFeatureType> featureTypeFunnel(); static void feature(@NonNull PrimitiveSink into, @NonNull List<Object> values); static void tree(@NonNull PrimitiveSink into, @NonNull List<Node> trees,
            @NonNull List<Node> features, @NonNull Iterable<Bucket> buckets); static ObjectId hashTag(@NonNull String name, @NonNull ObjectId commitId,
            @NonNull String message, @NonNull RevPerson tagger); static ObjectId hashFeature(@NonNull List<Object> values); static ObjectId hashCommit(@NonNull ObjectId treeId, @NonNull List<ObjectId> parentIds,
            @NonNull RevPerson author, @NonNull RevPerson committer,
            @NonNull String commitMessage); static ObjectId hashFeatureType(@NonNull FeatureType featureType); static ObjectId hashTree(@Nullable List<Node> trees, @Nullable List<Node> features,
            @Nullable Iterable<Bucket> buckets); static ObjectId hashValue(@Nullable Object value); static ObjectId hashObject(@NonNull RevObject o); static void tag(@NonNull PrimitiveSink into, @NonNull String name,
            @NonNull ObjectId commitId, @NonNull String message, @NonNull RevPerson tagger); static void featureType(@NonNull PrimitiveSink into, @NonNull FeatureType featureType); static void commit(@NonNull PrimitiveSink into, @NonNull ObjectId treeId,
            @NonNull List<ObjectId> parentIds, @NonNull RevPerson author,
            @NonNull RevPerson committer, @NonNull String commitMessage);  }### Answer:
@Test public void testTreeFunnel() { SortedMap<Integer, Bucket> buckets = new TreeMap<Integer, Bucket>(); List<Node> trees = new LinkedList<Node>(); List<Node> features = new LinkedList<Node>(); final Node testNode = RevObjectFactory.defaultInstance().createNode("Points", ObjectId.valueOf("abc123000000000000001234567890abcdef0001"), ObjectId.NULL, TYPE.TREE, null, null); final Bucket testBucket = RevObjectFactory.defaultInstance().createBucket( ObjectId.valueOf("abc123000000000000001234567890abcdef0002"), 0, new Envelope(0, 0, 1, 1)); RevTree testTree = new RevTree() { public @Override TYPE getType() { return RevObject.TYPE.TREE; } public @Override ObjectId getId() { return oid1; } public @Override long size() { return 0; } public @Override int numTrees() { return trees.size(); } public @Override List<Node> trees() { return ImmutableList.copyOf(trees); } public @Override List<Node> features() { return ImmutableList.copyOf(features); } public @Override Iterable<Bucket> getBuckets() { return buckets.values(); } }; Funnel<RevTree> treeFunnel = HashObjectFunnels.treeFunnel(); Hasher hasher = ObjectId.HASH_FUNCTION.newHasher(); treeFunnel.funnel(testTree, hasher); byte[] rawKey = hasher.hash().asBytes(); assertEquals(ObjectId.NUM_BYTES, rawKey.length); ObjectId id1 = ObjectId.create(rawKey); trees.add(testNode); features.add(testNode); buckets.put(0, testBucket); hasher = ObjectId.HASH_FUNCTION.newHasher(); treeFunnel.funnel(testTree, hasher); rawKey = hasher.hash().asBytes(); assertEquals(ObjectId.NUM_BYTES, rawKey.length); ObjectId id2 = ObjectId.create(rawKey); assertNotSame(id1, id2); ObjectId treeHash = HashObjectFunnels.hashTree(trees, features, buckets.values()); assertEquals(treeHash, id2); ObjectId treeHash2 = HashObjectFunnels.hashTree(null, null, (Iterable<Bucket>) null); assertEquals(treeHash2, id1); }