All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.calcite.sql.test.ResultCheckers Maven / Gradle / Ivy

/*
 * 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.sql.test;

import org.apache.calcite.avatica.ColumnMetaData;
import org.apache.calcite.test.Matchers;
import org.apache.calcite.util.ImmutableNullableSet;
import org.apache.calcite.util.JdbcType;

import com.google.common.collect.ImmutableSet;

import org.hamcrest.Matcher;

import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.Types;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

import static java.util.Objects.requireNonNull;

/** Utilities for {@link SqlTester.ResultChecker}. */
public class ResultCheckers {
  private ResultCheckers() {
  }

  public static SqlTester.ResultChecker isExactly(double value) {
    return new MatcherResultChecker<>(is(value),
        JdbcType.DOUBLE);
  }

  public static SqlTester.ResultChecker isExactly(String value) {
    return new MatcherResultChecker<>(is(new BigDecimal(value)),
        JdbcType.BIG_DECIMAL);
  }

  public static SqlTester.ResultChecker isWithin(double value, double delta) {
    return new MatcherResultChecker<>(Matchers.within(value, delta),
        JdbcType.DOUBLE);
  }

  public static SqlTester.ResultChecker isSingle(double delta, String value) {
    assert delta == 0d; // if not zero, call a different method
    return isSingle(value);
  }

  public static SqlTester.ResultChecker isSingle(String value) {
    return new MatcherResultChecker<>(is(value),
        JdbcType.STRING_NULLABLE);
  }

  public static SqlTester.ResultChecker isSingle(boolean value) {
    return new MatcherResultChecker<>(is(value),
        JdbcType.BOOLEAN);
  }

  public static SqlTester.ResultChecker isSingle(int value) {
    return new MatcherResultChecker<>(is(value),
        JdbcType.INTEGER);
  }

  public static SqlTester.ResultChecker isDecimal(String value) {
    return new MatcherResultChecker<>(is(new BigDecimal(value)),
        JdbcType.BIG_DECIMAL);
  }

  public static SqlTester.ResultChecker isSet(String... values) {
    return new RefSetResultChecker(ImmutableSet.copyOf(values));
  }

  public static SqlTester.ResultChecker isNullValue() {
    return new RefSetResultChecker(Collections.singleton(null));
  }

  /**
   * Compares the first column of a result set against a String-valued
   * reference set, disregarding order entirely.
   *
   * @param resultSet Result set
   * @param refSet    Expected results
   * @throws Exception .
   */
  static void compareResultSet(ResultSet resultSet,
      Set refSet) throws Exception {
    Set actualSet = new HashSet<>();
    final int columnType = resultSet.getMetaData().getColumnType(1);
    final ColumnMetaData.Rep rep = rep(columnType);
    while (resultSet.next()) {
      final String s = resultSet.getString(1);
      final String s0 = s == null ? "0" : s;
      final boolean wasNull0 = resultSet.wasNull();
      actualSet.add(s);
      switch (rep) {
      case BOOLEAN:
      case PRIMITIVE_BOOLEAN:
        assertThat(resultSet.getBoolean(1), equalTo(Boolean.valueOf(s)));
        break;
      case BYTE:
      case PRIMITIVE_BYTE:
      case SHORT:
      case PRIMITIVE_SHORT:
      case INTEGER:
      case PRIMITIVE_INT:
      case LONG:
      case PRIMITIVE_LONG:
        long l;
        try {
          l = Long.parseLong(s0);
        } catch (NumberFormatException e) {
          // Large integers come out in scientific format, say "5E+06"
          l = (long) Double.parseDouble(s0);
        }
        assertThat(resultSet.getByte(1), equalTo((byte) l));
        assertThat(resultSet.getShort(1), equalTo((short) l));
        assertThat(resultSet.getInt(1), equalTo((int) l));
        assertThat(resultSet.getLong(1), equalTo(l));
        break;
      case FLOAT:
      case PRIMITIVE_FLOAT:
      case DOUBLE:
      case PRIMITIVE_DOUBLE:
        final double d = Double.parseDouble(s0);
        assertThat(resultSet.getFloat(1), equalTo((float) d));
        assertThat(resultSet.getDouble(1), equalTo(d));
        break;
      default:
        // fall through; no type-specific validation is necessary
      }
      final boolean wasNull1 = resultSet.wasNull();
      final Object object = resultSet.getObject(1);
      final boolean wasNull2 = resultSet.wasNull();
      assertThat(object == null, equalTo(wasNull0));
      assertThat(wasNull1, equalTo(wasNull0));
      assertThat(wasNull2, equalTo(wasNull0));
    }
    resultSet.close();
    assertEquals(refSet, actualSet);
  }

