content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to you 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.apache.calcite.rel;
  
  import org.apache.calcite.util.ImmutableIntList;
  import org.apache.calcite.util.mapping.Mapping;
  import org.apache.calcite.util.mapping.Mappings;
  
  import com.google.common.collect.Lists;
  
  import org.junit.jupiter.api.Test;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  
  import static org.apache.calcite.rel.RelCollations.EMPTY;
  import static org.apache.calcite.rel.RelFieldCollation.Direction.ASCENDING;
  import static org.apache.calcite.rel.RelFieldCollation.Direction.CLUSTERED;
  import static org.apache.calcite.rel.RelFieldCollation.Direction.DESCENDING;
  import static org.apache.calcite.rel.RelFieldCollation.Direction.STRICTLY_ASCENDING;
  import static org.apache.calcite.rel.RelFieldCollation.Direction.STRICTLY_DESCENDING;
  
  import static org.hamcrest.CoreMatchers.equalTo;
  import static org.hamcrest.CoreMatchers.is;
  import static org.hamcrest.MatcherAssert.assertThat;
  
  /**
   * Tests for {@link RelCollation} and {@link RelFieldCollation}.
   */
  class RelCollationTest {
    /** Unit test for {@link RelCollations#contains(List, ImmutableIntList)}. */
    @SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
    @Test void testCollationContains() {
      final RelCollation collation21 =
          RelCollations.of(
              new RelFieldCollation(2, ASCENDING),
              new RelFieldCollation(1, DESCENDING));
      assertThat(RelCollations.contains(collation21, Arrays.asList(2)), is(true));
      assertThat(RelCollations.contains(collation21, Arrays.asList(1)),
          is(false));
      assertThat(RelCollations.contains(collation21, Arrays.asList(0)),
          is(false));
      assertThat(RelCollations.contains(collation21, Arrays.asList(2, 1)),
          is(true));
      assertThat(RelCollations.contains(collation21, Arrays.asList(2, 0)),
          is(false));
      assertThat(RelCollations.contains(collation21, Arrays.asList(2, 1, 3)),
          is(false));
      assertThat(RelCollations.contains(collation21, Arrays.asList()),
          is(true));
  
      // if there are duplicates in keys, later occurrences are ignored
      assertThat(RelCollations.contains(collation21, Arrays.asList(2, 1, 2)),
          is(true));
      assertThat(RelCollations.contains(collation21, Arrays.asList(2, 1, 1)),
          is(true));
      assertThat(RelCollations.contains(collation21, Arrays.asList(1, 2, 1)),
          is(false));
      assertThat(RelCollations.contains(collation21, Arrays.asList(1, 1)),
          is(false));
      assertThat(RelCollations.contains(collation21, Arrays.asList(2, 2)),
          is(true));
  
      final RelCollation collation1 =
          RelCollations.of(
              new RelFieldCollation(1, DESCENDING));
      assertThat(RelCollations.contains(collation1, Arrays.asList(1, 1)),
          is(true));
      assertThat(RelCollations.contains(collation1, Arrays.asList(2, 2)),
          is(false));
      assertThat(RelCollations.contains(collation1, Arrays.asList(1, 2, 1)),
          is(false));
      assertThat(RelCollations.contains(collation1, Arrays.asList()),
          is(true));
    }
  
    /** Unit test for {@link RelCollations#collationsContainKeysOrderless(List, List)}. */
    @Test void testCollationsContainKeysOrderless() {
      final List<RelCollation> collations = Lists.newArrayList(collation(2, 3, 1));
      assertThat(
          RelCollations.collationsContainKeysOrderless(
          collations, Arrays.asList(2, 2)), is(true));
      assertThat(
          RelCollations.collationsContainKeysOrderless(
          collations, Arrays.asList(2, 3)), is(true));
      assertThat(
          RelCollations.collationsContainKeysOrderless(
          collations, Arrays.asList(3, 2)), is(true));
      assertThat(
          RelCollations.collationsContainKeysOrderless(
          collations, Arrays.asList(3, 2, 1)), is(true));
      assertThat(
          RelCollations.collationsContainKeysOrderless(
          collations, Arrays.asList(3, 2, 1, 0)), is(false));
      assertThat(
          RelCollations.collationsContainKeysOrderless(
          collations, Arrays.asList(2, 3, 0)), is(false));
      assertThat(
          RelCollations.collationsContainKeysOrderless(
          collations, Arrays.asList(1)), is(false));
      assertThat(
          RelCollations.collationsContainKeysOrderless(
          collations, Arrays.asList(3, 1)), is(false));
      assertThat(
          RelCollations.collationsContainKeysOrderless(
          collations, Arrays.asList(0)), is(false));
    }
  
    /** Unit test for {@link RelCollations#keysContainCollationsOrderless(List, List)}. */
    @Test void testKeysContainCollationsOrderless() {
      final List<Integer> keys = Arrays.asList(2, 3, 1);
      assertThat(
          RelCollations.keysContainCollationsOrderless(
              keys, Lists.newArrayList(collation(2, 2))), is(true));
      assertThat(
          RelCollations.keysContainCollationsOrderless(
              keys, Lists.newArrayList(collation(2, 3))), is(true));
      assertThat(
          RelCollations.keysContainCollationsOrderless(
              keys, Lists.newArrayList(collation(3, 2))), is(true));
      assertThat(
          RelCollations.keysContainCollationsOrderless(
              keys, Lists.newArrayList(collation(3, 2, 1))), is(true));
      assertThat(
          RelCollations.keysContainCollationsOrderless(
              keys, Lists.newArrayList(collation(3, 2, 1, 0))), is(false));
      assertThat(
          RelCollations.keysContainCollationsOrderless(
              keys, Lists.newArrayList(collation(2, 3, 0))), is(false));
      assertThat(
          RelCollations.keysContainCollationsOrderless(
              keys, Lists.newArrayList(collation(1))), is(true));
      assertThat(
          RelCollations.keysContainCollationsOrderless(
              keys, Lists.newArrayList(collation(3, 1))), is(true));
      assertThat(
          RelCollations.keysContainCollationsOrderless(
              keys, Lists.newArrayList(collation(0))), is(false));
    }
  
    /**
     * Unit test for {@link org.apache.calcite.rel.RelCollationImpl#compareTo}.
     */
    @Test void testCollationCompare() {
      assertThat(collation(1, 2).compareTo(collation(1, 2)), equalTo(0));
      assertThat(collation(1, 2).compareTo(collation(1)), equalTo(1));
      assertThat(collation(1).compareTo(collation(1, 2)), equalTo(-1));
      assertThat(collation(1, 3).compareTo(collation(1, 2)), equalTo(1));
      assertThat(collation(0, 3).compareTo(collation(1, 2)), equalTo(-1));
      assertThat(collation().compareTo(collation(0)), equalTo(-1));
      assertThat(collation(1).compareTo(collation()), equalTo(1));
    }
  
    @Test void testCollationMapping() {
      final int n = 10; // Mapping source count.
      // [0]
      RelCollation collation0 = collation(0);
      assertThat(collation0.apply(mapping(n, 0)), is(collation0));
      assertThat(collation0.apply(mapping(n, 1)), is(EMPTY));
      assertThat(collation0.apply(mapping(n, 0, 1)), is(collation0));
      assertThat(collation0.apply(mapping(n, 1, 0)), is(collation(1)));
      assertThat(collation0.apply(mapping(n, 3, 1, 0)), is(collation(2)));
  
      // [0,1]
      RelCollation collation01 = collation(0, 1);
      assertThat(collation01.apply(mapping(n, 0)), is(collation(0)));
      assertThat(collation01.apply(mapping(n, 1)), is(EMPTY));
      assertThat(collation01.apply(mapping(n, 2)), is(EMPTY));
      assertThat(collation01.apply(mapping(n, 0, 1)), is(collation01));
      assertThat(collation01.apply(mapping(n, 1, 0)), is(collation(1, 0)));
      assertThat(collation01.apply(mapping(n, 3, 1, 0)), is(collation(2, 1)));
      assertThat(collation01.apply(mapping(n, 3, 2, 0)), is(collation(2)));
  
      // [2,3,4]
      RelCollation collation234 = collation(2, 3, 4);
      assertThat(collation234.apply(mapping(n, 0)), is(EMPTY));
      assertThat(collation234.apply(mapping(n, 1)), is(EMPTY));
      assertThat(collation234.apply(mapping(n, 2)), is(collation(0)));
      assertThat(collation234.apply(mapping(n, 3)), is(EMPTY));
      assertThat(collation234.apply(mapping(n, 4)), is(EMPTY));
      assertThat(collation234.apply(mapping(n, 5)), is(EMPTY));
      assertThat(collation234.apply(mapping(n, 0, 1, 2)), is(collation(2)));
      assertThat(collation234.apply(mapping(n, 3, 2)), is(collation(1, 0)));
      assertThat(collation234.apply(mapping(n, 3, 2, 4)), is(collation(1, 0, 2)));
      assertThat(collation234.apply(mapping(n, 3, 2, 4)), is(collation(1, 0, 2)));
      assertThat(collation234.apply(mapping(n, 4, 3, 2, 0)), is(collation(2, 1, 0)));
      assertThat(collation234.apply(mapping(n, 3, 4, 0)), is(EMPTY));
  
      // [9] , 9 < mapping.sourceCount()
      RelCollation collation9 = collation(n - 1);
      assertThat(collation9.apply(mapping(n, 0)), is(EMPTY));
      assertThat(collation9.apply(mapping(n, 1)), is(EMPTY));
      assertThat(collation9.apply(mapping(n, 2)), is(EMPTY));
      assertThat(collation9.apply(mapping(n, n - 1)), is(collation(0)));
    }
  
    /**
     * Unit test for {@link RelFieldCollation.Direction#reverse()}.
     */
    @Test void testDirectionReverse() {
      assertThat(ASCENDING.reverse(), is(DESCENDING));
      assertThat(DESCENDING.reverse(), is(ASCENDING));
      assertThat(STRICTLY_ASCENDING.reverse(), is(STRICTLY_DESCENDING));
      assertThat(STRICTLY_DESCENDING.reverse(), is(STRICTLY_ASCENDING));
      assertThat(CLUSTERED.reverse(), is(CLUSTERED));
    }
  
    private static RelCollation collation(int... ordinals) {
      final List<RelFieldCollation> list = new ArrayList<>();
      for (int ordinal : ordinals) {
        list.add(new RelFieldCollation(ordinal));
      }
      return RelCollations.of(list);
    }
  
    private static Mapping mapping(int sourceCount, int... sources) {
      return Mappings.target(ImmutableIntList.of(sources), sourceCount);
    }
  }
  