content: /*
   * Copyright 2015, 2024 StreamEx contributors
   *
   * 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 one.util.streamex;
  
  import org.junit.Test;
  
  import java.util.*;
  import java.util.stream.Collectors;
  import java.util.stream.IntStream;
  
  import static org.junit.Assert.assertArrayEquals;
  import static org.junit.Assert.assertEquals;
  
  /**
   * @author Tagir Valeev
   */
  public class LimiterTest {
      @Test
      public void testLimiter() {
          Comparator<String> cmp = Comparator.nullsFirst(Comparator.comparingInt(String::length));
          exerciseLimiter("str", Arrays.asList("abc", "abgdc", "abd", "a", "fgssdfg", "sfsvsx", null, "wrffvs",
              "xcvbxvcb", "sffg", "abe", "adf", "abh"), cmp);
          for (int i : new int[] { 10, 100, 1000, 10000, 100000 }) {
              List<Integer> ascending = IntStream.range(0, i).boxed().collect(Collectors.toList());
              exerciseLimiter("asc, nat, " + i, ascending, Comparator.naturalOrder());
              exerciseLimiter("asc, dec, " + i, ascending, Comparator.comparingInt(x -> x / 10));
              List<Integer> descending = IntStream.range(0, i).mapToObj(x -> ~x).collect(Collectors.toList());
              exerciseLimiter("desc, nat, " + i, descending, Comparator.naturalOrder());
              exerciseLimiter("desc, dec, " + i, descending, Comparator.comparingInt(x -> x / 10));
              List<Integer> random = new Random(1).ints(i).boxed().collect(Collectors.toList());
              exerciseLimiter("rnd, nat, " + i, random, Comparator.naturalOrder());
              exerciseLimiter("rnd, dec, " + i, random, Comparator.comparingInt(x -> x / 10));
              List<Integer> randomRange = new Random(1).ints(i, -1000, 1000).boxed().collect(Collectors.toList());
              exerciseLimiter("rnd2, nat, " + i, randomRange, Comparator.naturalOrder());
              exerciseLimiter("rnd2, dec, " + i, randomRange, Comparator.comparingInt(x -> x / 10));
          }
          List<Integer> list = IntStreamEx.range(100000).boxed().toList();
          exerciseLimiter("big", list, list, 50000, Comparator.naturalOrder()); 
          exerciseLimiter("big", list, list, 49999, Comparator.naturalOrder()); 
          exerciseLimiter("big", list, list, 10000, Comparator.naturalOrder());
          exerciseLimiter("big", list, list, Integer.MAX_VALUE / 3, Comparator.naturalOrder());
          exerciseLimiter("big", list, list, Integer.MAX_VALUE / 2, Comparator.naturalOrder());
      }
  
      public static <T> void exerciseLimiter(String msg, Collection<T> input, Comparator<T> comp) {
          for (int limit : new int[] { 0, 1, 2, 5, 10, 20, 100, 1000 }) {
              List<T> expected = new ArrayList<>(input);
              expected.sort(comp);
              exerciseLimiter(msg, expected, input, limit, comp);
          }
      }
  
      public static <T> void exerciseLimiter(String msg, List<T> expected, Collection<T> input, int limit, Comparator<T> comp) {
          List<T> subList = limit >= expected.size() ? expected : expected.subList(0, limit);
          List<T> actual = input.stream().collect(MoreCollectors.least(comp, limit));
          assertEquals("Mismatch (sequential), " + msg + ", limit=" + limit, subList, actual);
          actual = input.parallelStream().collect(MoreCollectors.least(comp, limit));
          assertEquals("Mismatch (parallel), " + msg + ", limit=" + limit, subList, actual);
      }
      
      @Test
      public void testDirect() {
          Limiter<Integer> limiter = new Limiter<>(5, Comparator.naturalOrder());
          limiter.put(1);
          limiter.put(2);
          limiter.put(3);
          limiter.put(4);
          assertEquals(4, limiter.size());
          limiter.put(5);
          assertEquals(5, limiter.size());
          limiter.put(6);
          assertEquals(5, limiter.size());
          Iterator<Integer> iterator = limiter.iterator();
          assertEquals(Arrays.asList(1, 2, 3, 4, 5), StreamEx.of(iterator).toList());
      }
      
      @Test
      public void testDirectPutAll() {
          Limiter<Integer> limiter = new Limiter<>(3, Comparator.naturalOrder());
          Limiter<Integer> limiter2 = new Limiter<>(3, Comparator.naturalOrder());
          limiter.put(6);
          limiter.put(5);
          limiter.put(4);
          limiter2.put(3);
          limiter2.put(1);
          limiter2.put(0);
          Limiter<Integer> result = limiter.putAll(limiter2);
          result.put(2);
          result.sort();
          assertArrayEquals(new Object[] {0, 1, 2}, result.toArray());
      }
  }
  