icsDataValidation 1.0.430__py3-none-any.whl → 1.0.438__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. icsDataValidation/connection_setups/sqlserver_connection_setup.py +4 -3
  2. icsDataValidation/input_parameters/testing_tool_params.py +0 -1
  3. icsDataValidation/services/database_services/snowflake_service.py +170 -67
  4. icsDataValidation/services/database_services/sqlserver_service.py +196 -88
  5. {icsdatavalidation-1.0.430.dist-info → icsdatavalidation-1.0.438.dist-info}/METADATA +1 -1
  6. {icsdatavalidation-1.0.430.dist-info → icsdatavalidation-1.0.438.dist-info}/RECORD +22 -8
  7. {icsdatavalidation-1.0.430.dist-info → icsdatavalidation-1.0.438.dist-info}/WHEEL +1 -1
  8. {icsdatavalidation-1.0.430.dist-info → icsdatavalidation-1.0.438.dist-info}/top_level.txt +1 -0
  9. tests/snowflake_service/test_create_checksums.py +146 -0
  10. tests/snowflake_service/test_create_pandas_df_from_group_by.py +485 -0
  11. tests/snowflake_service/test_create_pandas_df_from_sample.py +444 -0
  12. tests/snowflake_service/test_get_checksum_statement.py +243 -0
  13. tests/snowflake_service/test_get_column_clause.py +305 -0
  14. tests/snowflake_service/test_get_countnulls_statement.py +128 -0
  15. tests/snowflake_service/test_get_in_clause.py +66 -0
  16. tests/sqlserver_service/test_create_checksums.py +153 -0
  17. tests/sqlserver_service/test_create_pandas_df_from_group_by.py +427 -0
  18. tests/sqlserver_service/test_create_pandas_df_from_sample.py +286 -0
  19. tests/sqlserver_service/test_get_checksum_statement.py +160 -0
  20. tests/sqlserver_service/test_get_column_clause.py +182 -0
  21. tests/sqlserver_service/test_get_countnulls_statement.py +121 -0
  22. tests/sqlserver_service/test_get_in_clause.py +87 -0
