diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index 6073eb50b..51e07a6b5 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -882,12 +882,14 @@ create or replace package body ut_utils is function get_hash(a_data raw, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash is begin - return dbms_crypto.hash(a_data, a_hash_type); + --We cannot run hash on null + return case when a_data is null then null else dbms_crypto.hash(a_data, a_hash_type) end; end; function get_hash(a_data clob, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash is begin - return dbms_crypto.hash(a_data, a_hash_type); + --We cannot run hash on null + return case when a_data is null then null else dbms_crypto.hash(a_data, a_hash_type) end; end; function qualified_sql_name(a_name varchar2) return varchar2 is diff --git a/source/expectations/data_values/ut_compound_data_helper.pkb b/source/expectations/data_values/ut_compound_data_helper.pkb index 37d9901ff..6d21aaa21 100644 --- a/source/expectations/data_values/ut_compound_data_helper.pkb +++ b/source/expectations/data_values/ut_compound_data_helper.pkb @@ -278,7 +278,7 @@ create or replace package body ut_compound_data_helper is begin if a_data_info is not empty then for i in 1..a_data_info.count loop - if a_data_info(i).has_nested_col = 0 then + if a_data_info(i).has_nested_col = 0 and a_data_info(i).column_type <> 'OBJECT' then --Get XMLTABLE column list add_element_to_list(l_xmltab_list,generate_xmltab_stmt(a_data_info(i))); --Get Select statment list of columns @@ -398,8 +398,12 @@ create or replace package body ut_compound_data_helper is l_column_list ut_varchar2_list := ut_varchar2_list(); begin for i in 1..a_cursor_info.count loop - l_column_list.extend; - l_column_list(l_column_list.last) := a_cursor_info(i).access_path; + --This avoids extracting single columns from nested objects. + --as we can go down to any level but we will lose visibility of parent. + if a_cursor_info(i).hierarchy_level = 1 then + l_column_list.extend; + l_column_list(l_column_list.last) := a_cursor_info(i).access_path; + end if; end loop; return l_column_list; end; diff --git a/source/expectations/data_values/ut_cursor_column.tpb b/source/expectations/data_values/ut_cursor_column.tpb index 13b1b3158..a9fb6b0f4 100644 --- a/source/expectations/data_values/ut_cursor_column.tpb +++ b/source/expectations/data_values/ut_cursor_column.tpb @@ -14,8 +14,11 @@ create or replace type body ut_cursor_column as self.column_len := a_col_max_len; --length of column self.column_precision := a_col_precision; self.column_scale := a_col_scale; - self.column_name := TRIM( BOTH '''' FROM a_col_name); --name of the column self.column_type_name := coalesce(a_col_type_name,a_col_type); --type name e.g. test_dummy_object or varchar2 + self.column_name := case when a_col_name is null and a_collection = 1 then + self.column_type_name + else TRIM( BOTH '''' FROM a_col_name) + end; --name of the column, however in nested object for collection name is not defined in cursor. self.xml_valid_name := ut_utils.get_valid_xml_name(self.column_name); self.display_path := case when a_access_path is null then self.column_name @@ -25,15 +28,16 @@ create or replace type body ut_cursor_column as self.access_path := case when a_access_path is null then self.xml_valid_name else - a_access_path||'/'||self.xml_valid_name + a_access_path||'/'||self.xml_valid_name end; --Access path used for XMLTABLE query self.filter_path := '/'||self.access_path; --Filter path will differ from access path in anydata type + --Transformed name needs to be build on full access path to avoid ambiguity when there is 3 or more levels of nesting. self.transformed_name := case when length(self.xml_valid_name) > 30 then - '"'||ut_compound_data_helper.get_fixed_size_hash(self.parent_name||self.xml_valid_name)||'"' + '"'||ut_compound_data_helper.get_fixed_size_hash(self.access_path)||'"' when self.parent_name is null then '"'||self.xml_valid_name||'"' else - '"'||ut_compound_data_helper.get_fixed_size_hash(self.parent_name||self.xml_valid_name)||'"' + '"'||ut_compound_data_helper.get_fixed_size_hash(self.access_path)||'"' end; --when is nestd we need to hash name to make sure we dont exceed 30 char self.column_type := a_col_type; --column type e.g. user_defined , varchar2 self.column_schema := a_col_schema_name; -- schema name diff --git a/test/install_ut3_tester_helper.sql b/test/install_ut3_tester_helper.sql index 9841252a0..d9aacdf36 100644 --- a/test/install_ut3_tester_helper.sql +++ b/test/install_ut3_tester_helper.sql @@ -6,9 +6,15 @@ alter session set plsql_optimize_level=0; --Install ut3_tester_helper @@ut3_tester_helper/test_dummy_object.tps @@ut3_tester_helper/other_dummy_object.tps +@@ut3_tester_helper/test_dummy_nested_object.tps +@@ut3_tester_helper/test_dummy_double_nested_object.tps @@ut3_tester_helper/test_dummy_object_list.tps +@@ut3_tester_helper/test_dummy_nested_object_list.tps +@@ut3_tester_helper/test_dummy_double_nested_list.tps +@@ut3_tester_helper/test_dummy_dble_nest_lst_obj.tps @@ut3_tester_helper/test_tab_varchar2.tps @@ut3_tester_helper/test_tab_varray.tps +@@ut3_tester_helper/test_nested_tab_varray.tps @@ut3_tester_helper/test_dummy_number.tps @@ut3_tester_helper/ut_test_table.sql @@ut3_tester_helper/test_event_object.tps diff --git a/test/ut3_tester_helper/test_dummy_dble_nest_lst_obj.tps b/test/ut3_tester_helper/test_dummy_dble_nest_lst_obj.tps new file mode 100644 index 000000000..5134fef21 --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_dble_nest_lst_obj.tps @@ -0,0 +1,17 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_DBLE_NEST_LST_OBJ'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_dble_nest_lst_obj force'; + end if; +end; +/ + +CREATE TYPE test_dummy_dble_nest_lst_obj AS OBJECT +( + some_number_id NUMBER, + some_name VARCHAR2 (25), + dummy_list test_dummy_double_nested_list +); +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_dummy_double_nested_list.tps b/test/ut3_tester_helper/test_dummy_double_nested_list.tps new file mode 100644 index 000000000..625462824 --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_double_nested_list.tps @@ -0,0 +1,13 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_DOUBLE_NESTED_LIST'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_double_nested_list force'; + end if; +end; +/ + +CREATE TYPE test_dummy_double_nested_list AS + TABLE OF test_dummy_nested_object_list; +/ diff --git a/test/ut3_tester_helper/test_dummy_double_nested_object.tps b/test/ut3_tester_helper/test_dummy_double_nested_object.tps new file mode 100644 index 000000000..8f74f7ecb --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_double_nested_object.tps @@ -0,0 +1,15 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_DOUBLE_NESTED_OBJ'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_double_nested_obj force'; + end if; +end; +/ + +create or replace type test_dummy_double_nested_obj as object ( + first_double_nested_obj test_dummy_nested_object, + "Value" varchar2(30) +) +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_dummy_nested_object.tps b/test/ut3_tester_helper/test_dummy_nested_object.tps new file mode 100644 index 000000000..6aef3bef8 --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_nested_object.tps @@ -0,0 +1,15 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_NESTED_OBJECT'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_nested_object force'; + end if; +end; +/ + +create or replace type test_dummy_nested_object as object ( + first_nested_obj test_dummy_object, + sec_nested_obj test_dummy_object +) +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_dummy_nested_object_list.tps b/test/ut3_tester_helper/test_dummy_nested_object_list.tps new file mode 100644 index 000000000..fd47b55bd --- /dev/null +++ b/test/ut3_tester_helper/test_dummy_nested_object_list.tps @@ -0,0 +1,15 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_NESTED_OBJECT_LIST'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_nested_object_list force'; + end if; +end; +/ + +create or replace type test_dummy_nested_object_list as object ( + first_nested_obj test_dummy_object_list, + somename varchar2(50) +) +/ \ No newline at end of file diff --git a/test/ut3_tester_helper/test_dummy_object_list.tps b/test/ut3_tester_helper/test_dummy_object_list.tps index 67bba558e..849974da1 100644 --- a/test/ut3_tester_helper/test_dummy_object_list.tps +++ b/test/ut3_tester_helper/test_dummy_object_list.tps @@ -1,2 +1,12 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_DUMMY_OBJECT_LIST'; + if l_exists > 0 then + execute immediate 'drop type test_dummy_object_list force'; + end if; +end; +/ + create or replace type test_dummy_object_list as table of test_dummy_object / diff --git a/test/ut3_tester_helper/test_nested_tab_varray.tps b/test/ut3_tester_helper/test_nested_tab_varray.tps new file mode 100644 index 000000000..9f58d090e --- /dev/null +++ b/test/ut3_tester_helper/test_nested_tab_varray.tps @@ -0,0 +1,14 @@ +declare + l_exists integer; +begin + select count(1) into l_exists from user_types where type_name = 'TEST_NESTED_TAB_VARRAY'; + if l_exists > 0 then + execute immediate 'drop type test_nested_tab_varray force'; + end if; +end; +/ + +create or replace type test_nested_tab_varray as object ( + n_varray t_varray +) +/ diff --git a/test/ut3_user/expectations/test_expectation_anydata.pkb b/test/ut3_user/expectations/test_expectation_anydata.pkb index be666b284..98938c107 100644 --- a/test/ut3_user/expectations/test_expectation_anydata.pkb +++ b/test/ut3_user/expectations/test_expectation_anydata.pkb @@ -991,6 +991,225 @@ Rows: [ 60 differences, showing first 20 ] ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); end; + + procedure failure_nesting_objects is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') )); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'C', '0') )); + --Act + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_nested_object was expected to equal: ut3_tester_helper.test_dummy_nested_object +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 1C0 +%Row No. 1 - Expected: 1B0]'; + ut3_develop.ut.expect(g_test_actual).to_equal(g_test_expected); + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure failure_double_nested_objects is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_double_nested_obj(ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') ),'Test')); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_double_nested_obj(ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'C', '0') ),'Test')); + --Act + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_double_nested_obj was expected to equal: ut3_tester_helper.test_dummy_double_nested_obj +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 1A01C0 +%Row No. 1 - Expected: 1A01B0]'; + ut3_develop.ut.expect(g_test_actual).to_equal(g_test_expected); + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure success_nesting_objects is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') )); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') )); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + procedure success_double_nested_objects is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_double_nested_obj(ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') ),'Test')); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_double_nested_obj(ut3_tester_helper.test_dummy_nested_object(ut3_tester_helper.test_dummy_object(1, 'A', '0'),ut3_tester_helper.test_dummy_object(1, 'B', '0') ),'Test')); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure failure_nested_object_list is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum + 1, 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2 + order by rownum desc; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object_list(l_actual,'Test')); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object_list(l_expected,'Test')); + --Act + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_nested_object_list was expected to equal: ut3_tester_helper.test_dummy_nested_object_list +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 2Something 221Something 11 +%Row No. 1 - Expected: 3Something 222Something 11]'; + ut3_develop.ut.expect(g_test_actual).to_equal(g_test_expected); + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure success_nested_object_list is + l_actual ut3_tester_helper.test_dummy_object_list; + l_expected ut3_tester_helper.test_dummy_object_list; + begin + --Arrange + select ut3_tester_helper.test_dummy_object( rownum , 'Something '||rownum, rownum) + bulk collect into l_actual + from dual connect by level <=2 + order by rownum desc; + select ut3_tester_helper.test_dummy_object( rownum, 'Something '||rownum, rownum) + bulk collect into l_expected + from dual connect by level <=2 + order by rownum desc; + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object_list(l_actual,'Test')); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_dummy_nested_object_list(l_expected,'Test')); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure nested_varray_same_data is + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_nested_tab_varray(ut3_tester_helper.t_varray(1)) ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_nested_tab_varray(ut3_tester_helper.t_varray(1)) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + end; + + procedure nested_varray_diff_data is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + begin + --Arrange + g_test_expected := anydata.convertObject( ut3_tester_helper.test_nested_tab_varray(ut3_tester_helper.t_varray(1)) ); + g_test_actual := anydata.convertObject( ut3_tester_helper.test_nested_tab_varray(ut3_tester_helper.t_varray(2)) ); + --Act + ut3_develop.ut.expect( g_test_actual ).to_equal( g_test_expected ); + l_expected_message := q'[%Actual: ut3_tester_helper.test_nested_tab_varray was expected to equal: ut3_tester_helper.test_nested_tab_varray +%Diff: +%Rows: [ 1 differences ] +%Row No. 1 - Actual: 2 +%Row No. 1 - Expected: 1]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + end; + + procedure user_def_type_null_issue_1098 is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_actual ut3_tester_helper.test_dummy_dble_nest_lst_obj; + l_expected ut3_tester_helper.test_dummy_dble_nest_lst_obj; + begin + l_actual:= ut3_tester_helper.test_dummy_dble_nest_lst_obj( + 1, 'North America', + ut3_tester_helper.test_dummy_double_nested_list ( + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list( + ut3_tester_helper.test_dummy_object(1, '100 Broadway', 02474), + ut3_tester_helper.test_dummy_object(2, '200 Indian School Rd', 85016) + ),'USA' + ), + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list(),'USA' + ) + ) + ); + + l_expected := ut3_tester_helper.test_dummy_dble_nest_lst_obj( + 1, + 'North America', + ut3_tester_helper.test_dummy_double_nested_list(ut3_tester_helper.test_dummy_nested_object_list(ut3_tester_helper.test_dummy_object_list( + ut3_tester_helper.test_dummy_object(1, '100 Broadway', 02474), + ut3_tester_helper.test_dummy_object(2, '200 Indian School Rd', 85016) + ), 'USA')) + ); + ut3_develop.ut.expect(anydata.convertObject(l_actual)).to_equal(anydata.convertObject(l_expected)).unordered; + + l_expected_message := q'[%Actual: ut3_tester_helper.test_dummy_dble_nest_lst_obj was expected to equal: ut3_tester_helper.test_dummy_dble_nest_lst_obj +%Diff: +%Rows: [ 2 differences ] +%Extra: 1North America1100 Broadway24742200 Indian School Rd85016USAUSA +%Missing: 1North America1100 Broadway24742200 Indian School Rd85016USA]'; + l_actual_message := ut3_tester_helper.main_helper.get_failed_expectations(1); + --Assert + ut.expect(l_actual_message).to_be_like(l_expected_message); + + end; + + procedure complex_nested_object_success is + l_actual_message varchar2(32767); + l_expected_message varchar2(32767); + l_actual ut3_tester_helper.test_dummy_dble_nest_lst_obj; + l_expected ut3_tester_helper.test_dummy_dble_nest_lst_obj; + begin + l_actual:= ut3_tester_helper.test_dummy_dble_nest_lst_obj( + 1, 'North America', + ut3_tester_helper.test_dummy_double_nested_list ( + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list( + ut3_tester_helper.test_dummy_object(1, '100 Broadway', 02474), + ut3_tester_helper.test_dummy_object(2, '200 Indian School Rd', 85016) + ),'USA' + ), + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list(),'USA' + ) + ) + ); + + l_expected := ut3_tester_helper.test_dummy_dble_nest_lst_obj( + 1, 'North America', + ut3_tester_helper.test_dummy_double_nested_list ( + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list( + ut3_tester_helper.test_dummy_object(1, '100 Broadway', 02474), + ut3_tester_helper.test_dummy_object(2, '200 Indian School Rd', 85016) + ),'USA' + ), + ut3_tester_helper.test_dummy_nested_object_list( + ut3_tester_helper.test_dummy_object_list(),'USA' + ) + ) + ); + ut3_develop.ut.expect(anydata.convertObject(l_actual)).to_equal(anydata.convertObject(l_expected)).unordered; + ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0); + + end; end; / \ No newline at end of file diff --git a/test/ut3_user/expectations/test_expectation_anydata.pks b/test/ut3_user/expectations/test_expectation_anydata.pks index a6eeb25fb..2abb48b7f 100644 --- a/test/ut3_user/expectations/test_expectation_anydata.pks +++ b/test/ut3_user/expectations/test_expectation_anydata.pks @@ -203,5 +203,35 @@ create or replace package test_expectation_anydata is --%test ( Empty Array not equal array with space ) procedure arr_empty_nqua_arr_e_unord; + + --%test ( Reports diff between not equal nested objects ) + procedure failure_nesting_objects; + + --%test ( Reports diff between not equal double nested objects ) + procedure failure_double_nested_objects; + + --%test (Reports success when comparing identical nested object ) + procedure success_nesting_objects; + + --%test ( Reports success when comparing identical double nested object ) + procedure success_double_nested_objects; + + --%test ( Reports diff between two not equal nested object list ) + procedure failure_nested_object_list; + + --%test ( Reports success when comparing identical nested object list ) + procedure success_nested_object_list; + + --%test ( Reports success when comparing identical nested VARRAYS ) + procedure nested_varray_same_data; + + --%test ( Reports diff between two not equal nested VARRAYS ) + procedure nested_varray_diff_data; + + --%test ( Comparision won't fail on user_defined type that is null as per issue 1098 ) + procedure user_def_type_null_issue_1098; + + --%test ( Reports success when comparing complex nested objects ) + procedure complex_nested_object_success; end; /