blob: 8ff7e82a14739ed5bb2ccbf2baff074d44d92b5a [file] [log] [blame]
/*
* 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.hadoop.hive.tools;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
/**
*
* GenVectorTestCode.
* This class is mutable and maintains a hashmap of TestSuiteClassName to test cases.
* The tests cases are added over the course of vectorized expressions class generation,
* with test classes being outputted at the end. For each column vector (inputs and/or outputs)
* a matrix of pairwise covering Booleans is used to generate test cases across nulls and
* repeating dimensions. Based on the input column vector(s) nulls and repeating states
* the states of the output column vector (if there is one) is validated, along with the null
* vector. For filter operations the selection vector is validated against the generated
* data. Each template corresponds to a class representing a test suite.
*/
public class GenVectorTestCode {
public enum TestSuiteClassName{
TestColumnScalarOperationVectorExpressionEvaluation,
TestColumnScalarOperationVectorExpressionCheckedEvaluation,
TestColumnScalarFilterVectorExpressionEvaluation,
TestColumnColumnOperationVectorExpressionEvaluation,
TestColumnColumnOperationVectorExpressionCheckedEvaluation,
TestColumnColumnFilterVectorExpressionEvaluation,
}
private final String testOutputDir;
private final String testTemplateDirectory;
private final HashMap<TestSuiteClassName,StringBuilder> testsuites;
public GenVectorTestCode(String testOutputDir, String testTemplateDirectory) {
this.testOutputDir = testOutputDir;
this.testTemplateDirectory = testTemplateDirectory;
testsuites = new HashMap<TestSuiteClassName, StringBuilder>();
for(TestSuiteClassName className : TestSuiteClassName.values()) {
testsuites.put(className,new StringBuilder());
}
}
public void addColumnScalarOperationCheckedTestCases(boolean op1IsCol, String vectorExpClassName,
String inputColumnVectorType, String outputColumnVectorType, String scalarType,
boolean isReturnTypeLong)
throws IOException {
TestSuiteClassName template =
TestSuiteClassName.TestColumnScalarOperationVectorExpressionCheckedEvaluation;
//Read the template into a string;
String templateFile = GenVectorCode.joinPath(this.testTemplateDirectory,template.toString()+".txt");
String templateString = removeTemplateComments(GenVectorCode.readFile(templateFile));
String[] outputTypeInfos = null;
if (isReturnTypeLong) {
outputTypeInfos = new String[] {"tinyint", "smallint", "int", "bigint"};
} else {
outputTypeInfos = new String[] {"float", "double"};
}
for (String outputTypeInfo : outputTypeInfos) {
for (Boolean[] testMatrix : new Boolean[][] {
// Pairwise: InitOuputColHasNulls, InitOuputColIsRepeating, ColumnHasNulls, ColumnIsRepeating
{ false, true, true, true }, { false, false, false, false }, { true, false, true, false },
{ true, true, false, false }, { true, false, false, true } }) {
String testCase = templateString;
testCase = testCase.replaceAll("<TestName>",
"test" + vectorExpClassName
+ createNullRepeatingNameFragment("Out", testMatrix[0], testMatrix[1])
+ createNullRepeatingNameFragment("Col", testMatrix[2], testMatrix[3])
+ createOutputTypeInfoFragment("Ret", outputTypeInfo));
testCase = testCase.replaceAll("<OutputTypeInfo>", outputTypeInfo);
testCase = testCase.replaceAll("<VectorExpClassName>", vectorExpClassName);
testCase = testCase.replaceAll("<InputColumnVectorType>", inputColumnVectorType);
testCase = testCase.replaceAll("<OutputColumnVectorType>", outputColumnVectorType);
testCase = testCase.replaceAll("<ScalarType>", scalarType);
testCase = testCase.replaceAll("<CamelCaseScalarType>", GenVectorCode.getCamelCaseType(scalarType));
testCase = testCase.replaceAll("<InitOuputColHasNulls>", testMatrix[0].toString());
testCase = testCase.replaceAll("<InitOuputColIsRepeating>", testMatrix[1].toString());
testCase = testCase.replaceAll("<ColumnHasNulls>", testMatrix[2].toString());
testCase = testCase.replaceAll("<ColumnIsRepeating>", testMatrix[3].toString());
if (op1IsCol) {
testCase = testCase.replaceAll("<ConstructorParams>", "0, scalarValue");
} else {
testCase = testCase.replaceAll("<ConstructorParams>", "scalarValue, 0");
}
testsuites.get(template).append(testCase);
}
}
}
public void addColumnScalarOperationTestCases(boolean op1IsCol, String vectorExpClassName,
String inputColumnVectorType, String outputColumnVectorType, String scalarType)
throws IOException {
TestSuiteClassName template =
TestSuiteClassName.TestColumnScalarOperationVectorExpressionEvaluation;
//Read the template into a string;
String templateFile = GenVectorCode.joinPath(this.testTemplateDirectory,template.toString()+".txt");
String templateString = removeTemplateComments(GenVectorCode.readFile(templateFile));
for(Boolean[] testMatrix :new Boolean[][]{
// Pairwise: InitOuputColHasNulls, InitOuputColIsRepeating, ColumnHasNulls, ColumnIsRepeating
{false, true, true, true},
{false, false, false, false},
{true, false, true, false},
{true, true, false, false},
{true, false, false, true}}) {
String testCase = templateString;
testCase = testCase.replaceAll("<TestName>",
"test"
+ vectorExpClassName
+ createNullRepeatingNameFragment("Out", testMatrix[0], testMatrix[1])
+ createNullRepeatingNameFragment("Col", testMatrix[2], testMatrix[3]));
testCase = testCase.replaceAll("<VectorExpClassName>", vectorExpClassName);
testCase = testCase.replaceAll("<InputColumnVectorType>", inputColumnVectorType);
testCase = testCase.replaceAll("<OutputColumnVectorType>", outputColumnVectorType);
testCase = testCase.replaceAll("<ScalarType>", scalarType);
testCase = testCase.replaceAll("<CamelCaseScalarType>", GenVectorCode.getCamelCaseType(scalarType));
testCase = testCase.replaceAll("<InitOuputColHasNulls>", testMatrix[0].toString());
testCase = testCase.replaceAll("<InitOuputColIsRepeating>", testMatrix[1].toString());
testCase = testCase.replaceAll("<ColumnHasNulls>", testMatrix[2].toString());
testCase = testCase.replaceAll("<ColumnIsRepeating>", testMatrix[3].toString());
if(op1IsCol){
testCase = testCase.replaceAll("<ConstructorParams>","0, scalarValue");
}else{
testCase = testCase.replaceAll("<ConstructorParams>","scalarValue, 0");
}
testsuites.get(template).append(testCase);
}
}
public void addColumnScalarFilterTestCases(boolean op1IsCol, String vectorExpClassName,
String inputColumnVectorType, String scalarType, String operatorSymbol)
throws IOException {
TestSuiteClassName template =
TestSuiteClassName.TestColumnScalarFilterVectorExpressionEvaluation;
//Read the template into a string;
String templateFile = GenVectorCode.joinPath(this.testTemplateDirectory,template.toString()+".txt");
String templateString = removeTemplateComments(GenVectorCode.readFile(templateFile));
for(Boolean[] testMatrix : new Boolean[][]{
// Pairwise: ColumnHasNulls, ColumnIsRepeating
{true, true},
{true, false},
{false, false},
{false, true}}) {
String testCase = templateString;
testCase = testCase.replaceAll("<TestName>",
"test"
+ vectorExpClassName
+ createNullRepeatingNameFragment("Col", testMatrix[0], testMatrix[1]));
testCase = testCase.replaceAll("<VectorExpClassName>", vectorExpClassName);
testCase = testCase.replaceAll("<InputColumnVectorType>", inputColumnVectorType);
testCase = testCase.replaceAll("<ScalarType>", scalarType);
testCase = testCase.replaceAll("<CamelCaseScalarType>", GenVectorCode.getCamelCaseType(scalarType));
testCase = testCase.replaceAll("<ColumnHasNulls>", testMatrix[0].toString());
testCase = testCase.replaceAll("<ColumnIsRepeating>", testMatrix[1].toString());
testCase = testCase.replaceAll("<Operator>", operatorSymbol);
if(op1IsCol){
testCase = testCase.replaceAll("<Operand1>","inputColumnVector.vector[i]");
testCase = testCase.replaceAll("<Operand2>","scalarValue");
testCase = testCase.replaceAll("<ConstructorParams>","0, scalarValue");
}else{
testCase = testCase.replaceAll("<Operand1>","scalarValue");
testCase = testCase.replaceAll("<Operand2>","inputColumnVector.vector[i]");
testCase = testCase.replaceAll("<ConstructorParams>","scalarValue, 0");
}
testsuites.get(template).append(testCase);
}
}
public void addColumnColumnOperationCheckedTestCases(String vectorExpClassName,
String inputColumnVectorType1, String inputColumnVectorType2, String outputColumnVectorType,
boolean isReturnTypeLong)
throws IOException {
TestSuiteClassName template=
TestSuiteClassName.TestColumnColumnOperationVectorExpressionCheckedEvaluation;
//Read the template into a string;
String templateFile = GenVectorCode.joinPath(this.testTemplateDirectory,template.toString()+".txt");
String templateString = removeTemplateComments(GenVectorCode.readFile(templateFile));
String[] outputTypeInfos = null;
if (isReturnTypeLong) {
outputTypeInfos = new String[] {"tinyint", "smallint", "int", "bigint"};
} else {
outputTypeInfos = new String[] {"float", "double"};
}
for (String outputTypeInfo : outputTypeInfos) {
for (Boolean[] testMatrix : new Boolean[][] {
// Pairwise: InitOuputColHasNulls, InitOuputColIsRepeating, Column1HasNulls,
// Column1IsRepeating, Column2HasNulls, Column2IsRepeating
{ true, true, false, true, true, true },
{ false, false, true, false, false, false },
{ true, false, true, false, true, true },
{ true, true, true, true, false, false },
{ false, false, false, true, true, false },
{ false, true, false, false, false, true } }) {
String testCase = templateString;
testCase = testCase.replaceAll("<TestName>",
"test"
+ vectorExpClassName
+ createNullRepeatingNameFragment("Out", testMatrix[0],
testMatrix[1])
+ createNullRepeatingNameFragment("C1", testMatrix[2], testMatrix[3])
+ createNullRepeatingNameFragment("C2", testMatrix[4], testMatrix[5])
+ createOutputTypeInfoFragment("Ret", outputTypeInfo));
testCase = testCase.replaceAll("<VectorExpClassName>", vectorExpClassName);
testCase = testCase.replaceAll("<InputColumnVectorType1>", inputColumnVectorType1);
testCase = testCase.replaceAll("<InputColumnVectorType2>", inputColumnVectorType2);
testCase = testCase.replaceAll("<OutputColumnVectorType>", outputColumnVectorType);
testCase = testCase.replaceAll("<InitOuputColHasNulls>", testMatrix[0].toString());
testCase = testCase.replaceAll("<InitOuputColIsRepeating>", testMatrix[1].toString());
testCase = testCase.replaceAll("<Column1HasNulls>", testMatrix[2].toString());
testCase = testCase.replaceAll("<Column1IsRepeating>", testMatrix[3].toString());
testCase = testCase.replaceAll("<Column2HasNulls>", testMatrix[4].toString());
testCase = testCase.replaceAll("<Column2IsRepeating>", testMatrix[5].toString());
testCase = testCase.replaceAll("<OutputTypeInfo>", outputTypeInfo);
testsuites.get(template).append(testCase);
}
}
}
public void addColumnColumnOperationTestCases(String vectorExpClassName,
String inputColumnVectorType1, String inputColumnVectorType2, String outputColumnVectorType)
throws IOException {
TestSuiteClassName template=
TestSuiteClassName.TestColumnColumnOperationVectorExpressionEvaluation;
//Read the template into a string;
String templateFile = GenVectorCode.joinPath(this.testTemplateDirectory,template.toString()+".txt");
String templateString = removeTemplateComments(GenVectorCode.readFile(templateFile));
for(Boolean[] testMatrix : new Boolean[][]{
// Pairwise: InitOuputColHasNulls, InitOuputColIsRepeating, Column1HasNulls,
// Column1IsRepeating, Column2HasNulls, Column2IsRepeating
{true, true, false, true, true, true},
{false, false, true, false, false, false},
{true, false, true, false, true, true},
{true, true, true, true, false, false},
{false, false, false, true, true, false},
{false, true, false, false, false, true}}) {
String testCase = templateString;
testCase = testCase.replaceAll("<TestName>",
"test"
+ vectorExpClassName
+ createNullRepeatingNameFragment("Out", testMatrix[0], testMatrix[1])
+ createNullRepeatingNameFragment("C1", testMatrix[2], testMatrix[3])
+ createNullRepeatingNameFragment("C2", testMatrix[4], testMatrix[5]));
testCase = testCase.replaceAll("<VectorExpClassName>", vectorExpClassName);
testCase = testCase.replaceAll("<InputColumnVectorType1>", inputColumnVectorType1);
testCase = testCase.replaceAll("<InputColumnVectorType2>", inputColumnVectorType2);
testCase = testCase.replaceAll("<OutputColumnVectorType>", outputColumnVectorType);
testCase = testCase.replaceAll("<InitOuputColHasNulls>", testMatrix[0].toString());
testCase = testCase.replaceAll("<InitOuputColIsRepeating>", testMatrix[1].toString());
testCase = testCase.replaceAll("<Column1HasNulls>", testMatrix[2].toString());
testCase = testCase.replaceAll("<Column1IsRepeating>", testMatrix[3].toString());
testCase = testCase.replaceAll("<Column2HasNulls>", testMatrix[4].toString());
testCase = testCase.replaceAll("<Column2IsRepeating>", testMatrix[5].toString());
testsuites.get(template).append(testCase);
}
}
public void addColumnColumnFilterTestCases(String vectorExpClassName,
String inputColumnVectorType1, String inputColumnVectorType2, String operatorSymbol)
throws IOException {
TestSuiteClassName template=
TestSuiteClassName.TestColumnColumnFilterVectorExpressionEvaluation;
//Read the template into a string;
String templateFile = GenVectorCode.joinPath(this.testTemplateDirectory,template.toString()+".txt");
String templateString = removeTemplateComments(GenVectorCode.readFile(templateFile));
for(Boolean[] testMatrix : new Boolean[][]{
// Pairwise: Column1HasNulls, Column1IsRepeating, Column2HasNulls, Column2IsRepeating
{false, true, true, true},
{false, false, false, false},
{true, false, true, false},
{true, true, false, false},
{true, false, false, true}}) {
String testCase = templateString;
testCase = testCase.replaceAll("<TestName>",
"test"
+ vectorExpClassName
+ createNullRepeatingNameFragment("C1", testMatrix[0], testMatrix[1])
+ createNullRepeatingNameFragment("C2", testMatrix[2], testMatrix[3]));
testCase = testCase.replaceAll("<VectorExpClassName>", vectorExpClassName);
testCase = testCase.replaceAll("<InputColumnVectorType1>", inputColumnVectorType1);
testCase = testCase.replaceAll("<InputColumnVectorType2>", inputColumnVectorType2);
testCase = testCase.replaceAll("<Column1HasNulls>", testMatrix[0].toString());
testCase = testCase.replaceAll("<Column1IsRepeating>", testMatrix[1].toString());
testCase = testCase.replaceAll("<Column2HasNulls>", testMatrix[2].toString());
testCase = testCase.replaceAll("<Column2IsRepeating>", testMatrix[3].toString());
testCase = testCase.replaceAll("<Operator>", operatorSymbol);
testsuites.get(template).append(testCase);
}
}
public void generateTestSuites() throws IOException {
String templateFile = GenVectorCode.joinPath(this.testTemplateDirectory, "TestClass.txt");
for(TestSuiteClassName testClass : testsuites.keySet()) {
String templateString = GenVectorCode.readFile(templateFile);
templateString = templateString.replaceAll("<ClassName>", testClass.toString());
templateString = templateString.replaceAll("<TestCases>", testsuites.get(testClass).toString());
String outputFile = GenVectorCode.joinPath(this.testOutputDir, testClass + ".java");
GenVectorCode.writeFile(new File(outputFile), templateString);
}
}
private static String createNullRepeatingNameFragment(String identifier, boolean nulls, boolean repeating)
{
if(nulls || repeating){
if(nulls){
identifier+="Nulls";
}
if(repeating){
identifier+="Repeats";
}
return identifier;
}
return "";
}
private static String createOutputTypeInfoFragment(String identifier, String outputTypeInfo) {
if (identifier == null) {
throw new RuntimeException("Received null input for the identifier");
}
switch (outputTypeInfo) {
case "tinyint": {
return identifier + "TinyInt";
}
case "smallint": {
return identifier + "SmallInt";
}
case "int": {
return identifier + "Int";
}
case "bigint": {
return identifier + "BigInt";
}
case "float": {
return identifier + "Float";
}
case "double": {
return identifier + "Double";
}
default: {
throw new RuntimeException("Unsupported input typeInfo " + outputTypeInfo);
}
}
}
private static String removeTemplateComments(String templateString){
return templateString.replaceAll("(?s)<!--(.*)-->", "");
}
}