@@ -0,0 +1,121 @@
1
+ from unittest.mock import MagicMock, Mock
2
+
3
+ import pytest
4
+
5
+ from icsDataValidation.core.database_objects import DatabaseObject
6
+ from icsDataValidation.services.database_services.sqlserver_service import SQLServerService
7
+
8
+
9
+ @pytest.fixture
10
+ def sqlserver_service():
11
+ """Create a SQLServerService instance with mocked connection."""
12
+ connection_params = {
13
+ 'Driver': 'ODBC Driver 18 for SQL Server',
14
+ 'Server': 'localhost',
15
+ 'Port': '1433',
16
+ 'Database': 'testdb',
17
+ 'User': 'sa',
18
+ 'Password': 'password',
19
+ 'Encrypt': True,
20
+ 'TrustServerCertificate': True
21
+ }
22
+ service = SQLServerService(connection_params=connection_params)
23
+ service.sqlserver_connection = MagicMock()
24
+ return service
25
+
26
+
27
+ @pytest.fixture
28
+ def mock_database_object():
29
+ """Create a mock DatabaseObject."""
30
+ obj = Mock(spec=DatabaseObject)
31
+ obj.database = "TestDB"
32
+ obj.schema = "dbo"
33
+ obj.name = "TestTable"
34
+ obj.type = "table"
35
+ return obj
36
+
37
+
38
+ class TestGetCountnullsStatementParametrized:
39
+ """Parametrized tests for _get_countnulls_statement method."""
40
+
41
+ @pytest.mark.parametrize(
42
+ "columns,exclude_columns,where_clause,expected_contains,expected_not_in",
43
+ [
44
+ ( # single column
45
+ ["Amount"],
46
+ [],
47
+ "",
48
+ ["SUM(CASE WHEN [AMOUNT] IS NULL THEN 1 ELSE 0 END)", "AS [COUNTNULLS_AMOUNT]", "FROM dbo.TestTable"],
49
+ []
50
+ ),
51
+ ( # multiple columns
52
+ ["Amount", "Name", "IsActive"],
53
+ [],
54
+ "",
55
+ [
56
+ "SUM(CASE WHEN [AMOUNT] IS NULL THEN 1 ELSE 0 END)", "AS [COUNTNULLS_AMOUNT]",
57
+ "SUM(CASE WHEN [NAME] IS NULL THEN 1 ELSE 0 END)", "AS [COUNTNULLS_NAME]",
58
+ "SUM(CASE WHEN [ISACTIVE] IS NULL THEN 1 ELSE 0 END)", "AS [COUNTNULLS_ISACTIVE]"
59
+ ],
60
+ []
61
+ ),
62
+ ( # with where clause
63
+ ["Amount"],
64
+ [],
65
+ "WHERE Amount > 100",
66
+ ["SUM(CASE WHEN [AMOUNT] IS NULL THEN 1 ELSE 0 END)", "WHERE Amount > 100"],
67
+ []
68
+ ),
69
+ ( # with exclude columns
70
+ ["Amount", "Price", "Quantity"],
71
+ ["Price"],
72
+ "",
73
+ ["AMOUNT", "QUANTITY"],
74
+ ["PRICE"]
75
+ ),
76
+ ( # special characters in column names
77
+ ["/ISDFPS/OBJNR", "MANDT"],
78
+ [],
79
+ "",
80
+ ["[/ISDFPS/OBJNR]", "AS [COUNTNULLS_/ISDFPS/OBJNR]", "[MANDT]", "AS [COUNTNULLS_MANDT]"],
81
+ []
82
+ ),
83
+ ( # empty columns
84
+ [],
85
+ [],
86
+ "",
87
+ ["SELECT", "FROM dbo.TestTable"],
88
+ ["COUNTNULLS"]
89
+ ),
90
+ ( # all columns excluded
91
+ ["Amount", "Price"],
92
+ ["Amount", "Price"],
93
+ "",
94
+ ["SELECT", "FROM dbo.TestTable"],
95
+ ["COUNTNULLS"]
96
+ ),
97
+ ( # case insensitive columns
98
+ ["amount", "Name", "QUANTITY"],
99
+ [],
100
+ "",
101
+ ["[AMOUNT]", "[NAME]", "[QUANTITY]"],
102
+ []
103
+ ),
104
+ ],
105
+ )
106
+ def test_get_countnulls_statement(
107
+ self, sqlserver_service, mock_database_object,
108
+ columns, exclude_columns, where_clause, expected_contains, expected_not_in
109
+ ):
110
+ """Test countnulls statement with various configurations."""
111
+ result = sqlserver_service._get_countnulls_statement(
112
+ object=mock_database_object,
113
+ column_intersections=columns,
114
+ exclude_columns=exclude_columns,
115
+ where_clause=where_clause
116
+ )
117
+
118
+ for expected in expected_contains:
119
+ assert expected in result
120
+ for expected in expected_not_in:
121
+ assert expected not in result
@@ -0,0 +1,87 @@
1
+ import pytest
2
+
3
+ from icsDataValidation.services.database_services.sqlserver_service import SQLServerService
4
+
5
+
6
+ class TestInClauseVariations:
7
+ """Test various IN clause generation scenarios using parametrization."""
8
+
9
+ @pytest.mark.parametrize(
10
+ "key_filters,numeric_columns,numeric_scale,expected_contains",
11
+ [
12
+ ( # basic single row
13
+ {"col1": ["value1"], "col2": ["value2"]},
14
+ [],
15
+ 2,
16
+ [" AND (CONCAT(", "CONCAT([col1], '|' ,[col2], '|')", "('value1|value2|')"],
17
+ ),
18
+ ( # basic single row with one column
19
+ {"col1": ["value1"]},
20
+ [],
21
+ 2,
22
+ [" AND (CONCAT(", "CONCAT([col1], '|')", "('value1|')"],
23
+ ),
24
+ ( # multiple rows
25
+ {"id": [1, 2, 3], "name": ["a", "b", "c"]},
26
+ [],
27
+ 2,
28
+ ["(CONCAT([id], '|' ,[name], '|')", "('1|a|','2|b|','3|c|')"],
29
+ ),
30
+ ( # numeric columns with rounding
31
+ {"price": [10.5, 20.3], "quantity": [5, 10]},
32
+ ["price"],
33
+ 2,
34
+ ["ROUND([price], 2)", "numeric(38, 2)", "quantity", "('10.5|5|','20.3|10|')"],
35
+ ),
36
+ ( # quotes in column names (should be removed)
37
+ {"'col1'": ["value1"], "'col2'": ["value2"]},
38
+ [],
39
+ 2,
40
+ ["col1", "col2"],
41
+ ),
42
+ ( # empty filters
43
+ {},
44
+ [],
45
+ 2,
46
+ [""],
47
+ ),
48
+ ( # numeric with specific scale
49
+ {"Price": [100.123, 200.456], "Count": [1, 2]},
50
+ ["Price"],
51
+ 3,
52
+ ["ROUND([Price], 3)", "numeric(38, 3)", "Count"],
53
+ ),
54
+ ( # all numeric columns
55
+ {"col1": [1.1, 2.2], "col2": [3.3, 4.4]},
56
+ ["col1", "col2"],
57
+ 2,
58
+ ["ROUND([col1], 2)", "ROUND([col2], 2)", "numeric(38, 2)"],
59
+ ),
60
+ ( # mixed data types
61
+ {"amount": [100, 200], "category": ["A", "B"], "quantity": [10, 20]},
62
+ ["amount", "quantity"],
63
+ 0,
64
+ ["ROUND([amount], 0)", "ROUND([quantity], 0)", "category"],
65
+ ),
66
+ ( # values order check
67
+ {"id": [1, 2], "name": ["alice", "bob"]},
68
+ [],
69
+ 2,
70
+ ["('1|alice|','2|bob|')"],
71
+ ),
72
+ ( # special character column names
73
+ {"/ABC": ["value1", "value2"], "Normal": ["val1", "val2"]},
74
+ [],
75
+ 2,
76
+ ["[/ABC]", "[Normal]", "CONCAT([/ABC], '|' ,[Normal], '|')"],
77
+ ),
78
+ ],
79
+ )
80
+ def test_in_clause_contains(
81
+ self, key_filters, numeric_columns, numeric_scale, expected_contains
82
+ ):
83
+ """Test that result contains expected substrings."""
84
+ result = SQLServerService._get_in_clause(key_filters, numeric_columns, numeric_scale)
85
+
86
+ for expected in expected_contains:
87
+ assert expected in result