  private static ColumnMetaData.Rep rep(int columnType) {
    switch (columnType) {
    case Types.BOOLEAN:
      return ColumnMetaData.Rep.BOOLEAN;
    case Types.TINYINT:
      return ColumnMetaData.Rep.BYTE;
    case Types.SMALLINT:
      return ColumnMetaData.Rep.SHORT;
    case Types.INTEGER:
      return ColumnMetaData.Rep.INTEGER;
    case Types.BIGINT:
      return ColumnMetaData.Rep.LONG;
    case Types.REAL:
      return ColumnMetaData.Rep.FLOAT;
    case Types.DOUBLE:
      return ColumnMetaData.Rep.DOUBLE;
    case Types.TIME:
      return ColumnMetaData.Rep.JAVA_SQL_TIME;
    case Types.TIMESTAMP:
      return ColumnMetaData.Rep.JAVA_SQL_TIMESTAMP;
    case Types.DATE:
      return ColumnMetaData.Rep.JAVA_SQL_DATE;
    default:
      return ColumnMetaData.Rep.OBJECT;
    }
  }

  /**
   * Compares the first column of a result set against a pattern. The result
   * set must return exactly one row.
   *
   * @param resultSet Result set
   * @param pattern   Expected pattern
   */
  static void compareResultSetWithPattern(ResultSet resultSet,
      Pattern pattern) throws Exception {
    if (!resultSet.next()) {
      fail("Query returned 0 rows, expected 1");
    }
    String actual = resultSet.getString(1);
    if (resultSet.next()) {
      fail("Query returned 2 or more rows, expected 1");
    }
    if (!pattern.matcher(actual).matches()) {
      fail("Query returned '"
              + actual
              + "', expected '"
              + pattern.pattern()
              + "'");
    }
  }

  /**
   * Compares the first column of a result set against a {@link Matcher}.
   * The result set must return exactly one row.
   *
   * @param resultSet Result set
   * @param matcher   Matcher
   *
   * @param  Value type
   */
  static  void compareResultSetWithMatcher(ResultSet resultSet,
      JdbcType jdbcType, Matcher matcher) throws Exception {
    if (!resultSet.next()) {
      fail("Query returned 0 rows, expected 1");
    }
    T actual = jdbcType.get(1, resultSet);
    if (resultSet.next()) {
      fail("Query returned 2 or more rows, expected 1");
    }
    assertThat(actual, matcher);
  }

  /** Creates a ResultChecker that accesses a column of a given type
   * and then uses a Hamcrest matcher to check the value. */
  public static  SqlTester.ResultChecker createChecker(Matcher matcher,
      JdbcType jdbcType) {
    return new MatcherResultChecker<>(matcher, jdbcType);
  }

  /** Creates a ResultChecker from an expected result.
   *
   * 

The result may be a {@link SqlTester.ResultChecker}, * a regular expression ({@link Pattern}), * a Hamcrest {@link Matcher}, * a {@link Collection} of strings (representing the values of one column). * *

If none of the above, the value is converted to a string and compared * with the value of a single column, single row result set that is converted * to a string. */ public static SqlTester.ResultChecker createChecker(Object result) { requireNonNull(result, "to check for a null result, use isNullValue()"); if (result instanceof Pattern) { return new PatternResultChecker((Pattern) result); } else if (result instanceof SqlTester.ResultChecker) { return (SqlTester.ResultChecker) result; } else if (result instanceof Matcher) { //noinspection unchecked,rawtypes return createChecker((Matcher) result, JdbcType.DOUBLE); } else if (result instanceof Collection) { //noinspection unchecked final Collection collection = (Collection) result; return new RefSetResultChecker(ImmutableNullableSet.copyOf(collection)); } else { return isSingle(result.toString()); } } /** * Result checker that checks a result against a regular expression. */ static class PatternResultChecker implements SqlTester.ResultChecker { final Pattern pattern; PatternResultChecker(Pattern pattern) { this.pattern = requireNonNull(pattern, "pattern"); } @Override public void checkResult(ResultSet resultSet) throws Exception { compareResultSetWithPattern(resultSet, pattern); } } /** * Result checker that checks a result using a {@link org.hamcrest.Matcher}. * * @param Result type */ static class MatcherResultChecker implements SqlTester.ResultChecker { private final Matcher matcher; private final JdbcType jdbcType; MatcherResultChecker(Matcher matcher, JdbcType jdbcType) { this.matcher = requireNonNull(matcher, "matcher"); this.jdbcType = requireNonNull(jdbcType, "jdbcType"); } @Override public void checkResult(ResultSet resultSet) throws Exception { compareResultSetWithMatcher(resultSet, jdbcType, matcher); } } /** * Result checker that checks a result against a list of expected strings. */ static class RefSetResultChecker implements SqlTester.ResultChecker { private final Set expected; RefSetResultChecker(Set expected) { this.expected = ImmutableNullableSet.copyOf(expected); } @Override public void checkResult(ResultSet resultSet) throws Exception { compareResultSet(resultSet, expected); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy