org.javimmutable.collections.util.RandomLoop Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javimmutable-collections Show documentation
Show all versions of javimmutable-collections Show documentation
Library providing immutable/persistent collection classes for
Java. While collections are immutable they provide methods for
adding and removing values by creating new modified copies of
themselves. Each copy shares almost all of its structure with
other copies to minimize memory consumption.
///###////////////////////////////////////////////////////////////////////////
//
// Burton Computer Corporation
// http://www.burton-computer.com
//
// Copyright (c) 2014, Burton Computer Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
//
// Neither the name of the Burton Computer Corporation nor the names
// of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package org.javimmutable.collections.util;
import org.javimmutable.collections.JImmutableArray;
import org.javimmutable.collections.JImmutableList;
import org.javimmutable.collections.JImmutableMap;
import org.javimmutable.collections.JImmutableRandomAccessList;
import org.javimmutable.collections.JImmutableSet;
import org.javimmutable.collections.JImmutableStack;
import org.javimmutable.collections.Sequence;
import javax.annotation.Nonnull;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;
/**
* Test program to run an infinite loop feeding data to a PersistentMap, querying the
* data, and deleting the data to verify the map always contains what it should.
*/
public class RandomLoop
{
private static class MapFactory
{
private int count;
private JImmutableMap createMap()
{
count += 1;
if (count % 2 == 0) {
return JImmutables.map();
} else {
return JImmutables.sortedMap();
}
}
}
public void execute(String[] filenames)
throws Exception
{
MapFactory factory = new MapFactory();
long seed = System.currentTimeMillis();
System.out.printf("Starting with initial seed %d%n", seed);
Random random = new Random(seed);
JImmutableList tokens = loadTokens(filenames);
System.out.printf("Loaded %d tokens from %d files%n", tokens.size(), filenames.length);
//noinspection InfiniteLoopStatement
while (true) {
testStack(random);
testList(random);
testRandomAccessList(random);
testSets(tokens, random);
testMaps(factory, tokens, random);
testBadHashMap(tokens, random);
testComparableBadHashMap(tokens, random);
testArray(tokens, random);
}
}
public static void main(String[] argv)
throws Exception
{
new RandomLoop().execute(argv);
}
private void testStack(Random random)
{
JImmutableStack stack = JImmutables.stack();
LinkedList expected = new LinkedList();
int size = random.nextInt(1000);
System.out.printf("Testing PersistentStack of size %d%n", size);
for (int i = 0; i < size; ++i) {
int value = random.nextInt(999999999);
stack = stack.insert(value);
expected.add(0, value);
}
Sequence seq = stack;
for (Integer value : expected) {
if (!value.equals(seq.getHead())) {
throw new RuntimeException(String.format("found mismatch expected %d found %d", value, seq.getHead()));
}
seq = seq.getTail();
}
if (!seq.isEmpty()) {
throw new RuntimeException("expected to be at end of stack but found more values");
}
System.out.println("PersistentStack test completed without errors");
}
private void testList(Random random)
{
JImmutableList list = JImmutables.list();
ArrayList expected = new ArrayList();
int size = random.nextInt(10000);
System.out.printf("Testing PersistentList of size %d%n", size);
for (int loops = 1; loops <= 6; ++loops) {
System.out.printf("growing %d%n", list.size());
for (int i = 0; i < size / 3; ++i) {
int value = random.nextInt(999999999);
switch (random.nextInt(3)) {
case 0:
list = list.insert(value);
expected.add(value);
break;
case 1:
list = list.insertLast(value);
expected.add(value);
break;
case 2:
list = list.insertFirst(value);
expected.add(0, value);
break;
default:
throw new RuntimeException();
}
}
verifyContents(expected, list);
System.out.printf("shrinking %d%n", list.size());
for (int i = 0; i < size / 6; ++i) {
if (random.nextInt(2) == 0) {
list = list.deleteLast();
expected.remove(expected.size() - 1);
} else {
list = list.deleteFirst();
expected.remove(0);
}
}
verifyContents(expected, list);
}
System.out.printf("cleanup %d%n", expected.size());
while (list.size() > 0) {
list = list.deleteLast();
expected.remove(expected.size() - 1);
}
verifyContents(expected, list);
System.out.println("PersistentList test completed without errors");
}
private void testRandomAccessList(Random random)
{
JImmutableRandomAccessList list = JImmutables.ralist();
ArrayList expected = new ArrayList();
int size = random.nextInt(10000);
System.out.printf("Testing PersistentRandomAccessList of size %d%n", size);
for (int loops = 1; loops <= 6; ++loops) {
System.out.printf("growing %d%n", list.size());
for (int i = 0; i < size / 3; ++i) {
int value = random.nextInt(999999999);
if (list.isEmpty()) {
list = list.insert(value);
expected.add(value);
} else {
switch (random.nextInt(8)) {
case 0:
list = list.insert(value);
expected.add(value);
break;
case 1:
list = list.insertLast(value);
expected.add(value);
break;
case 2:
list = list.insertFirst(value);
expected.add(0, value);
break;
default:
int index = random.nextInt(list.size());
list = list.insert(index, value);
expected.add(index, value);
break;
}
}
}
verifyContents(expected, list);
System.out.printf("shrinking %d%n", list.size());
for (int i = 0; i < size / 6; ++i) {
if (list.size() == 1) {
list = list.deleteLast();
expected.remove(expected.size() - 1);
} else {
switch (random.nextInt(8)) {
case 0:
list = list.deleteLast();
expected.remove(expected.size() - 1);
break;
case 1:
list = list.deleteFirst();
expected.remove(0);
break;
default:
int index = random.nextInt(list.size());
list = list.delete(index);
expected.remove(index);
}
}
}
verifyContents(expected, list);
}
System.out.printf("cleanup %d%n", expected.size());
while (list.size() > 0) {
list = list.delete(0);
expected.remove(0);
}
verifyContents(expected, list);
System.out.println("PersistentRandomAccessList test completed without errors");
}
private void testSets(JImmutableList tokens,
Random random)
{
JImmutableSet hset = JImmutables.set();
JImmutableSet tset = JImmutables.sortedSet();
Set expected = new HashSet();
int size = random.nextInt(100000);
JImmutableRandomAccessList values = JImmutables.ralist();
System.out.printf("Testing PersistentSet of size %d%n", size);
for (int loops = 1; loops <= 6; ++loops) {
System.out.printf("growing %d%n", hset.size());
for (int i = 0; i < size / 3; ++i) {
String value = makeKey(tokens, random);
values = values.insert(value);
hset = hset.insert(value);
tset = tset.insert(value);
expected.add(value);
}
verifyContents(expected, hset);
verifyContents(expected, tset);
System.out.printf("shrinking %d%n", hset.size());
for (int i = 0; i < size / 6; ++i) {
int keyIndex = random.nextInt(values.size());
String key = values.get(keyIndex);
expected.remove(key);
hset = hset.delete(key);
tset = tset.delete(key);
values = values.delete(keyIndex);
}
verifyContents(expected, hset);
verifyContents(expected, tset);
}
System.out.printf("cleanup %d%n", expected.size());
while (values.size() > 0) {
String value = values.get(0);
hset = hset.delete(value);
tset = tset.delete(value);
expected.remove(value);
values = values.delete(0);
}
verifyContents(expected, hset);
verifyContents(expected, tset);
System.out.println("PersistentSet test completed without errors");
}
private void testMaps(MapFactory factory,
JImmutableList tokens,
Random random)
{
final int tokenCount = 1 + random.nextInt(100000);
final List keys = new ArrayList();
final Map expected = new HashMap();
JImmutableMap map = factory.createMap();
JImmutableRandomAccessList pkeys = JImmutables.ralist();
System.out.printf("starting %s test with %d tokens and factory %s%n", map.getClass().getSimpleName(), tokenCount, map.getClass().getSimpleName());
for (int loops = 1; loops <= 6; ++loops) {
System.out.printf("growing %d%n", map.size());
for (int i = 0; i < tokenCount / 3; ++i) {
String key = makeKey(tokens, random);
keys.add(key);
pkeys = pkeys.insert(key);
expected.put(key, key);
map = map.assign(key, key);
}
verifyContents(expected, map);
System.out.printf("updating %d%n", map.size());
for (int i = 0; i < map.size(); ++i) {
int keyIndex = random.nextInt(keys.size());
String key = pkeys.get(keyIndex);
int valueIndex = random.nextInt(keys.size());
String value = pkeys.get(valueIndex);
expected.put(key, value);
map = map.assign(key, value);
}
verifyContents(expected, map);
System.out.printf("shrinking %d%n", map.size());
for (int i = 0; i < tokenCount / 6; ++i) {
int keyIndex = random.nextInt(keys.size());
String key = pkeys.get(keyIndex);
expected.remove(key);
map = map.delete(key);
keys.remove(keyIndex);
pkeys = pkeys.delete(keyIndex);
}
verifyContents(expected, map);
}
if (keys.size() != pkeys.size()) {
throw new RuntimeException(String.format("key size mismatch - expected %d found %d%n", keys.size(), pkeys.size()));
}
System.out.printf("comparing %d keys%n", pkeys.size());
for (int i = 0; i < pkeys.size(); ++i) {
String key = keys.get(i);
String pkey = pkeys.get(i);
if (!key.equals(pkey)) {
throw new RuntimeException(String.format("key mismatch - expected %s found %s%n", key, pkey));
}
}
System.out.printf("cleanup %d%n", map.size());
for (String key : keys) {
expected.remove(key);
map = map.delete(key);
}
if (map.size() != 0) {
throw new RuntimeException(String.format("expected map to be empty but it contained %d keys%n", map.size()));
}
verifyContents(expected, map);
System.out.printf("completed %s test without errors%n", map.getClass().getSimpleName());
}
private void testArray(JImmutableList tokens,
Random random)
{
final int tokenCount = 1 + random.nextInt(100000);
final List keys = new ArrayList();
final Map expected = new HashMap();
JImmutableArray map = JImmutables.array();
JImmutableRandomAccessList pkeys = JImmutables.ralist();
JImmutableRandomAccessList pvalues = JImmutables.ralist();
System.out.printf("starting %s test with %d tokens and factory %s%n", map.getClass().getSimpleName(), tokenCount, map.getClass().getSimpleName());
for (int loops = 1; loops <= 6; ++loops) {
System.out.printf("growing %d%n", map.size());
for (int i = 0; i < tokenCount / 3; ++i) {
int key = random.nextInt();
String value = makeKey(tokens, random);
keys.add(key);
pkeys = pkeys.insert(key);
pvalues = pvalues.insert(value);
expected.put(key, value);
map = map.assign(key, value);
}
verifyContents(expected, map);
System.out.printf("updating %d%n", map.size());
for (int i = 0; i < map.size(); ++i) {
int keyIndex = random.nextInt(keys.size());
int key = pkeys.get(keyIndex);
int valueIndex = random.nextInt(keys.size());
String value = pvalues.get(valueIndex);
expected.put(key, value);
pvalues = pvalues.assign(keyIndex, value);
map = map.assign(key, value);
}
verifyContents(expected, map);
System.out.printf("shrinking %d%n", map.size());
for (int i = 0; i < tokenCount / 6; ++i) {
int keyIndex = random.nextInt(keys.size());
int key = pkeys.get(keyIndex);
expected.remove(key);
map = map.delete(key);
keys.remove(keyIndex);
pkeys = pkeys.delete(keyIndex);
pvalues = pvalues.delete(keyIndex);
}
verifyContents(expected, map);
}
if (keys.size() != pkeys.size()) {
throw new RuntimeException(String.format("key size mismatch - expected %d found %d%n", keys.size(), pkeys.size()));
}
System.out.printf("comparing %d keys%n", pkeys.size());
for (int i = 0; i < pkeys.size(); ++i) {
int key = keys.get(i);
int pkey = pkeys.get(i);
if (key != pkey) {
throw new RuntimeException(String.format("key mismatch - expected %s found %s%n", key, pkey));
}
}
System.out.printf("cleanup %d%n", map.size());
for (Integer key : keys) {
expected.remove(key);
map = map.delete(key);
}
if (map.size() != 0) {
throw new RuntimeException(String.format("expected map to be empty but it contained %d keys%n", map.size()));
}
verifyContents(expected, map);
System.out.printf("completed %s test without errors%n", map.getClass().getSimpleName());
}
private void testBadHashMap(JImmutableList tokens,
Random random)
{
final int tokenCount = 1 + random.nextInt(100000);
final List> keys = new ArrayList>();
final Map, String> expected = new HashMap, String>();
JImmutableMap, String> map = JImmutables.map();
JImmutableRandomAccessList> pkeys = JImmutables.ralist();
System.out.printf("starting %s BadHash test with %d tokens and factory %s%n", map.getClass().getSimpleName(), tokenCount, map.getClass().getSimpleName());
for (int loops = 1; loops <= 6; ++loops) {
System.out.printf("growing %d%n", map.size());
for (int i = 0; i < tokenCount / 3; ++i) {
BadHash key = new BadHash(makeKey(tokens, random));
keys.add(key);
pkeys = pkeys.insert(key);
expected.put(key, key.value);
map = map.assign(key, key.value);
}
verifyContents(expected, map);
System.out.printf("updating %d%n", map.size());
for (int i = 0; i < map.size(); ++i) {
int keyIndex = random.nextInt(keys.size());
BadHash key = pkeys.get(keyIndex);
int valueIndex = random.nextInt(keys.size());
String value = pkeys.get(valueIndex).value;
expected.put(key, value);
map = map.assign(key, value);
}
verifyContents(expected, map);
System.out.printf("shrinking %d%n", map.size());
for (int i = 0; i < tokenCount / 6; ++i) {
int keyIndex = random.nextInt(keys.size());
BadHash key = pkeys.get(keyIndex);
expected.remove(key);
map = map.delete(key);
keys.remove(keyIndex);
pkeys = pkeys.delete(keyIndex);
}
verifyContents(expected, map);
}
if (keys.size() != pkeys.size()) {
throw new RuntimeException(String.format("key size mismatch - expected %d found %d%n", keys.size(), pkeys.size()));
}
System.out.printf("comparing %d keys%n", pkeys.size());
for (int i = 0; i < pkeys.size(); ++i) {
BadHash key = keys.get(i);
BadHash pkey = pkeys.get(i);
if (!key.equals(pkey)) {
throw new RuntimeException(String.format("key mismatch - expected %s found %s%n", key, pkey));
}
}
System.out.printf("cleanup %d%n", map.size());
for (BadHash key : keys) {
expected.remove(key);
map = map.delete(key);
}
if (map.size() != 0) {
throw new RuntimeException(String.format("expected map to be empty but it contained %d keys%n", map.size()));
}
verifyContents(expected, map);
System.out.printf("completed %s test without errors%n", map.getClass().getSimpleName());
}
private void testComparableBadHashMap(JImmutableList tokens,
Random random)
{
final int tokenCount = 1 + random.nextInt(100000);
final List> keys = new ArrayList>();
final Map, String> expected = new HashMap, String>();
JImmutableMap, String> map = JImmutables.map();
JImmutableRandomAccessList> pkeys = JImmutables.ralist();
System.out.printf("starting %s ComparableBadHash test with %d tokens and factory %s%n", map.getClass().getSimpleName(), tokenCount, map.getClass().getSimpleName());
for (int loops = 1; loops <= 6; ++loops) {
System.out.printf("growing %d%n", map.size());
for (int i = 0; i < tokenCount / 3; ++i) {
ComparableBadHash key = new ComparableBadHash(makeKey(tokens, random));
keys.add(key);
pkeys = pkeys.insert(key);
expected.put(key, key.value);
map = map.assign(key, key.value);
}
verifyContents(expected, map);
System.out.printf("updating %d%n", map.size());
for (int i = 0; i < map.size(); ++i) {
int keyIndex = random.nextInt(keys.size());
ComparableBadHash key = pkeys.get(keyIndex);
int valueIndex = random.nextInt(keys.size());
String value = pkeys.get(valueIndex).value;
expected.put(key, value);
map = map.assign(key, value);
}
verifyContents(expected, map);
System.out.printf("shrinking %d%n", map.size());
for (int i = 0; i < tokenCount / 6; ++i) {
int keyIndex = random.nextInt(keys.size());
ComparableBadHash key = pkeys.get(keyIndex);
expected.remove(key);
map = map.delete(key);
keys.remove(keyIndex);
pkeys = pkeys.delete(keyIndex);
}
verifyContents(expected, map);
}
if (keys.size() != pkeys.size()) {
throw new RuntimeException(String.format("key size mismatch - expected %d found %d%n", keys.size(), pkeys.size()));
}
System.out.printf("comparing %d keys%n", pkeys.size());
for (int i = 0; i < pkeys.size(); ++i) {
ComparableBadHash key = keys.get(i);
ComparableBadHash pkey = pkeys.get(i);
if (!key.equals(pkey)) {
throw new RuntimeException(String.format("key mismatch - expected %s found %s%n", key, pkey));
}
}
System.out.printf("cleanup %d%n", map.size());
for (ComparableBadHash key : keys) {
expected.remove(key);
map = map.delete(key);
}
if (map.size() != 0) {
throw new RuntimeException(String.format("expected map to be empty but it contained %d keys%n", map.size()));
}
verifyContents(expected, map);
System.out.printf("completed %s test without errors%n", map.getClass().getSimpleName());
}
private void verifyContents(List expected,
JImmutableList list)
{
System.out.printf("checking contents with size %d%n", list.size());
if (list.size() != expected.size()) {
throw new RuntimeException(String.format("size mismatch - expected %d found %d", expected.size(), list.size()));
}
int index = 0;
for (Integer expectedValue : expected) {
Integer listValue = list.get(index);
if (!expectedValue.equals(listValue)) {
throw new RuntimeException(String.format("value mismatch - expected %d found %d%n", expectedValue, listValue));
}
index += 1;
}
index = 0;
for (Integer listValue : list) {
Integer expectedValue = expected.get(index);
if (!expectedValue.equals(listValue)) {
throw new RuntimeException(String.format("value mismatch - expected %d found %d%n", expectedValue, listValue));
}
index += 1;
}
}
private void verifyContents(Set expected,
JImmutableSet set)
{
System.out.printf("checking contents with size %d%n", set.size());
if (set.size() != expected.size()) {
throw new RuntimeException(String.format("size mismatch - expected %d found %d", expected.size(), set.size()));
}
for (String expectedValue : expected) {
if (!set.contains(expectedValue)) {
throw new RuntimeException(String.format("value mismatch - expected %s but not in %s%n", expectedValue, set.getClass().getSimpleName()));
}
}
for (String expectedValue : set) {
if (!expected.contains(expectedValue)) {
throw new RuntimeException(String.format("value mismatch - expected %s but not in Set%n", expectedValue));
}
}
}
private void verifyContents(Map expected,
JImmutableMap map)
{
System.out.printf("checking contents with size %d%n", map.size());
if (map.size() != expected.size()) {
throw new RuntimeException(String.format("size mismatch - expected %d found %d", expected.size(), map.size()));
}
for (JImmutableMap.Entry entry : map) {
V mapValue = map.find(entry.getKey()).getValueOrNull();
V expectedValue = expected.get(entry.getKey());
if (!mapValue.equals(expectedValue)) {
throw new RuntimeException(String.format("value mismatch - expected %s found %s%n", expectedValue, mapValue));
}
}
for (Map.Entry entry : expected.entrySet()) {
V mapValue = map.find(entry.getKey()).getValueOrNull();
V expectedValue = expected.get(entry.getKey());
if (!mapValue.equals(expectedValue)) {
throw new RuntimeException(String.format("value mismatch - expected %s found %s%n", expectedValue, mapValue));
}
}
}
private void verifyContents(Map expected,
JImmutableArray map)
{
System.out.printf("checking contents with size %d%n", map.size());
if (map.size() != expected.size()) {
throw new RuntimeException(String.format("size mismatch - expected %d found %d", expected.size(), map.size()));
}
for (JImmutableMap.Entry entry : map) {
V mapValue = map.find(entry.getKey()).getValueOrNull();
V expectedValue = expected.get(entry.getKey());
if (!mapValue.equals(expectedValue)) {
throw new RuntimeException(String.format("value mismatch - expected %s found %s%n", expectedValue, mapValue));
}
}
for (Map.Entry entry : expected.entrySet()) {
V mapValue = map.find(entry.getKey()).getValueOrNull();
V expectedValue = expected.get(entry.getKey());
if (!mapValue.equals(expectedValue)) {
throw new RuntimeException(String.format("value mismatch - expected %s found %s%n", expectedValue, mapValue));
}
}
}
private String makeKey(JImmutableList tokens,
Random random)
{
int length = 1 + random.nextInt(250);
StringBuilder sb = new StringBuilder();
while (sb.length() < length) {
sb.append(tokens.get(random.nextInt(tokens.size())));
}
return sb.toString();
}
private JImmutableList loadTokens(String[] filenames)
throws IOException
{
JImmutableSet tokens = JImmutables.set();
for (String filename : filenames) {
tokens = addTokensFromFile(tokens, filename);
}
return JImmutables.list(tokens);
}
private JImmutableSet addTokensFromFile(JImmutableSet tokens,
String filename)
throws IOException
{
BufferedReader inp = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "UTF-8"));
try {
for (String line = inp.readLine(); line != null; line = inp.readLine()) {
StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens()) {
tokens = tokens.insert(tokenizer.nextToken());
}
}
} finally {
inp.close();
}
return tokens;
}
@SuppressWarnings("unchecked")
private static class BadHash
{
private final T value;
private BadHash(T value)
{
this.value = value;
}
@Override
public int hashCode()
{
return value.hashCode() >>> 8;
}
@Override
public boolean equals(Object o)
{
return (o instanceof BadHash) && value.equals(((BadHash)o).value);
}
}
@SuppressWarnings("unchecked")
private static class ComparableBadHash>
implements Comparable>
{
private final T value;
private ComparableBadHash(T value)
{
this.value = value;
}
@Override
public int hashCode()
{
return value.hashCode() >>> 8;
}
@Override
public boolean equals(Object o)
{
return (o instanceof ComparableBadHash) && value.equals(((ComparableBadHash)o).value);
}
@Override
public int compareTo(@Nonnull ComparableBadHash other)
{
return value.compareTo(other.value);
}
}
}