-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24 from hyperskill/sql
SQL tests support
- Loading branch information
Showing
20 changed files
with
310 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from hstest.exception.outcomes import WrongAnswer | ||
from hstest.stage.stage_test import StageTest | ||
from hstest.testing.runner.sql_runner import SQLRunner | ||
|
||
|
||
class SQLTest(StageTest): | ||
queries: dict[str, str] = dict() | ||
db: any = None | ||
|
||
def __init__(self, source: str = ''): | ||
super().__init__(source) | ||
self.runner = SQLRunner(self) | ||
|
||
def execute(self, query_name: str): | ||
query = self.queries[query_name] if query_name in self.queries else query_name | ||
cursor = self.db.cursor() | ||
try: | ||
return cursor.execute(query) | ||
except Exception as ex: | ||
raise WrongAnswer(str(ex)) | ||
|
||
def executeAndFetchAll(self, query_name: str): | ||
return self.execute(query_name).fetchall() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from hstest.testing.execution.runnable.runnable_file import RunnableFile | ||
from hstest.testing.execution.searcher.base_searcher import BaseSearcher | ||
|
||
|
||
class SQLSearcher(BaseSearcher): | ||
|
||
@property | ||
def extension(self) -> str: | ||
return '.sql' | ||
|
||
def search(self, where: str = None) -> RunnableFile: | ||
return self._base_search(where) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import os | ||
import re | ||
import sqlite3 | ||
import typing | ||
|
||
from hstest.exceptions import WrongAnswer | ||
from hstest.test_case.check_result import CheckResult | ||
from hstest.testing.execution.searcher.sql_searcher import SQLSearcher | ||
from hstest.testing.runner.test_runner import TestRunner | ||
|
||
if typing.TYPE_CHECKING: | ||
from hstest.testing.test_run import TestRun, TestCase | ||
|
||
|
||
class SQLRunner(TestRunner): | ||
|
||
def __init__(self, sql_test_cls): | ||
self.sql_test_cls = sql_test_cls | ||
super(SQLRunner, self).__init__() | ||
|
||
def test(self, test_run: 'TestRun'): | ||
test_case = test_run.test_case | ||
|
||
try: | ||
result = test_case.dynamic_testing() | ||
return result | ||
except BaseException as ex: | ||
test_run.set_error_in_test(ex) | ||
|
||
return CheckResult.from_error(test_run.error_in_test) | ||
|
||
def set_up(self, test_case: 'TestCase'): | ||
self.parse_sql_file() | ||
self.set_up_database() | ||
|
||
def set_up_database(self): | ||
if self.sql_test_cls.db is not None: | ||
return | ||
|
||
self.sql_test_cls.db = sqlite3.connect(':memory:') | ||
|
||
def parse_sql_file(self) -> None: | ||
sql_file = SQLSearcher().search() | ||
file_path = os.path.join(sql_file.folder, sql_file.file) | ||
|
||
with open(file_path, 'r') as file: | ||
lines = file.readlines() | ||
sql_content = " ".join(lines).replace("\n", "") | ||
commands = re.findall("(\\w+)\\s+?=\\s+?\"(.+?)\"", sql_content) | ||
|
||
for (name, query) in commands: | ||
if name in self.sql_test_cls.queries: | ||
self.sql_test_cls.queries[name] = query | ||
|
||
for name in self.sql_test_cls.queries: | ||
if self.sql_test_cls.queries[name] is None: | ||
raise WrongAnswer(f"Can't find '{name}' query from SQL files!") | ||
|
||
def tear_down(self, test_case: 'TestCase'): | ||
try: | ||
self.sql_test_cls.db.close() | ||
except Exception: | ||
pass |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from hstest import SQLTest, dynamic_test, correct, wrong | ||
from sqlite3 import Connection | ||
|
||
|
||
class TestSQLProject(SQLTest): | ||
@dynamic_test | ||
def test_queries(self): | ||
if type(self.db) is not Connection: | ||
return wrong('SQLite should be used by default') | ||
|
||
return correct() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
create_table | ||
= "CREATE TABLE STUDENT( | ||
ID INT PRIMARY KEY NOT NULL, | ||
NAME CHAR(20) NOT NULL, | ||
ROLL CHAR(20), | ||
ADDRESS CHAR(50), | ||
CLASS CHAR(20) )"; | ||
|
||
test | ||
= "UPDATE Customers | ||
SET ContactName = 'Alfred Schmidt', City= 'Frankfurt' | ||
WHERE CustomerID = 1"; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from hstest import SQLTest, dynamic_test, correct, wrong | ||
|
||
|
||
class TestSQLProject(SQLTest): | ||
queries = { | ||
'create_table': None, | ||
'test': None | ||
} | ||
|
||
@dynamic_test | ||
def test_queries(self): | ||
|
||
expected_queries = { | ||
'create_table': "CREATE TABLE STUDENT( ID INT PRIMARY KEY NOT NULL, NAME CHAR(20) NOT NULL," | ||
" ROLL CHAR(20), ADDRESS CHAR(50), CLASS CHAR(20) )", | ||
'test': "UPDATE Customers SET ContactName = 'Alfred Schmidt', City= 'Frankfurt' WHERE CustomerID = 1" | ||
} | ||
|
||
for query in self.queries: | ||
if self.queries[query] != expected_queries[query]: | ||
return wrong(f"'{query}' is wrong! \n Expected:\n {expected_queries[query]}\n" | ||
f"Found:\n{self.queries[query]}") | ||
return correct() |
7 changes: 7 additions & 0 deletions
7
tests/sql/test_queries/execute/test_execute_with_plain_query/main.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
create_table = "CREATE TABLE contacts ( | ||
contact_id INTEGER PRIMARY KEY, | ||
first_name TEXT NOT NULL, | ||
last_name TEXT NOT NULL, | ||
email TEXT NOT NULL UNIQUE, | ||
phone TEXT NOT NULL UNIQUE | ||
);" |
24 changes: 24 additions & 0 deletions
24
tests/sql/test_queries/execute/test_execute_with_plain_query/test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from hstest import SQLTest, dynamic_test, correct, wrong | ||
|
||
|
||
class TestSQLProject(SQLTest): | ||
queries = { | ||
'create_table': None | ||
} | ||
|
||
@dynamic_test | ||
def test_queries(self): | ||
self.execute("""CREATE TABLE contacts ( | ||
contact_id INTEGER PRIMARY KEY, | ||
first_name TEXT NOT NULL, | ||
last_name TEXT NOT NULL, | ||
email TEXT NOT NULL UNIQUE, | ||
phone TEXT NOT NULL UNIQUE | ||
);""") | ||
|
||
result = self.db.execute("SELECT name FROM sqlite_schema WHERE type='table' ORDER BY name;") | ||
|
||
if 'contacts' not in result.fetchall()[0]: | ||
return wrong("Can't find 'contacts' table in the database") | ||
|
||
return correct() |
7 changes: 7 additions & 0 deletions
7
tests/sql/test_queries/execute/test_execute_with_query_name/main.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
create_table = "CREATE TABLE contacts ( | ||
contact_id INTEGER PRIMARY KEY, | ||
first_name TEXT NOT NULL, | ||
last_name TEXT NOT NULL, | ||
email TEXT NOT NULL UNIQUE, | ||
phone TEXT NOT NULL UNIQUE | ||
);" |
18 changes: 18 additions & 0 deletions
18
tests/sql/test_queries/execute/test_execute_with_query_name/test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from hstest import SQLTest, dynamic_test, correct, wrong | ||
|
||
|
||
class TestSQLProject(SQLTest): | ||
queries = { | ||
'create_table': None | ||
} | ||
|
||
@dynamic_test | ||
def test_queries(self): | ||
self.execute('create_table') | ||
|
||
result = self.db.execute("SELECT name FROM sqlite_schema WHERE type='table' ORDER BY name;") | ||
|
||
if 'contacts' not in result.fetchall()[0]: | ||
return wrong("Can't find 'contacts' table in the database") | ||
|
||
return correct() |
7 changes: 7 additions & 0 deletions
7
tests/sql/test_queries/execute/test_execute_with_wrong_plain_query/main.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
create_table = "CREATE TABLE contacts ( | ||
contact_id INTEGER PRIMARY KEY, | ||
first_name TEXT NOT NULL, | ||
last_name TEXT NOT NULL, | ||
email TEXT NOT NULL UNIQUE, | ||
phone TEXT NOT NULL UNIQUE | ||
);" |
30 changes: 30 additions & 0 deletions
30
tests/sql/test_queries/execute/test_execute_with_wrong_plain_query/test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import unittest | ||
|
||
from hstest import SQLTest, dynamic_test, correct, wrong | ||
|
||
|
||
class TestSQLProject(SQLTest): | ||
queries = { | ||
'create_table': None | ||
} | ||
|
||
@dynamic_test | ||
def test_queries(self): | ||
self.execute("""CRE TABLE contacts ( | ||
contact_id INTEGER PRIMARY KEY, | ||
first_name TEXT NOT NULL, | ||
last_name TEXT NOT NULL, | ||
email TEXT NOT NULL UNIQUE, | ||
phone TEXT NOT NULL UNIQUE | ||
);""") | ||
|
||
return correct() | ||
|
||
|
||
class Test(unittest.TestCase): | ||
|
||
def test(self): | ||
result, feedback = TestSQLProject().run_tests() | ||
self.assertEqual(result, -1) | ||
self.assertIn('Wrong answer in test #1', feedback) | ||
self.assertIn('near "CRE": syntax error', feedback) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
create_table = "CREATE TABLE contacts ( | ||
contact_id INTEGER PRIMARY KEY, | ||
first_name TEXT NOT NULL, | ||
last_name TEXT NOT NULL, | ||
email TEXT NOT NULL UNIQUE, | ||
phone TEXT NOT NULL UNIQUE | ||
);" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from hstest import SQLTest, dynamic_test, correct, wrong | ||
|
||
|
||
class TestSQLProject(SQLTest): | ||
queries = { | ||
'create_table': None | ||
} | ||
|
||
@dynamic_test | ||
def test_queries(self): | ||
self.db.execute(self.queries['create_table']) | ||
|
||
result = self.db.execute("SELECT name FROM sqlite_schema WHERE type='table' ORDER BY name;") | ||
|
||
if 'contacts' not in result.fetchall()[0]: | ||
return wrong("Can't find 'contacts' table in the database") | ||
|
||
return correct() |
9 changes: 9 additions & 0 deletions
9
tests/sql/test_queries/sqlite/insert_and_select_data/main.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
create_table = "CREATE TABLE contacts ( | ||
contact_id INTEGER PRIMARY KEY, | ||
first_name TEXT NOT NULL, | ||
last_name TEXT NOT NULL, | ||
email TEXT NOT NULL UNIQUE, | ||
phone TEXT NOT NULL UNIQUE | ||
);" | ||
|
||
insert_data = "INSERT INTO contacts VALUES(1, 'first_name', 'last_name', 'email', 'phone');" |
31 changes: 31 additions & 0 deletions
31
tests/sql/test_queries/sqlite/insert_and_select_data/test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from hstest import SQLTest, dynamic_test, correct, wrong | ||
|
||
|
||
class TestSQLProject(SQLTest): | ||
queries = { | ||
'create_table': None, | ||
'insert_data': None | ||
} | ||
|
||
@dynamic_test | ||
def test_create_table(self): | ||
self.db.execute(self.queries['create_table']) | ||
|
||
result = self.db.execute("SELECT name FROM sqlite_schema WHERE type='table' ORDER BY name;") | ||
|
||
if 'contacts' not in result.fetchall()[0]: | ||
return wrong("Can't find 'contacts' table in the database") | ||
|
||
return correct() | ||
|
||
@dynamic_test | ||
def test_insert_data(self): | ||
self.db.execute(self.queries['insert_data']) | ||
result = self.db.execute("SELECT * FROM contacts").fetchall()[0] | ||
|
||
correct_result = [1, 'first_name', 'last_name', 'email', 'phone'] | ||
|
||
if list(result) != correct_result: | ||
return wrong('Wrong data was inserted!') | ||
|
||
return correct() |