package net.ranides.assira.collection.query.base;

import lombok.RequiredArgsConstructor;
import net.ranides.test.CQueryAssert;
import org.junit.Test;

import net.ranides.assira.collection.iterators.SpliteratorUtils;
import net.ranides.assira.collection.lists.IntRange;
import net.ranides.assira.collection.query.CQuery;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;

import static org.junit.Assert.*;

public class CQSpliteratorTest {

    @Test
    public void basic() {
        List<Integer> input = Arrays.asList(1, 2, 3, 4, 5);
        CQuery<Integer> query = CQSpliterator.from(true, () -> input.spliterator());

        CQueryAssert.assertEquals(input, query);
    }

    @Test
    public void paralellEach() {
        List<Integer> range = new ArrayList<>(new IntRange(0, 50));
        CQueryAssert.assertOrderedParallel(CQSpliterator.from(true, () -> range.spliterator()));

        CQueryAssert.assertUnorderedParallel(CQSpliterator.from(true, () -> {
            return new NotSizedSpliterator<>(range.spliterator());
        }));
    }

    @RequiredArgsConstructor
    private static class NotSizedSpliterator<T> implements Spliterator<T> {

        private final Spliterator<T> source;

        @Override
        public boolean tryAdvance(Consumer<? super T> action) {
            return source.tryAdvance(action);
        }

        @Override
        public Spliterator<T> trySplit() {
            Spliterator<T> out = source.trySplit();
            return out !=null ? new NotSizedSpliterator<>(out) : null;
        }

        @Override
        public long estimateSize() {
            return Long.MAX_VALUE;
        }

        @Override
        public int characteristics() {
            return source.characteristics() & ~(SIZED | SUBSIZED);
        }


    }
}