From 3e031410d81dd099765ebce23906e64c84a9b1c8 Mon Sep 17 00:00:00 2001 From: Richard Tia Date: Wed, 3 May 2023 16:26:09 -0700 Subject: [PATCH] test: add string function test cases --- bft/dialects/parser.py | 5 ++- bft/dialects/types.py | 30 ++++++++++++++--- bft/testers/postgres/runner.py | 9 ++++- bft/testers/sqlite/runner.py | 10 +++++- bft/testers/velox/runner.py | 2 +- cases/string/concat.yaml | 42 ++++++++++++++++++++++++ cases/string/like.yaml | 60 ++++++++++++++++++++++++++++++++++ cases/string/substring.yaml | 54 ++++++++++++++++++++++++++++++ dialects/postgres.yaml | 7 ++++ dialects/sqlite.yaml | 6 ++++ dialects/velox_presto.yaml | 4 +++ 11 files changed, 221 insertions(+), 8 deletions(-) create mode 100644 cases/string/concat.yaml create mode 100644 cases/string/like.yaml create mode 100644 cases/string/substring.yaml diff --git a/bft/dialects/parser.py b/bft/dialects/parser.py index 82871d03..f3057268 100644 --- a/bft/dialects/parser.py +++ b/bft/dialects/parser.py @@ -14,8 +14,11 @@ def visit_scalar_function(self, func): local_name = self._get_or_else(func, "local_name", name) infix = self._get_or_else(func, "infix", False) postfix = self._get_or_else(func, "postfix", False) + skip = self._get_or_else(func, "skip", False) bad_kernels = self._visit_list(self.visit_kernel, func, "unsupported_kernels") - return DialectFunction(name, local_name, infix, postfix, required_opts, bad_kernels) + return DialectFunction( + name, local_name, infix, postfix, skip, required_opts, bad_kernels + ) def visit(self, dfile): name = self._get_or_die(dfile, "name") diff --git a/bft/dialects/types.py b/bft/dialects/types.py index b400c78c..a05d2438 100644 --- a/bft/dialects/types.py +++ b/bft/dialects/types.py @@ -1,5 +1,7 @@ from typing import Dict, List, NamedTuple +import pytest + from bft.cases.types import Case, CaseLiteral, Literal, case_to_kernel_str from bft.core.function import Kernel @@ -14,6 +16,7 @@ class DialectFunction(NamedTuple): local_name: str infix: bool postfix: bool + skip: bool required_options: Dict[str, str] unsupported_kernels: List[DialectKernel] @@ -28,6 +31,7 @@ class SqlMapping(NamedTuple): local_name: str infix: bool postfix: bool + skip: bool should_pass: bool reason: str @@ -100,18 +104,36 @@ def supports_kernel(self, function_name: str, kernel: Kernel) -> bool: def mapping_for_case(self, case: Case) -> SqlMapping: dfunc = self.__scalar_functions_by_name.get(case.function, None) + if dfunc.skip: + pytest.skip("Skipping unsupported function.") if dfunc is None: return None kernel_failure = self.__supports_case_kernel(dfunc, case.args, case.result) if kernel_failure is not None: - return SqlMapping(dfunc.local_name, dfunc.infix, dfunc.postfix, False, kernel_failure) + return SqlMapping( + dfunc.local_name, + dfunc.infix, + dfunc.postfix, + dfunc.skip, + False, + kernel_failure, + ) option_failure = self.__supports_options(dfunc, case) if option_failure is not None: - return SqlMapping(dfunc.local_name, dfunc.infix, dfunc.postfix, False, option_failure) - - return SqlMapping(dfunc.local_name, dfunc.infix, dfunc.postfix, True, None) + return SqlMapping( + dfunc.local_name, + dfunc.infix, + dfunc.postfix, + dfunc.skip, + False, + option_failure, + ) + + return SqlMapping( + dfunc.local_name, dfunc.infix, dfunc.postfix, dfunc.skip, True, None + ) class DialectsLibrary(object): diff --git a/bft/testers/postgres/runner.py b/bft/testers/postgres/runner.py index 080c752c..ee5a76bb 100644 --- a/bft/testers/postgres/runner.py +++ b/bft/testers/postgres/runner.py @@ -61,7 +61,14 @@ def run_sql_case(self, case: Case, mapping: SqlMapping) -> SqlCaseResult: arg_names = [f"arg{idx}" for idx in range(len(case.args))] joined_arg_names = ",".join(arg_names) - arg_vals = ",".join([literal_to_str(arg) for arg in case.args]) + arg_vals = ",".join( + [ + "'" + literal_to_str(arg) + "'" + if arg.type == "string" and arg.value is not None + else literal_to_str(arg) + for arg in case.args + ] + ) self.conn.execute( f"INSERT INTO my_table ({joined_arg_names}) VALUES ({arg_vals});" ) diff --git a/bft/testers/sqlite/runner.py b/bft/testers/sqlite/runner.py index 68a6d72a..d4c75f60 100644 --- a/bft/testers/sqlite/runner.py +++ b/bft/testers/sqlite/runner.py @@ -13,6 +13,7 @@ "fp32": "REAL", "fp64": "REAL", "boolean": "BOOLEAN", + "string": "TEXT", } @@ -51,7 +52,14 @@ def run_sql_case(self, case: Case, mapping: SqlMapping) -> SqlCaseResult: arg_names = [f"arg{idx}" for idx in range(len(case.args))] joined_arg_names = ",".join(arg_names) - arg_vals = ",".join([literal_to_str(arg) for arg in case.args]) + arg_vals = ",".join( + [ + "'" + literal_to_str(arg) + "'" + if arg.type == "string" and arg.value is not None + else literal_to_str(arg) + for arg in case.args + ] + ) self.conn.execute( f"INSERT INTO my_table ({joined_arg_names}) VALUES ({arg_vals});" ) diff --git a/bft/testers/velox/runner.py b/bft/testers/velox/runner.py index 1cdac8f4..a0553f62 100644 --- a/bft/testers/velox/runner.py +++ b/bft/testers/velox/runner.py @@ -5,7 +5,7 @@ def is_type_supported(type): - return type in set({"i8", "i16", "i32", "i64", "fp32", "fp64", "boolean"}) + return type in set({"i8", "i16", "i32", "i64", "fp32", "fp64", "boolean", "string"}) class VeloxRunner(SqlCaseRunner): diff --git a/cases/string/concat.yaml b/cases/string/concat.yaml new file mode 100644 index 00000000..3791b2bf --- /dev/null +++ b/cases/string/concat.yaml @@ -0,0 +1,42 @@ +function: concat +cases: + - group: + id: basic + description: Basic examples without any special cases + args: + - value: 'abcd' + type: string + - value: 'efg' + type: string + result: + value: 'abcdefg' + type: string + - group: + id: null_input + description: Examples with null as input + args: + - value: 'abcd' + type: string + - value: null + type: string + result: + value: null + type: string + - group: null_input + args: + - value: null + type: string + - value: 'abcd' + type: string + result: + value: null + type: string + - group: null_input + args: + - value: null + type: string + - value: null + type: string + result: + value: null + type: string \ No newline at end of file diff --git a/cases/string/like.yaml b/cases/string/like.yaml new file mode 100644 index 00000000..6b12b198 --- /dev/null +++ b/cases/string/like.yaml @@ -0,0 +1,60 @@ +function: like +cases: + - group: + id: basic + description: Basic examples without any special cases + args: + - value: 'abcdefg' + type: string + - value: 'abcdefg' + type: string + result: + value: true + type: boolean + - group: basic + args: + - value: 'abcdefg' + type: string + - value: 'abc' + type: string + result: + value: false + type: boolean + - group: + id: wildcard + description: Examples using wildcards + args: + - value: 'abcdefg' + type: string + - value: 'abc%' + type: string + result: + value: true + type: boolean + - group: wildcard + args: + - value: 'abcdefg' + type: string + - value: '%efg' + type: string + result: + value: true + type: boolean + - group: wildcard + args: + - value: 'abcdefg' + type: string + - value: '_bcdefg' + type: string + result: + value: true + type: boolean + - group: wildcard + args: + - value: 'abcdefg' + type: string + - value: 'abc_efg' + type: string + result: + value: true + type: boolean diff --git a/cases/string/substring.yaml b/cases/string/substring.yaml new file mode 100644 index 00000000..c76aabd0 --- /dev/null +++ b/cases/string/substring.yaml @@ -0,0 +1,54 @@ +function: substring +cases: + - group: + id: basic + description: Basic examples without any special cases + args: + - value: 'abcdefg' + type: string + - value: 1 + type: i32 + - value: 5 + type: i32 + result: + value: 'abcde' + type: string + - group: + id: zero_start + description: Example where start argument is zero + args: + - value: 'abcdefg' + type: string + - value: 0 + type: i32 + - value: 3 + type: i32 + result: + value: 'ab' + type: string + - group: + id: negative_start + description: Example where start argument is a negative integer + args: + - value: 'abcdefg' + type: string + - value: -3 + type: i32 + - value: 2 + type: i32 + result: + value: 'ef' + type: string + - group: + id: start_greater_than_length + description: Example where start argument greater than the length of the string + args: + - value: 'abcdefg' + type: string + - value: 10 + type: i32 + - value: 2 + type: i32 + result: + value: '' + type: string \ No newline at end of file diff --git a/dialects/postgres.yaml b/dialects/postgres.yaml index b6f7f507..0ffb07cc 100644 --- a/dialects/postgres.yaml +++ b/dialects/postgres.yaml @@ -144,3 +144,10 @@ scalar_functions: - i8 - i8 result: i8 + - name: substring + skip: true + - name: concat + local_name: "||" + infix: True + - name: like + infix: True diff --git a/dialects/sqlite.yaml b/dialects/sqlite.yaml index bd28e094..b27f2f55 100644 --- a/dialects/sqlite.yaml +++ b/dialects/sqlite.yaml @@ -69,3 +69,9 @@ scalar_functions: local_name: "NULLIF" infix: False - name: coalesce + - name: substring + - name: concat + local_name: "||" + infix: True + - name: like + infix: True diff --git a/dialects/velox_presto.yaml b/dialects/velox_presto.yaml index 460afc40..63ba313e 100644 --- a/dialects/velox_presto.yaml +++ b/dialects/velox_presto.yaml @@ -81,3 +81,7 @@ scalar_functions: local_name: "!=" infix: True - name: coalesce + - name: substring + local_name: substr + - name: concat + - name: like