import pytest
import tempfile
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'apexbase', 'python'))
try:
from apexbase import ApexClient
except ImportError as e:
pytest.skip(f"ApexBase not available: {e}", allow_module_level=True)
@pytest.fixture
def client():
with tempfile.TemporaryDirectory() as temp_dir:
c = ApexClient(dirpath=temp_dir)
c.create_table("test_data")
c.use_table("test_data")
c.store([
{"id": 1, "name": "Alice", "value": 100, "price": 10.5, "text": " hello world ", "date_str": "2024-01-15"},
{"id": 2, "name": "Bob", "value": 200, "price": 20.75, "text": "test string", "date_str": "2024-06-20"},
{"id": 3, "name": "Charlie", "value": -50, "price": 5.0, "text": "UPPER lower", "date_str": "2023-12-01"},
{"id": 4, "name": None, "value": None, "price": None, "text": None, "date_str": None},
])
c.flush()
yield c
c.close()
class TestStringFunctions:
def test_instr_locate(self, client):
result = client.execute("SELECT INSTR(name, 'l') AS pos FROM test_data WHERE id = 1").to_dict()
assert result[0]["pos"] == 2
result = client.execute("SELECT LOCATE('l', name) AS pos FROM test_data WHERE id = 1").to_dict()
assert result[0]["pos"] == 2
result = client.execute("SELECT LOCATE('l', name, 4) AS pos FROM test_data WHERE id = 1").to_dict()
assert result[0]["pos"] == 0
def test_lpad_rpad(self, client):
result = client.execute("SELECT LPAD(name, 10, '*') AS padded FROM test_data WHERE id = 2").to_dict()
assert result[0]["padded"] == "*******Bob"
result = client.execute("SELECT RPAD(name, 10, '*') AS padded FROM test_data WHERE id = 2").to_dict()
assert result[0]["padded"] == "Bob*******"
def test_ltrim_rtrim(self, client):
result = client.execute("SELECT LTRIM(text) AS trimmed FROM test_data WHERE id = 1").to_dict()
assert result[0]["trimmed"] == "hello world "
result = client.execute("SELECT RTRIM(text) AS trimmed FROM test_data WHERE id = 1").to_dict()
assert result[0]["trimmed"] == " hello world"
def test_reverse(self, client):
result = client.execute("SELECT REVERSE(name) AS rev FROM test_data WHERE id = 2").to_dict()
assert result[0]["rev"] == "boB"
def test_initcap(self, client):
result = client.execute("SELECT INITCAP(text) AS capped FROM test_data WHERE id = 3").to_dict()
assert result[0]["capped"] == "Upper Lower"
def test_concat_ws(self, client):
result = client.execute("SELECT CONCAT_WS('-', name, 'test') AS joined FROM test_data WHERE id = 1").to_dict()
assert result[0]["joined"] == "Alice-test"
def test_repeat(self, client):
result = client.execute("SELECT REPEAT('ab', 3) AS repeated FROM test_data WHERE id = 1").to_dict()
assert result[0]["repeated"] == "ababab"
def test_space(self, client):
result = client.execute("SELECT CONCAT('a', SPACE(3), 'b') AS spaced FROM test_data WHERE id = 1").to_dict()
assert result[0]["spaced"] == "a b"
def test_ascii_chr(self, client):
result = client.execute("SELECT ASCII('A') AS code FROM test_data WHERE id = 1").to_dict()
assert result[0]["code"] == 65
result = client.execute("SELECT CHR(65) AS char FROM test_data WHERE id = 1").to_dict()
assert result[0]["char"] == "A"
def test_left_right(self, client):
result = client.execute("SELECT LEFT(name, 2) AS l FROM test_data WHERE id = 1").to_dict()
assert result[0]["l"] == "Al"
result = client.execute("SELECT RIGHT(name, 2) AS r FROM test_data WHERE id = 1").to_dict()
assert result[0]["r"] == "ce"
def test_split(self, client):
result = client.execute("SELECT SPLIT(text, ' ')[1] AS word FROM test_data WHERE id = 2").to_dict()
assert result[0]["word"] == "string"
result = client.execute("SELECT SPLIT(text, ' ')[0] AS elem FROM test_data WHERE id = 2").to_dict()
assert result[0]["elem"] == "test"
def test_regexp_replace(self, client):
result = client.execute("SELECT REGEXP_REPLACE(text, '[0-9]+', 'X') AS replaced FROM test_data WHERE id = 2").to_dict()
assert result[0]["replaced"] == "test string"
def test_regexp_extract(self, client):
result = client.execute("SELECT REGEXP_EXTRACT('abc123def', '[0-9]+', 0) AS num FROM test_data WHERE id = 1").to_dict()
assert result[0]["num"] == "123"
class TestMathFunctions:
def test_power_pow(self, client):
result = client.execute("SELECT POWER(2, 3) AS p FROM test_data WHERE id = 1").to_dict()
assert result[0]["p"] == 8.0
result = client.execute("SELECT POW(2, 3) AS p FROM test_data WHERE id = 1").to_dict()
assert result[0]["p"] == 8.0
def test_exp(self, client):
result = client.execute("SELECT ROUND(EXP(1), 2) AS e FROM test_data WHERE id = 1").to_dict()
assert abs(result[0]["e"] - 2.72) < 0.01
def test_ln_log(self, client):
result = client.execute("SELECT ROUND(LN(2.718281828), 2) AS l FROM test_data WHERE id = 1").to_dict()
assert abs(result[0]["l"] - 1.0) < 0.01
result = client.execute("SELECT ROUND(LOG(10, 100), 2) AS l FROM test_data WHERE id = 1").to_dict()
assert abs(result[0]["l"] - 2.0) < 0.01
def test_log10_log2(self, client):
result = client.execute("SELECT LOG10(100) AS l FROM test_data WHERE id = 1").to_dict()
assert abs(result[0]["l"] - 2.0) < 0.01
result = client.execute("SELECT LOG2(8) AS l FROM test_data WHERE id = 1").to_dict()
assert abs(result[0]["l"] - 3.0) < 0.01
def test_trig_functions(self, client):
result = client.execute("SELECT ROUND(SIN(0), 2) AS s FROM test_data WHERE id = 1").to_dict()
assert abs(result[0]["s"] - 0.0) < 0.01
result = client.execute("SELECT ROUND(COS(0), 2) AS c FROM test_data WHERE id = 1").to_dict()
assert abs(result[0]["c"] - 1.0) < 0.01
def test_sign(self, client):
result = client.execute("SELECT SIGN(value) AS s FROM test_data WHERE id = 1").to_dict()
assert result[0]["s"] == 1
result = client.execute("SELECT SIGN(value) AS s FROM test_data WHERE id = 3").to_dict()
assert result[0]["s"] == -1
def test_greatest_least(self, client):
result = client.execute("SELECT GREATEST(1, 5, 3) AS g FROM test_data WHERE id = 1").to_dict()
assert result[0]["g"] == 5
result = client.execute("SELECT LEAST(1, 5, 3) AS l FROM test_data WHERE id = 1").to_dict()
assert result[0]["l"] == 1
def test_truncate(self, client):
result = client.execute("SELECT TRUNCATE(price, 1) AS t FROM test_data WHERE id = 1").to_dict()
assert result[0]["t"] == 10.5
result = client.execute("SELECT TRUNCATE(price, 0) AS t FROM test_data WHERE id = 2").to_dict()
assert result[0]["t"] == 20.0
def test_pi_e(self, client):
result = client.execute("SELECT ROUND(PI(), 2) AS pi FROM test_data WHERE id = 1").to_dict()
assert abs(result[0]["pi"] - 3.14) < 0.01
result = client.execute("SELECT ROUND(E(), 2) AS e FROM test_data WHERE id = 1").to_dict()
assert abs(result[0]["e"] - 2.72) < 0.01
class TestDateFunctions:
def test_year_month_day(self, client):
result = client.execute("SELECT YEAR(date_str) AS y FROM test_data WHERE id = 1").to_dict()
assert result[0]["y"] == 2024
result = client.execute("SELECT MONTH(date_str) AS m FROM test_data WHERE id = 1").to_dict()
assert result[0]["m"] == 1
result = client.execute("SELECT DAY(date_str) AS d FROM test_data WHERE id = 1").to_dict()
assert result[0]["d"] == 15
def test_current_date(self, client):
result = client.execute("SELECT CURRENT_DATE() AS d FROM test_data WHERE id = 1").to_dict()
assert result[0]["d"] is not None
def test_date_add_sub(self, client):
result = client.execute("SELECT DATE_ADD(date_str, 10) AS d FROM test_data WHERE id = 1").to_dict()
assert result[0]["d"] == "2024-01-25"
result = client.execute("SELECT DATE_SUB(date_str, 10) AS d FROM test_data WHERE id = 1").to_dict()
assert result[0]["d"] == "2024-01-05"
def test_datediff(self, client):
result = client.execute("SELECT DATEDIFF(date_str, '2024-01-01') AS diff FROM test_data WHERE id = 1").to_dict()
assert result[0]["diff"] == 14
def test_date_format(self, client):
result = client.execute("SELECT DATE_FORMAT(date_str, '%Y-%m') AS fmt FROM test_data WHERE id = 1").to_dict()
assert result[0]["fmt"] == "2024-01"
def test_to_date(self, client):
result = client.execute("SELECT TO_DATE('2024-01-15 10:30:00') AS d FROM test_data WHERE id = 1").to_dict()
assert result[0]["d"] == "2024-01-15"
def test_unix_timestamp(self, client):
result = client.execute("SELECT UNIX_TIMESTAMP('2024-01-15 00:00:00') AS ts FROM test_data WHERE id = 1").to_dict()
assert result[0]["ts"] > 0
result = client.execute("SELECT FROM_UNIXTIME(1705276800) AS dt FROM test_data WHERE id = 1").to_dict()
assert "2024-01-15" in result[0]["dt"]
class TestConditionalFunctions:
def test_if_function(self, client):
result = client.execute("SELECT IF(value > 100, 'high', 'low') AS level FROM test_data WHERE id = 1").to_dict()
assert result[0]["level"] == "low"
result = client.execute("SELECT IF(value > 100, 'high', 'low') AS level FROM test_data WHERE id = 2").to_dict()
assert result[0]["level"] == "high"
def test_nvl2(self, client):
result = client.execute("SELECT NVL2(name, 'has name', 'no name') AS status FROM test_data WHERE id = 1").to_dict()
assert result[0]["status"] == "has name"
result = client.execute("SELECT NVL2(value, 'has value', 'no value') AS status FROM test_data WHERE id = 4").to_dict()
assert result[0]["status"] in ["has value", "no value"]
def test_decode(self, client):
result = client.execute("SELECT DECODE(id, 1, 'one', 2, 'two', 'other') AS label FROM test_data WHERE id = 1").to_dict()
assert result[0]["label"] == "one"
result = client.execute("SELECT DECODE(id, 1, 'one', 2, 'two', 'other') AS label FROM test_data WHERE id = 3").to_dict()
assert result[0]["label"] == "other"
class TestTypeConversion:
def test_cast_to_string(self, client):
result = client.execute("SELECT CAST(value AS STRING) AS s FROM test_data WHERE id = 1").to_dict()
assert result[0]["s"] == "100"
def test_cast_to_int(self, client):
result = client.execute("SELECT CAST(price AS INT) AS i FROM test_data WHERE id = 2").to_dict()
assert result[0]["i"] == 20
def test_cast_to_float(self, client):
result = client.execute("SELECT CAST(value AS DOUBLE) AS f FROM test_data WHERE id = 1").to_dict()
assert result[0]["f"] == 100.0
class TestAggregateFunctions:
def test_count_distinct(self, client):
client.store([{"id": 5, "name": "Alice", "value": 300, "price": 15.0, "text": "test", "date_str": "2024-02-01"}])
client.flush()
result = client.execute("SELECT COUNT(DISTINCT name) AS cnt FROM test_data").to_dict()
assert result[0]["cnt"] == 3
def test_group_concat(self, client):
result = client.execute("SELECT GROUP_CONCAT(name) AS names FROM test_data WHERE id <= 2").to_dict()
assert "Alice" in result[0]["names"]
assert "Bob" in result[0]["names"]
if __name__ == "__main__":
pytest.main([__file__, "-v"])