/*
* Copyright 2013 Samppa Saarela
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.javersion.util;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.mutable.MutableLong;
import org.assertj.core.api.Assertions;
import org.javersion.util.PersistentHashMapTest.HashKey;
import org.junit.Test;
import com.google.common.collect.*;
public class PersistentHashSetTest {
public static final PersistentHashSet<Integer> SET;
static {
SET = new PersistentHashSet<Integer>().conjAll(integers());
}
static Set<Integer> integers() {
Random random = new Random(2004);
Set<Integer> set = Sets.newLinkedHashSet();
for (int i=1; i <= 257; i++) {
set.add(random.nextInt());
}
return set;
}
@Test
public void empty_set_contains() {
assertThat(new PersistentHashSet<Object>().contains("foo")).isFalse();
}
@Test
public void Set_Equals() {
assertThat(SET.asSet()).isEqualTo(integers());
}
@Test
public void Removal() {
MutableHashSet<Integer> set = SET.toMutableSet();
for (Integer e : set) {
set.remove(e);
}
assertThat(set.size()).isEqualTo(0);
}
@Test
public void Remove_Missing_Value() {
assertThat(SET.disj(123)).isSameAs(SET);
}
@Test
public void add_and_remove_all() {
PersistentHashSet<Integer> set = new PersistentHashSet<>();
Set<Integer> ints = integers();
set = set.conjAll(ints);
assertThat(set.asSet()).isEqualTo(ints);
set = set.disjAll(ints);
assertThat(set.asSet()).isEqualTo(new HashSet<>());
assertThat(set.size()).isEqualTo(0);
}
@Test
public void Add_Incremental() {
PersistentHashSet<Integer> set = new PersistentHashSet<>();
Set<Integer> ints = integers();
for (Integer integer : ints) {
set = set.conj(integer);
}
assertThat(set.asSet()).isEqualTo(ints);
}
@Test
public void reduce() {
PersistentHashSet<HashKey> set = new PersistentHashSet<>();
int sum=0;
int count=0;
// ArrayNode
for (int i=0; i < 32; i++) {
sum+=i;
count++;
set = set.conj(new HashKey(i));
}
// HashNode
for (int i=1; i < 5; i++) {
int num = i<<(4 + i);
sum+=num;
count++;
set = set.conj(new HashKey(num));
}
// CollisionNodes
set = set.conj(new HashKey(1));
sum+=1;
count++;
set = set.conj(new HashKey(1));
sum+=1;
count++;
assertThat(sumOf(set.stream())).isEqualTo(sum);
assertThat(set.stream().count()).isEqualTo(count);
assertThat(sumOf(set.parallelStream())).isEqualTo(sum);
assertThat(set.parallelStream().count()).isEqualTo(count);
// Reduce partially consumed in parallel
for (int i=1; i < set.size(); i++) {
Spliterator<HashKey> spliterator = set.spliterator();
final MutableInt partialSum = new MutableInt(0);
for (int j=0; j < i; j++) {
spliterator.tryAdvance(k -> partialSum.add(k.hash));
}
Assertions.assertThat(sumOf(StreamSupport.stream(spliterator, true)) + partialSum.intValue()).isEqualTo(sum);
}
}
@Test
public void split_till_the_end() {
PersistentHashSet<Integer> ints = new PersistentHashSet<Integer>().conjAll(integers());
List<Spliterator<Integer>> spliterators = new ArrayList<>();
spliterators.add(ints.spliterator());
int size = 0;
while(size != spliterators.size()) {
size = spliterators.size();
for (int i=size-1; i >= 0; i--) {
Spliterator<Integer> spliterator = spliterators.get(i);
Spliterator<Integer> split = spliterator.trySplit();
if (split != null) {
spliterators.add(split);
}
}
}
final MutableLong sum = new MutableLong(0);
for (Spliterator<Integer> spliterator : spliterators) {
while (spliterator.tryAdvance(i -> sum.add(i)));
}
Assertions.assertThat(sum.longValue()).isEqualTo(
ints.stream().map(Long::new).reduce(Long::sum).get());
}
@Test
public void try_split_single_entry() {
PersistentHashSet<Integer> set = new PersistentHashSet<Integer>().conj(5);
assertThat(set.spliterator().trySplit()).isNull();
Spliterator<Integer> spliterator = set.spliterator();
assertThat(spliterator.tryAdvance(i-> assertThat(i).isEqualTo(5) )).isTrue();
assertThat(spliterator.trySplit()).isNull();
}
@Test
public void try_split_sub_spliterator() {
PersistentHashSet<Integer> set = new PersistentHashSet<Integer>().conj(1).conj(33);
Spliterator<Integer> spliterator = set.spliterator();
assertThat(spliterator.tryAdvance(i-> assertThat(i).isEqualTo(1) )).isTrue();
assertThat(spliterator.trySplit()).isNull();
assertThat(spliterator.tryAdvance(i -> assertThat(i).isEqualTo(33))).isTrue();
assertThat(spliterator.tryAdvance(i -> {})).isFalse();
}
@Test
public void to_string() {
PersistentHashSet<Integer> set = new PersistentHashSet<Integer>();
assertThat(set.toString()).isEqualTo("[]");
set = set.conj(1);
assertThat(set.toString()).isEqualTo("[1]");
set = set.conj(2);
assertThat(set.toString()).isEqualTo("[1, 2]");
}
private int sumOf(Stream<HashKey> stream) {
return stream.map(Object::hashCode)
.reduce(Integer::sum).get();
}
@Test
public void empty_stream() {
assertThat(new PersistentHashSet<>().stream().count()).isEqualTo(0);
}
}