/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.server.store.statistics.histograms; import com.foundationdb.util.AssertUtils; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import static org.junit.Assert.assertEquals; public final class SplitHandlerTest { @Test public void singleStream() { List<String> inputs = Arrays.asList( "one", "one", "two", "three", "three", "three" ); List<SplitPair> onlyStream = Arrays.asList( new SplitPair("one", 2), new SplitPair("two", 1), new SplitPair("three", 3) ); List<List<SplitPair>> expected = Collections.singletonList(onlyStream); List<List<SplitPair>> actual = run(new BucketTestUtils.SingletonSplitter<String>(), inputs); AssertUtils.assertCollectionEquals("single stream", expected, actual); } @Test public void twoStreamsSameLength() { List<String> inputs = Arrays.asList( "one a", "one a", "two b", "three c", "three c", "three c" ); List<SplitPair> firstStream = Arrays.asList( new SplitPair("one", 2), new SplitPair("two", 1), new SplitPair("three", 3) ); List<SplitPair> secondStream = Arrays.asList( new SplitPair("a", 2), new SplitPair("b", 1), new SplitPair("c", 3) ); Splitter<String> splitter = new Splitter<String>() { @Override public int segments() { return 2; } @Override public List<? extends String> split(String input) { return Arrays.asList(input.split(" ")); } }; List<List<SplitPair>> expected = new ArrayList<>(); expected.add(firstStream); expected.add(secondStream); List<List<SplitPair>> actual = run(splitter, inputs); AssertUtils.assertCollectionEquals("single stream", expected, actual); } @Test public void twoStreamsDifferentLength() { List<String> inputs = Arrays.asList( "one a", "one a", "two a", "three c", "three c", "three c" ); List<SplitPair> firstStream = Arrays.asList( new SplitPair("one", 2), new SplitPair("two", 1), new SplitPair("three", 3) ); List<SplitPair> secondStream = Arrays.asList( new SplitPair("a", 3), new SplitPair("c", 3) ); Splitter<String> splitter = new Splitter<String>() { @Override public int segments() { return 2; } @Override public List<? extends String> split(String input) { return Arrays.asList(input.split(" ")); } }; List<List<SplitPair>> expected = new ArrayList<>(); expected.add(firstStream); expected.add(secondStream); List<List<SplitPair>> actual = run(splitter, inputs); AssertUtils.assertCollectionEquals("single stream", expected, actual); } @Test public void noInputs() { ToArraySplitHandler handler = new ToArraySplitHandler(new BucketTestUtils.SingletonSplitter<String>()); handler.init(); handler.finish(); List<List<SplitPair>> actual = handler.splitPairStreams; List<SplitPair> emptyStream = Collections.emptyList(); assertEquals("empty input results", Collections.singletonList(emptyStream), actual); } @Test(expected = IllegalStateException.class) public void visitBeforeInit() { ToArraySplitHandler handler = new ToArraySplitHandler(new BucketTestUtils.SingletonSplitter<String>()); handler.visit("foo"); } @Test(expected = IllegalStateException.class) public void finishBeforeInit() { ToArraySplitHandler handler = new ToArraySplitHandler(new BucketTestUtils.SingletonSplitter<String>()); handler.finish(); } @Test(expected = IllegalStateException.class) public void mismatchedSegmentsCount() { Splitter<String> splitter = new Splitter<String>() { @Override public int segments() { return 1; // lie! we'll be returning a list of size 2 } @Override public List<? extends String> split(String input) { return Arrays.asList(input.split(" ")); } }; ToArraySplitHandler handler = new ToArraySplitHandler(splitter); handler.init(); handler.visit("one two"); } private List<List<SplitPair>> run(Splitter<String> splitter, List<String> inputs) { ToArraySplitHandler handler = new ToArraySplitHandler(splitter); handler.init(); for (String input : inputs) { handler.visit(input); } handler.finish(); return handler.splitPairStreams; } private static class ToArraySplitHandler extends SplitHandler<String> { @Override protected void handle(int segmentIndex, String input, int count) { SplitPair splitPair = new SplitPair(input, count); List<SplitPair> stream = splitPairStreams.get(segmentIndex); stream.add(splitPair); } private ToArraySplitHandler(Splitter<String> objectSplitter) { super(objectSplitter); int segments = objectSplitter.segments(); splitPairStreams = new ArrayList<>(segments); for (int i = 0; i < segments; ++i) { splitPairStreams.add(new ArrayList<SplitPair>()); } } final List<List<SplitPair>> splitPairStreams; } private static class SplitPair { private SplitPair(Object value, int count) { this.value = value; this.count = count; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SplitPair splitPair = (SplitPair) o; return count == splitPair.count && value.equals(splitPair.value); } @Override public int hashCode() { int result = value.hashCode(); result = 31 * result + count; return result; } @Override public String toString() { return String.format("(%s)x%d", value, count); } final Object value; final int count; } }