From 7f5ce6294e1033d352a9e615339b027bd7ce7376 Mon Sep 17 00:00:00 2001 From: atsy Date: Thu, 12 Nov 2015 12:51:52 +0200 Subject: [PATCH] Main class code and nugget. RELEASE 0.1 --- README.md | 9 +- lib/zcl_mockup_loader.abap | 1031 ++++++++++++++ lib/zcx_mockup_loader_error-raise.abap | 21 + lib/zcx_mockup_loader_error.abap | 79 ++ test/zcl_mockup_loader-unit_test.abap | 880 ++++++++++++ zmockup_loader-0.1.nugg | 1722 ++++++++++++++++++++++++ 6 files changed, 3740 insertions(+), 2 deletions(-) create mode 100644 lib/zcl_mockup_loader.abap create mode 100644 lib/zcx_mockup_loader_error-raise.abap create mode 100644 lib/zcx_mockup_loader_error.abap create mode 100644 test/zcl_mockup_loader-unit_test.abap create mode 100644 zmockup_loader-0.1.nugg diff --git a/README.md b/README.md index 3b0d442..4543e8c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Mockup Loader for ABAP unit testing# +*Version: 0.1* + ## Contents ## @@ -149,7 +151,10 @@ A nugget is available to install the code with SAPLink. SAPLink does not support * `MSG type SCX_ATTRNAME` * `CODE type CHAR2` 2. Go to Texts tab, choose exception id `ZCX_MOCKUP_LOADER_ERROR` (the only one there) and press Message Test button. Set `Message class = 0M, Message number = 500, Attrib1 = METHNAME, Attrib2 = MSG`. This message is one of standard messages with text "& & & &". - 3. Create a static public method `RAISE`. Copy the content of the `lib/zcx_mockup_loader_error-raise.abap` there + 3. Create a static public method `RAISE`. Copy the content of the `lib/zcx_mockup_loader_error-raise.abap` there. + * Add importing parameter `MSG type STRING` + * Add optional importing parameter `CODE type CHAR2` + * Add `ZCX_MOCKUP_LOADER_ERROR` to the exceptions section 4. Activate 4. Optionally upload unit tests. 1. Create a **test class** for the `ZCL_MOCKUP_LOADER`. Copy the content of `test/zcl_mockup_loader-unit_test.abap` there and activate. @@ -184,7 +189,7 @@ So we created a script which does the work automatically. How to use it: 7. Each file is processed according to points 1-3 and each sheet is saved as `.txt` file (in UTF16 encoding) to `uncompressed/EXCELFILENAME/` directory, where `EXCELFILENAME` is the name of the Excel file. 8. After everything is finished the "uncompressed" directory is compressed to a zip file and placed to the same directory where script is. -### Command line ### +### Command line parameters ### The script also supports command line parameters and can be executed with `cscript.exe` (preferable - then execution log is output to console). We use `.bat` files like this for example: diff --git a/lib/zcl_mockup_loader.abap b/lib/zcl_mockup_loader.abap new file mode 100644 index 0000000..f78c166 --- /dev/null +++ b/lib/zcl_mockup_loader.abap @@ -0,0 +1,1031 @@ +*/--------------------------------------------------------------------------------\ +*| This file is part of Mockup loader | +*| | +*| The MIT License (MIT) | +*| | +*| Copyright (c) 2015 SBCG Team (www.sbcg.com.ua), Alexander Tsybulsky | +*| | +*| Permission is hereby granted, free of charge, to any person obtaining a copy | +*| of this software and associated documentation files (the "Software"), to deal | +*| in the Software without restriction, including without limitation the rights | +*| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | +*| copies of the Software, and to permit persons to whom the Software is | +*| furnished to do so, subject to the following conditions: | +*| | +*| The above copyright notice and this permission notice shall be included in all | +*| copies or substantial portions of the Software. | +*| | +*| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | +*| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | +*| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | +*| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | +*| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | +*| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | +*| SOFTWARE. | +*\--------------------------------------------------------------------------------/ +*/--------------------------------------------------------------------------------\ +*| CONTRIBUTORS | +*|--------------------------------------------------------------------------------| +*| Leading developers : Alexander Tsybulsky (atsybulsky@sbcg.com.ua) | +*| Svetlana Shlapak (sshlapak@sbcg.com.ua) | +*| Testing and ideas: Bohdan Petruschak (b.petrushchak@sbcg.com.ua) | +*|--------------------------------------------------------------------------------| +*| project homepage: https://github.com/sbcgua/mockup_loader | +*\--------------------------------------------------------------------------------/ + + +class ZCL_MOCKUP_LOADER definition + public + final + create private . + +public section. + + class-methods GET_INSTANCE + returning + value(RO_INSTANCE) type ref to ZCL_MOCKUP_LOADER + raising + ZCX_MOCKUP_LOADER_ERROR . + methods LOAD_RAW + importing + !I_OBJ type STRING + !I_EXT type STRING optional + exporting + !E_CONTENT type XSTRING + raising + ZCX_MOCKUP_LOADER_ERROR . + type-pools ABAP . + methods LOAD_AND_STORE + importing + !I_OBJ type STRING + !I_STRICT type ABAP_BOOL default ABAP_TRUE + !I_NAME type CHAR40 + !I_TYPE type CSEQUENCE + !I_TABKEY type ABAP_COMPNAME optional + raising + ZCX_MOCKUP_LOADER_ERROR . + methods LOAD_DATA + importing + !I_OBJ type STRING + !I_STRICT type ABAP_BOOL default ABAP_TRUE + exporting + !E_CONTAINER type ANY + raising + ZCX_MOCKUP_LOADER_ERROR . + methods PURGE + importing + !I_NAME type CHAR40 . + class-methods RETRIEVE + importing + !I_NAME type CHAR40 + !I_SIFT type CLIKE optional + exporting + !E_DATA type ANY + exceptions + RETRIEVE_ERROR . + methods STORE + importing + !I_NAME type CHAR40 + !I_DATA type ANY + !I_TABKEY type ABAP_COMPNAME optional + raising + ZCX_MOCKUP_LOADER_ERROR . + class-methods FREE_INSTANCE . + class-methods CLASS_SET_SOURCE + importing + !I_PATH type STRING + !I_TYPE type CHAR4 . + class-methods CLASS_CONSTRUCTOR . +protected section. +private section. + + types: + tt_string type table of string . + types: + begin of ty_store, + name type char40, + tabkey type abap_compname, + data type ref to data, + end of ty_store . + types: + tt_store type table of ty_store . + + class-data GO_INSTANCE type ref to ZCL_MOCKUP_LOADER . + data O_ZIP type ref to CL_ABAP_ZIP . + data AT_STORE type TT_STORE . + class-data G_MOCKUP_LOAD_PATH type STRING . + class-data G_MOCKUP_LOAD_TYPE type CHAR4 . + + type-pools ABAP . + methods MAP_FILE_STRUCTURE + importing + !I_LINE type STRING + !IO_STRUC_DESCR type ref to CL_ABAP_STRUCTDESCR + !I_STRICT type ABAP_BOOL + exporting + !ET_MAP type INT4_TABLE + raising + ZCX_MOCKUP_LOADER_ERROR . + methods INITIALIZE + raising + ZCX_MOCKUP_LOADER_ERROR . + methods PARSE_APPLY_EXIT + importing + !I_DATA type STRING + !I_CONVEXIT type STRING + exporting + !E_FIELD type ANY + raising + ZCX_MOCKUP_LOADER_ERROR . + methods PARSE_DATA + importing + !I_RAWDATA type STRING + !I_STRICT type ABAP_BOOL default ABAP_TRUE + exporting + !E_CONTAINER type ANY + raising + ZCX_MOCKUP_LOADER_ERROR . + methods PARSE_LINE + importing + !I_LINE type STRING + !IT_MAP type INT4_TABLE + !IO_STRUC_DESCR type ref to CL_ABAP_STRUCTDESCR + !I_INDEX type INT4 + exporting + !ES_CONTAINER type ANY + raising + ZCX_MOCKUP_LOADER_ERROR . + methods PARSE_FIELD + importing + !IS_COMPONENT type ABAP_COMPDESCR + !I_DATA type STRING + exporting + !E_FIELD type ANY + raising + ZCX_MOCKUP_LOADER_ERROR . + methods READ_ZIP + importing + !I_NAME type STRING + exporting + !E_RAWDATA type STRING + raising + ZCX_MOCKUP_LOADER_ERROR . + methods _STORE + importing + !I_NAME type CHAR40 + !I_DATA_REF type ref to DATA + !I_TABKEY type ABAP_COMPNAME optional + raising + ZCX_MOCKUP_LOADER_ERROR . + methods _RETRIEVE + importing + !I_NAME type CHAR40 + !I_SIFT type CLIKE optional + exporting + !E_DATA type ANY + raising + ZCX_MOCKUP_LOADER_ERROR . +ENDCLASS. + + + +CLASS ZCL_MOCKUP_LOADER IMPLEMENTATION. + + +* ---------------------------------------------------------------------------------------+ +* | Static Public Method ZCL_MOCKUP_LOADER=>CLASS_CONSTRUCTOR +* +-------------------------------------------------------------------------------------------------+ +* +-------------------------------------------------------------------------------------- +method class_constructor. + class_set_source( i_type = 'MIME' i_path = '' ). " Defaults +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Static Public Method ZCL_MOCKUP_LOADER=>CLASS_SET_SOURCE +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_PATH TYPE STRING +* | [--->] I_TYPE TYPE CHAR4 +* +-------------------------------------------------------------------------------------- +method class_set_source. + check i_type = 'MIME' or i_type = 'FILE'. "TODO some more sophisticated error handling + + g_mockup_load_type = i_type. + g_mockup_load_path = i_path. +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Static Public Method ZCL_MOCKUP_LOADER=>FREE_INSTANCE +* +-------------------------------------------------------------------------------------------------+ +* +-------------------------------------------------------------------------------------- +method free_instance. + if go_instance is not initial. + free go_instance. + endif. +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Static Public Method ZCL_MOCKUP_LOADER=>GET_INSTANCE +* +-------------------------------------------------------------------------------------------------+ +* | [<-()] RO_INSTANCE TYPE REF TO ZCL_MOCKUP_LOADER +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method get_instance. + + if go_instance is initial. + create object go_instance. + call method go_instance->initialize. + endif. + + ro_instance = go_instance. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Private Method ZCL_MOCKUP_LOADER->INITIALIZE +* +-------------------------------------------------------------------------------------------------+ +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method initialize. + data: l_key type wwwdatatab, + l_xstring type xstring, + l_size type int4, + lt_w3mime type table of w3mime, + ls_w3mime type w3mime. + + " Load data + case g_mockup_load_type. + when 'MIME'. " Load from SMW0 + l_key-relid = 'MI'. + l_key-objid = g_mockup_load_path. + + call function 'WWWDATA_IMPORT' + exporting + key = l_key + tables + mime = lt_w3mime[] + exceptions + others = 1. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = 'SMW0 data import error' code = 'RE' ). "#EC NOTEXT + endif. + + describe table lt_w3mime lines l_size. + l_size = sy-tleng * sy-tfill. + + when 'FILE'. " Load from frontend + call function 'GUI_UPLOAD' + exporting + filename = g_mockup_load_path + filetype = 'BIN' + importing + filelength = l_size + tables + data_tab = lt_w3mime + exceptions + others = 1. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Cannot upload file: { g_mockup_load_path }| code = 'RE' ). "#EC NOTEXT + endif. + + when others. + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = 'Wrong source type' code = 'WS' ). "#EC NOTEXT + endif. + + endcase. + + " Convert to XString + call function 'SCMS_BINARY_TO_XSTRING' + exporting + input_length = l_size + importing + buffer = l_xstring + tables + binary_tab = lt_w3mime[] + exceptions + failed = 1. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( 'Binary to string error' ). "#EC NOTEXT + endif. + + " Extract zip + if o_zip is initial. + create object o_zip. + endif. + + call method o_zip->load + exporting zip = l_xstring + exceptions others = 4. + + if sy-subrc is not initial or lines( o_zip->files ) = 0. + zcx_mockup_loader_error=>raise( msg = 'ZIP load failed' code = 'ZE' ). "#EC NOTEXT + endif. +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Public Method ZCL_MOCKUP_LOADER->LOAD_AND_STORE +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_OBJ TYPE STRING +* | [--->] I_STRICT TYPE ABAP_BOOL (default =ABAP_TRUE) +* | [--->] I_NAME TYPE CHAR40 +* | [--->] I_TYPE TYPE CSEQUENCE +* | [--->] I_TABKEY TYPE ABAP_COMPNAME(optional) +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method load_and_store. + data: + lo_type type ref to cl_abap_typedescr, + lo_dtype type ref to cl_abap_datadescr, + lr_data type ref to data. + + field-symbols type data. + + " Create container to load zip data to + call method cl_abap_typedescr=>describe_by_name + exporting p_name = i_type + receiving p_descr_ref = lo_type + exceptions others = 4. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Type { i_type } not found| code = 'WT' ). "#EC NOTEXT + endif. + + lo_dtype ?= lo_type. + + create data lr_data type handle lo_dtype. + assign lr_data->* to . + if is not assigned. + zcx_mockup_loader_error=>raise( 'Data cannot be assigned' ). "#EC NOTEXT + endif. + + " Load from zip and store + call method load_data + exporting + i_obj = i_obj + i_strict = i_strict + importing + e_container = . + + call method _store + exporting + i_name = i_name + i_data_ref = lr_data + i_tabkey = i_tabkey. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Public Method ZCL_MOCKUP_LOADER->LOAD_DATA +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_OBJ TYPE STRING +* | [--->] I_STRICT TYPE ABAP_BOOL (default =ABAP_TRUE) +* | [<---] E_CONTAINER TYPE ANY +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method load_data. + data l_rawdata type string. + + if e_container is not supplied. + zcx_mockup_loader_error=>raise( msg = 'No container supplied' code = 'NC' ). "#EC NOTEXT + endif. + + call method me->read_zip + exporting i_name = i_obj && '.txt' + importing e_rawdata = l_rawdata. + + call method me->parse_data + exporting + i_rawdata = l_rawdata + i_strict = i_strict + importing + e_container = e_container. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Public Method ZCL_MOCKUP_LOADER->LOAD_RAW +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_OBJ TYPE STRING +* | [--->] I_EXT TYPE STRING(optional) +* | [<---] E_CONTENT TYPE XSTRING +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method load_raw. + data l_filename type string. + + if e_content is not supplied. + zcx_mockup_loader_error=>raise( msg = 'No container supplied' code = 'NC' ). "#EC NOTEXT + endif. + + if i_ext is initial. + l_filename = i_obj && '.txt'. + else. + l_filename = i_obj && i_ext. + endif. + + call method o_zip->get + exporting name = l_filename + importing content = e_content. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Private Method ZCL_MOCKUP_LOADER->MAP_FILE_STRUCTURE +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_LINE TYPE STRING +* | [--->] IO_STRUC_DESCR TYPE REF TO CL_ABAP_STRUCTDESCR +* | [--->] I_STRICT TYPE ABAP_BOOL +* | [<---] ET_MAP TYPE INT4_TABLE +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method map_file_structure. + data: + l_tabcnt type i, + l_fieldcnt type i, + lt_fields type tt_string, + l_field_name type string, + lt_dupcheck type tt_string. + + split i_line at cl_abap_char_utilities=>horizontal_tab into table lt_fields. + + " Check if the line ends with TAB + find all occurrences of cl_abap_char_utilities=>horizontal_tab in i_line match count l_tabcnt. + if l_tabcnt = lines( lt_fields ). " Line ends with TAB, last empty field is not added to table, see help for 'split' + zcx_mockup_loader_error=>raise( msg = 'Empty field at the end' code = 'EN' ). "#EC NOTEXT + endif. + + " Compare number of fields, check structure similarity + if i_strict = abap_true. + l_fieldcnt = lines( lt_fields ). + + " MANDT field may be skipped + read table io_struc_descr->components with key name = 'MANDT' transporting no fields. + if sy-subrc is initial. " Found in strcuture components + read table lt_fields with key table_line = 'MANDT' transporting no fields. + if sy-subrc is not initial. " But not found in the file + add 1 to l_fieldcnt. + endif. + endif. + + if l_fieldcnt <> lines( io_struc_descr->components ). + zcx_mockup_loader_error=>raise( msg = 'Different columns number' code = 'CN' ). "#EC NOTEXT + endif. + endif. + + " Check duplicate field names in incoming structure + lt_dupcheck[] = lt_fields[]. + sort lt_dupcheck[]. + delete adjacent duplicates from lt_dupcheck[]. + if lines( lt_dupcheck ) <> lines( lt_fields ). + zcx_mockup_loader_error=>raise( msg = 'Duplicate field names found' code = 'DN' ). "#EC NOTEXT + endif. + + " Compare columns names and make map + loop at lt_fields into l_field_name. + if l_field_name is initial. " Check empty fields + zcx_mockup_loader_error=>raise( msg = 'Empty field name found' code = 'EN' ). "#EC NOTEXT + endif. + + read table io_struc_descr->components with key name = l_field_name transporting no fields. + if sy-subrc is initial. + append sy-tabix to et_map. + else. + zcx_mockup_loader_error=>raise( msg = |Column { l_field_name } not found in target structure| code = 'MC' ). "#EC NOTEXT + endif. + endloop. + +endmethod. "analyse_structure + + +* ---------------------------------------------------------------------------------------+ +* | Instance Private Method ZCL_MOCKUP_LOADER->PARSE_APPLY_EXIT +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_DATA TYPE STRING +* | [--->] I_CONVEXIT TYPE STRING +* | [<---] E_FIELD TYPE ANY +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method parse_apply_exit. + data l_fmname type rs38l_fnam value 'CONVERSION_EXIT_XXXXX_INPUT'. + + replace first occurrence of 'XXXXX' in l_fmname with i_convexit. + + call function 'FUNCTION_EXISTS' + exporting + funcname = l_fmname + exceptions + function_not_exist = 1 + others = 2. + + if sy-subrc <> 0. + zcx_mockup_loader_error=>raise( msg = 'Conversion exit not found' code = 'EM' ). "#EC NOTEXT + endif. + + call function l_fmname + exporting input = i_data + importing output = e_field + exceptions others = 1. + + if sy-subrc <> 0. + zcx_mockup_loader_error=>raise( msg = 'Conversion exit failed' code = 'EF' ). "#EC NOTEXT + endif. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Private Method ZCL_MOCKUP_LOADER->PARSE_DATA +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_RAWDATA TYPE STRING +* | [--->] I_STRICT TYPE ABAP_BOOL (default =ABAP_TRUE) +* | [<---] E_CONTAINER TYPE ANY +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method parse_data. + data: + lt_lines type table of string, + ls_line type string, + lt_map type int4_table, + + lo_type_descr type ref to cl_abap_typedescr, + lo_table_descr type ref to cl_abap_tabledescr, + lo_struc_descr type ref to cl_abap_structdescr, + ref_tab_line type ref to data. + + field-symbols: + type any table, + type any. + + clear e_container. + + " Identify container type and create temp container + lo_type_descr = cl_abap_typedescr=>describe_by_data( e_container ). + case lo_type_descr->kind. + when 'T'. " Table + lo_table_descr ?= lo_type_descr. + lo_struc_descr ?= lo_table_descr->get_table_line_type( ). + create data ref_tab_line type handle lo_struc_descr. + assign ref_tab_line->* to . + assign e_container to
. + when 'S'. " Structure + lo_struc_descr ?= lo_type_descr. + assign e_container to . + when others. " Not a table or structure ? + zcx_mockup_loader_error=>raise( msg = 'Table or structure containers only' code = 'DT' ). "#EC NOTEXT + endcase. + + " Read and process header line + split i_rawdata at cl_abap_char_utilities=>cr_lf into table lt_lines. + read table lt_lines into ls_line index 1. + if sy-subrc <> 0. + zcx_mockup_loader_error=>raise( msg = 'No header line found in the file' code = 'NH' ). "#EC NOTEXT + endif. + if ls_line is initial. + zcx_mockup_loader_error=>raise( msg = 'Header line is empty' code = 'HE' ). "#EC NOTEXT + endif. + + delete lt_lines index 1. + + call method me->map_file_structure + exporting + i_line = ls_line + io_struc_descr = lo_struc_descr + i_strict = i_strict + importing + et_map = lt_map. + + " Main data parsing loop + loop at lt_lines into ls_line. + if ls_line is initial. " Check empty lines + check sy-tabix < lines( lt_lines ). " Last line of a file may be empty, others - not + zcx_mockup_loader_error=>raise( msg = |Empty line { sy-tabix + 1 } cannot be parsed| code = 'LE' ). "#EC NOTEXT + endif. + + call method parse_line + exporting + i_line = ls_line + io_struc_descr = lo_struc_descr + it_map = lt_map + i_index = sy-tabix + 1 + importing + es_container = . + + " Only first line goes to structure and then exits + if lo_type_descr->kind = 'S'. " Structure + exit. + else. " Table + insert into table
. + endif. + + endloop. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Private Method ZCL_MOCKUP_LOADER->PARSE_FIELD +* +-------------------------------------------------------------------------------------------------+ +* | [--->] IS_COMPONENT TYPE ABAP_COMPDESCR +* | [--->] I_DATA TYPE STRING +* | [<---] E_FIELD TYPE ANY +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method parse_field. + data l_mask type string. + + case is_component-type_kind. + when 'D'. " Date + call function 'CONVERT_DATE_TO_INTERNAL' + exporting + date_external = i_data + accept_initial_date = 'X' + importing + date_internal = e_field + exceptions + date_external_is_invalid = 1 + others = 2. + + when 'C'. " Char + convexits + describe field e_field edit mask l_mask. + if l_mask is initial. + e_field = i_data. + else. + shift l_mask left deleting leading '='. + call method me->parse_apply_exit + exporting + i_data = i_data + i_convexit = l_mask + importing + e_field = e_field. + endif. + + when 'g'. " String + e_field = i_data. + + when 'P'. " Amount + call function 'HRCM_STRING_TO_AMOUNT_CONVERT' + exporting + string = i_data + decimal_separator = ',' + thousands_separator = '.' + importing + betrg = e_field + exceptions + convert_error = 1 + others = 2. + + when 'N' or 'I'. " Integer number + if i_data co '0123456789'. + e_field = i_data. + else. + sy-subrc = 4. + endif. + + endcase. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Field: { is_component-name }| code = 'PF' ). "#EC NOTEXT + endif. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Private Method ZCL_MOCKUP_LOADER->PARSE_LINE +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_LINE TYPE STRING +* | [--->] IT_MAP TYPE INT4_TABLE +* | [--->] IO_STRUC_DESCR TYPE REF TO CL_ABAP_STRUCTDESCR +* | [--->] I_INDEX TYPE INT4 +* | [<---] ES_CONTAINER TYPE ANY +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method parse_line. + data: + l_tabcnt type i, + lt_fields type table of string, + ls_field type string, + ls_component type abap_compdescr, + l_index type int4. + + field-symbols type any. + + clear es_container. + split i_line at cl_abap_char_utilities=>horizontal_tab into table lt_fields. + + " Count TABs, if line ends with TAB last empty field is not added to table, see help for 'split' + find all occurrences of cl_abap_char_utilities=>horizontal_tab in i_line match count l_tabcnt. + add 1 to l_tabcnt. " Number of fields in the line + + " Check field number is the same as in header + if l_tabcnt > lines( it_map ). + zcx_mockup_loader_error=>raise( msg = |More fields than in header @{ i_index }| code = '>H' ). "#EC NOTEXT + elseif l_tabcnt < lines( it_map ). + zcx_mockup_loader_error=>raise( msg = |Less fields than in header @{ i_index }| code = 'components into ls_component index l_index. " Get component + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( 'No component found?!' ). "#EC NOTEXT + endif. + + check ls_component-name ne 'MANDT'. " Skip client fields + + assign component ls_component-name of structure es_container to . + if is not assigned. + zcx_mockup_loader_error=>raise( 'Field assign failed?!' ). "#EC NOTEXT + endif. + + call method parse_field + exporting + is_component = ls_component + i_data = ls_field + importing + e_field = . + + endloop. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Public Method ZCL_MOCKUP_LOADER->PURGE +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_NAME TYPE CHAR40 +* +-------------------------------------------------------------------------------------- +method purge. + data l_store type ty_store. + + if i_name = '*'. " Delete all + loop at at_store into l_store. + free l_store-data. + endloop. + clear at_store. + + else. " Delete specific record + read table at_store with key name = i_name into l_store. + check sy-subrc is initial. + delete at_store index sy-tabix. + free l_store-data. + endif. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Private Method ZCL_MOCKUP_LOADER->READ_ZIP +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_NAME TYPE STRING +* | [<---] E_RAWDATA TYPE STRING +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method read_zip. + data: + l_xstring type xstring, + lo_conv type ref to cl_abap_conv_in_ce, + l_ex type ref to cx_root. + + call method o_zip->get + exporting name = i_name + importing content = l_xstring + exceptions zip_index_error = 1. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Cannot read { i_name }| code = 'ZF' ). "#EC NOTEXT + endif. + + shift l_xstring left deleting leading cl_abap_char_utilities=>byte_order_mark_little in byte mode. + + try. + lo_conv = cl_abap_conv_in_ce=>create( encoding = '4103' ). " UTF16 + lo_conv->convert( exporting input = l_xstring importing data = e_rawdata ). + catch cx_root into l_ex. + zcx_mockup_loader_error=>raise( msg = 'Codepage conversion error' code = 'CP' ). "#EC NOTEXT + endtry. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Static Public Method ZCL_MOCKUP_LOADER=>RETRIEVE +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_NAME TYPE CHAR40 +* | [--->] I_SIFT TYPE CLIKE(optional) +* | [<---] E_DATA TYPE ANY +* | [EXC!] RETRIEVE_ERROR +* +-------------------------------------------------------------------------------------- +method retrieve. + data lo_ex type ref to zcx_mockup_loader_error. + + try . + get_instance( )->_retrieve( + exporting i_name = i_name + i_sift = i_sift + importing e_data = e_data ). + + catch zcx_mockup_loader_error into lo_ex. + + " Switch to non-class exceptions to ensure better code readability + " and compatibility with substituted select results + " e.g. zcl_mockup_loader=>retrieve( ... ). if sy_subrc is not initial ... + call method cl_message_helper=>set_msg_vars_for_if_t100_msg exporting text = lo_ex. + message id sy-msgid type sy-msgty number sy-msgno raising retrieve_error + with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. + + endtry. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Public Method ZCL_MOCKUP_LOADER->STORE +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_NAME TYPE CHAR40 +* | [--->] I_DATA TYPE ANY +* | [--->] I_TABKEY TYPE ABAP_COMPNAME(optional) +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method store. + data lr_data type ref to data. + field-symbols type any. + + " Create clone container + create data lr_data like i_data. + assign lr_data->* to . + if is not assigned. + zcx_mockup_loader_error=>raise( 'Data cannot be assigned' ). "#EC NOTEXT + endif. + + = i_data. " Copy data to container + + call method _store + exporting + i_name = i_name + i_data_ref = lr_data + i_tabkey = i_tabkey. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Private Method ZCL_MOCKUP_LOADER->_RETRIEVE +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_NAME TYPE CHAR40 +* | [--->] I_SIFT TYPE CLIKE(optional) +* | [<---] E_DATA TYPE ANY +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method _retrieve. + data: + l_store type ty_store, + r_data_tab type ref to data, + ld_src type ref to cl_abap_typedescr, + ld_dst type ref to cl_abap_typedescr, + ld_tab type ref to cl_abap_tabledescr, + ld_src_line type ref to cl_abap_structdescr, + ld_dst_line type ref to cl_abap_structdescr. + + field-symbols: + type any, + type any, + type any table, + type standard table, + type any. + + clear e_data. + + " Find store + read table at_store with key name = i_name into l_store. + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Cannot find store { i_name }| code = 'NF' ). "#EC NOTEXT + endif. + + assign l_store-data->* to . + if is not assigned. + zcx_mockup_loader_error=>raise( 'Data cannot be assigned' ). "#EC NOTEXT + endif. + + " Ensure types are the same + ld_src = cl_abap_typedescr=>describe_by_data( ). + ld_dst = cl_abap_typedescr=>describe_by_data( e_data ). + + if ld_src->kind = 'T'. + ld_tab ?= ld_src. + ld_src_line ?= ld_tab->get_table_line_type( ). + endif. + + " If types are not equal try going deeper to table line structure + if ld_src->absolute_name ne ld_dst->absolute_name. + if ld_src->kind = 'T' and ld_dst->kind = 'T'. " Table => Table + ld_tab ?= ld_dst. + ld_dst_line ?= ld_tab->get_table_line_type( ). + elseif i_sift is not initial and ld_src->kind = 'T' and ld_dst->kind = 'S'. " Table + filter => Structure + ld_dst_line ?= ld_dst. + else. + zcx_mockup_loader_error=>raise( msg = |Types differ for store { i_name }| code = 'TT' ). "#EC NOTEXT + endif. + + if ld_src_line->absolute_name ne ld_dst_line->absolute_name. + zcx_mockup_loader_error=>raise( msg = |Types differ for store { i_name }| code = 'TS' ). "#EC NOTEXT + endif. + endif. + + " Copy or sift (filter with tabkey) values + if i_sift is initial. + e_data = . + + else. " Assuming ld_src->kind = 'T' -> see STORE + assert ld_src->kind = 'T'. + assert ld_dst->kind ca 'ST'. + assign l_store-data->* to . + + case ld_dst->kind. + when 'T'. " Table + " Create temporary table (needed because DST table can be hashed or sorted) + ld_tab = cl_abap_tabledescr=>create( + p_line_type = ld_src_line + p_table_kind = cl_abap_tabledescr=>tablekind_std + p_unique = abap_false ). + + create data r_data_tab type handle ld_tab. + assign r_data_tab->* to . + + loop at assigning . + assign component l_store-tabkey of structure to . + if is not assigned. + zcx_mockup_loader_error=>raise( msg = 'Tabkey field not found' code = 'FM' ). "#EC NOTEXT + endif. + check = i_sift. + append to . + endloop. + + e_data = . + free r_data_tab. + + when 'S'. " Structure + read table into e_data with key (l_store-tabkey) = i_sift. "#EC CI_ANYSEQ + endcase. + endif. + + if e_data is initial. + zcx_mockup_loader_error=>raise( msg = 'No data returned' code = '04' ). "#EC NOTEXT + endif. + +endmethod. + + +* ---------------------------------------------------------------------------------------+ +* | Instance Private Method ZCL_MOCKUP_LOADER->_STORE +* +-------------------------------------------------------------------------------------------------+ +* | [--->] I_NAME TYPE CHAR40 +* | [--->] I_DATA_REF TYPE REF TO DATA +* | [--->] I_TABKEY TYPE ABAP_COMPNAME(optional) +* | [!CX!] ZCX_MOCKUP_LOADER_ERROR +* +-------------------------------------------------------------------------------------- +method _store. + data: + l_store type ty_store, + lo_type type ref to cl_abap_typedescr, + lo_tab_type type ref to cl_abap_tabledescr, + lo_str_type type ref to cl_abap_structdescr. + + " Check if tabkey exists + if i_tabkey is not initial. + lo_type = cl_abap_typedescr=>describe_by_data_ref( i_data_ref ). + if lo_type->kind <> 'T'. " Not table ? + zcx_mockup_loader_error=>raise( msg = 'Tabkey is relevant for tables only' code = 'TO' ). "#EC NOTEXT + endif. + + lo_tab_type ?= lo_type. lo_str_type ?= lo_tab_type->get_table_line_type( ). + + read table lo_str_type->components with key name = i_tabkey transporting no fields. + if sy-subrc <> 0. + zcx_mockup_loader_error=>raise( msg = 'Tabkey field not found' code = 'FM' ). "#EC NOTEXT + endif. + endif. + + " Store data + l_store-name = i_name. + l_store-tabkey = i_tabkey. + l_store-data = i_data_ref. + + me->purge( i_name ). + append l_store to me->at_store. + +endmethod. +ENDCLASS. diff --git a/lib/zcx_mockup_loader_error-raise.abap b/lib/zcx_mockup_loader_error-raise.abap new file mode 100644 index 0000000..bcc351e --- /dev/null +++ b/lib/zcx_mockup_loader_error-raise.abap @@ -0,0 +1,21 @@ +method RAISE. + data: + l_methname type string, + sys_call type sys_calls, + sys_stack type sys_callst. + + " Get stack information + call function 'SYSTEM_CALLSTACK' + exporting max_level = 2 + importing et_callstack = sys_stack. + + read table sys_stack into sys_call index 2. + l_methname = sys_call-eventname && '():'. + + raise exception type zcx_mockup_loader_error + exporting + methname = l_methname + msg = msg + code = code. + +endmethod. diff --git a/lib/zcx_mockup_loader_error.abap b/lib/zcx_mockup_loader_error.abap new file mode 100644 index 0000000..e044835 --- /dev/null +++ b/lib/zcx_mockup_loader_error.abap @@ -0,0 +1,79 @@ +class ZCX_MOCKUP_LOADER_ERROR definition + public + inheriting from CX_STATIC_CHECK + final + create public . + +public section. + + interfaces IF_T100_MESSAGE . + + constants: + begin of ZCX_MOCKUP_LOADER_ERROR, + msgid type symsgid value '0M', + msgno type symsgno value '500', + attr1 type scx_attrname value 'METHNAME', + attr2 type scx_attrname value 'MSG', + attr3 type scx_attrname value '', + attr4 type scx_attrname value '', + end of ZCX_MOCKUP_LOADER_ERROR . + data METHNAME type SCX_ATTRNAME read-only . + data MSG type SCX_ATTRNAME read-only . + data CODE type CHAR2 read-only . + + methods CONSTRUCTOR + importing + !TEXTID like IF_T100_MESSAGE=>T100KEY optional + !PREVIOUS like PREVIOUS optional + !METHNAME type SCX_ATTRNAME optional + !MSG type SCX_ATTRNAME optional + !CODE type CHAR2 optional . + class-methods RAISE + importing + !MSG type STRING + !CODE type CHAR2 optional + raising + ZCX_MOCKUP_LOADER_ERROR . +endclass. + +class ZCX_MOCKUP_LOADER_ERROR implementation. + + method CONSTRUCTOR. + CALL METHOD SUPER->CONSTRUCTOR + EXPORTING + PREVIOUS = PREVIOUS + . + me->METHNAME = METHNAME . + me->MSG = MSG . + me->CODE = CODE . + clear me->textid. + if textid is initial. + IF_T100_MESSAGE~T100KEY = ZCX_MOCKUP_LOADER_ERROR . + else. + IF_T100_MESSAGE~T100KEY = TEXTID. + endif. + endmethod. + + method RAISE. + data: + l_methname type string, + sys_call type sys_calls, + sys_stack type sys_callst. + + " Get stack information + call function 'SYSTEM_CALLSTACK' + exporting max_level = 2 + importing et_callstack = sys_stack. + + read table sys_stack into sys_call index 2. + l_methname = sys_call-eventname && '():'. + + raise exception type zcx_mockup_loader_error + exporting + methname = l_methname + msg = msg + code = code. + + endmethod. + +endclass. diff --git a/test/zcl_mockup_loader-unit_test.abap b/test/zcl_mockup_loader-unit_test.abap new file mode 100644 index 0000000..10afe19 --- /dev/null +++ b/test/zcl_mockup_loader-unit_test.abap @@ -0,0 +1,880 @@ +*/--------------------------------------------------------------------------------\ +*| This file is part of Mockup loader | +*| | +*| The MIT License (MIT) | +*| | +*| Copyright (c) 2015 SBCG Team (www.sbcg.com.ua), Alexander Tsybulsky | +*| | +*| Permission is hereby granted, free of charge, to any person obtaining a copy | +*| of this software and associated documentation files (the "Software"), to deal | +*| in the Software without restriction, including without limitation the rights | +*| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | +*| copies of the Software, and to permit persons to whom the Software is | +*| furnished to do so, subject to the following conditions: | +*| | +*| The above copyright notice and this permission notice shall be included in all | +*| copies or substantial portions of the Software. | +*| | +*| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | +*| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | +*| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | +*| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | +*| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | +*| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | +*| SOFTWARE. | +*\--------------------------------------------------------------------------------/ +*/--------------------------------------------------------------------------------\ +*| CONTRIBUTORS | +*|--------------------------------------------------------------------------------| +*| Leading developers : Alexander Tsybulsky (atsybulsky@sbcg.com.ua) | +*| Svetlana Shlapak (sshlapak@sbcg.com.ua) | +*| Testing and ideas: Bohdan Petruschak (b.petrushchak@sbcg.com.ua) | +*|--------------------------------------------------------------------------------| +*| project homepage: https://github.com/sbcgua/mockup_loader | +*\--------------------------------------------------------------------------------/ + +********************************************************************** +* MACRO +********************************************************************** + define test_parse. + clear dummy. + read table lo_struc_descr->components into ls_component with key name = '&1'. + call method o->parse_field + exporting + is_component = ls_component + i_data = &2 + importing + e_field = dummy-&1. + end-of-definition. + + define test_positive. + test_parse &1 &2. + assert_equals( act = dummy-&1 exp = &3 ). + end-of-definition. + + define test_negative. + test_parse &1 &2. + assert_differs( act = dummy-&1 exp = &3 ). + end-of-definition. + +********************************************************************** +* Test Class definition +********************************************************************** + +class lcl_test_mockup_loader definition for testing + duration short + inheriting from cl_aunit_assert risk level harmless. + +* ================ + public section. + + types: + begin of ty_dummy, + mandt type mandt, + tdate type datum, + tchar type char8, + tstring type string, + talpha type belnr_d, + tdecimal type wrbtr, + tnumber type gjahr, + tinteger type i, + end of ty_dummy. + + types: + tt_dummy type table of ty_dummy. + +* ================ + private section. + + data o type ref to zcl_mockup_loader. "class under test + + class-methods: class_setup. + methods: setup. + + methods: read_zip for testing. + methods: integrated_test for testing. + + methods: parse_data for testing. + methods: parse_field for testing. + methods: empty_lines for testing. + methods: map_file_structure for testing. + + methods: store_retrieve for testing. + methods: retrieve_types for testing. + methods: store_retrieve_with_key for testing. + methods: load_and_store for testing. + + methods: get_dummy_data + importing + i_strict type abap_bool default abap_true + exporting + e_dummy_struc type ty_dummy + e_dummy_tab type tt_dummy + e_dummy_string type string. + +endclass. "lcl_test_mockup_loader + +* Friends +class zcl_mockup_loader definition local friends lcl_test_mockup_loader. + +********************************************************************** +* Implementation +********************************************************************** + +class lcl_test_mockup_loader implementation. + +********************************************************************** +* Setup methods +********************************************************************** + method class_setup. + zcl_mockup_loader=>class_set_source( i_type = 'MIME' i_path = 'ZMOCKUP_LOADER_UNIT_TEST' ). + endmethod. "class_setup + + method setup. + data lo_ex type ref to zcx_mockup_loader_error. + + try. + o = zcl_mockup_loader=>get_instance( ). + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + endmethod. "setup + +********************************************************************** +* Dummy data generation +********************************************************************** + method get_dummy_data. + data l_string type string. + + if i_strict = abap_true. + l_string = 'MANDT\tTDATE\tTCHAR\tTSTRING\tTALPHA\tTDECIMAL\tTNUMBER\tTINTEGER\n' + && '\t01.01.2015\tTrololo1\tString1\t100000\t1234567,81\t2015\t1111\n' + && '\t02.01.2015\tTrololo2\tString2\t200000\t1234567,82\t2016\t2222\n' . + else. + l_string = 'TDATE\tTSTRING\tTCHAR\tTDECIMAL\tTNUMBER\n' + && '01.01.2015\tString1\tTrololo1\t1234567,81\t2015\n' + && '02.01.2015\tString2\tTrololo2\t1234567,82\t2016\n' . + endif. + + replace all occurrences of '\t' in l_string with cl_abap_char_utilities=>horizontal_tab. + replace all occurrences of '\n' in l_string with cl_abap_char_utilities=>cr_lf. + + clear e_dummy_tab. + + e_dummy_struc-tdate = '20150101'. + e_dummy_struc-tchar = 'Trololo1'. + e_dummy_struc-tstring = 'String1'. + e_dummy_struc-tdecimal = '1234567.81'. + e_dummy_struc-tnumber = 2015. + if i_strict = abap_true. + e_dummy_struc-tinteger = 1111. + e_dummy_struc-talpha = '0000100000'. + endif. + append e_dummy_struc to e_dummy_tab. + + e_dummy_struc-tdate = '20150102'. + e_dummy_struc-tchar = 'Trololo2'. + e_dummy_struc-tstring = 'String2'. + e_dummy_struc-tdecimal = '1234567.82'. + e_dummy_struc-tnumber = 2016. + if i_strict = abap_true. + e_dummy_struc-tinteger = 2222. + e_dummy_struc-talpha = '0000200000'. + endif. + append e_dummy_struc to e_dummy_tab. + + read table e_dummy_tab into e_dummy_struc index 1. + e_dummy_string = l_string. + + endmethod. " get_dummy_data + +********************************************************************** +* Simple integrated test - most basic usage of the class +********************************************************************** + method integrated_test. + data: + dummy_act type ty_dummy, + dummy_exp type ty_dummy, + dummy_tab_act type tt_dummy, + dummy_tab_exp type tt_dummy, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_struc = dummy_exp + e_dummy_tab = dummy_tab_exp. + + " Strict ******************************************************** + try. + call method o->load_data + exporting i_obj = 'testdir/testfile_complete' + importing e_container = dummy_tab_act. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + call method o->load_data + exporting i_obj = 'testdir/testfile_complete' + importing e_container = dummy_act. + + assert_equals( act = dummy_act exp = dummy_exp ). + + call method o->load_data " No MANDT field in file + exporting i_obj = 'testdir/testfile_no_mandt' + importing e_container = dummy_tab_act. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + " NOT Strict **************************************************** + call method get_dummy_data + exporting i_strict = abap_false + importing + e_dummy_tab = dummy_tab_exp. + + try. + call method o->load_data + exporting i_obj = 'testdir/testfile_no_strict' + i_strict = abap_false + importing e_container = dummy_tab_act. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + endmethod. " integrated_test + +********************************************************************** +* Test of data parser - dummy data is supplied to the tested method +********************************************************************** + method parse_data. + data: + dummy_val type char40, + dummy_act type ty_dummy, + dummy_tab_act type tt_dummy, + dummy_htab type hashed table of ty_dummy with unique key tdate, + dummy_stab type sorted table of ty_dummy with unique key tdate, + dummy_exp type ty_dummy, + dummy_tab_exp type tt_dummy, + l_string type string, + lo_ex type ref to zcx_mockup_loader_error. + + " Strict parsing ********************************* + call method get_dummy_data + importing + e_dummy_struc = dummy_exp + e_dummy_tab = dummy_tab_exp + e_dummy_string = l_string. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_act. + + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_act exp = dummy_exp ). + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Parse to sorted and hashed tables *************** + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_stab. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_stab exp = dummy_tab_exp ). + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_htab. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_htab exp = dummy_tab_exp ). + + " NOT STRICT parsing ****************************** + call method get_dummy_data + exporting + i_strict = abap_false + importing + e_dummy_tab = dummy_tab_exp + e_dummy_string = l_string. + + try. + call method o->parse_data + exporting i_rawdata = l_string + i_strict = '' + importing e_container = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Fields out of bound (more fields than in header) *** + clear lo_ex. + call method get_dummy_data importing e_dummy_string = l_string. + replace first occurrence of '1111' in l_string + with '1111' && cl_abap_char_utilities=>horizontal_tab && 'EXCESS_FIELD'. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = '>H' act = lo_ex->code ). + + " Fields out of bound (less fields than in header) *** + clear lo_ex. + call method get_dummy_data importing e_dummy_string = l_string. + replace first occurrence of cl_abap_char_utilities=>horizontal_tab && '1111' + in l_string with ''. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'code ). + + " Parse to field (not table or structure) ************* + clear lo_ex. + call method get_dummy_data importing e_dummy_string = l_string. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_val. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'DT' act = lo_ex->code ). + + endmethod. "parse_Data + +********************************************************************** +* Individual field parsing test +********************************************************************** + method parse_field. + data: + dummy type ty_dummy, + lo_struc_descr type ref to cl_abap_structdescr, + ls_component type abap_compdescr, + lo_ex type ref to zcx_mockup_loader_error. + + lo_struc_descr ?= cl_abap_structdescr=>describe_by_data( dummy ). + + " Positive tests ****************************** + try. + test_positive TDATE '01.01.2015' '20150101'. + test_positive TCHAR 'ABC' 'ABC'. + test_positive TSTRING 'The string test' 'The string test'. + test_positive TALPHA '100000' '0000100000'. + test_positive TDECIMAL '1234,12' '1234.12'. + test_negative TDECIMAL '1234.12' '1234.12'. + test_positive TNUMBER '2015' '2015'. + test_positive TINTEGER '123' 123. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + " Negative tests (1) ************************** + clear lo_ex. + try. test_parse TDATE '01.012015'. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'PF' act = lo_ex->code ). + + " Negative tests (2) ************************** + clear lo_ex. + try. test_parse TNUMBER '20ha'. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'PF' act = lo_ex->code ). + + endmethod. "parse_Field + +********************************************************************** +* ZIP file read test - gets data from SMW0 ZMOCKUP_LOADER_UNIT_TEST +********************************************************************** + method read_zip. + data: + l_filename type string, + l_str type string, + lo_ex type ref to zcx_mockup_loader_error. + + assert_not_initial( act = lines( o->o_zip->files ) ). + + l_filename = 'testdir/testfile_complete.txt'. + + " Positive *************************************** + try. + call method o->read_zip + exporting i_name = l_filename + importing e_rawdata = l_str. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_not_initial( act = l_str ). + + " Negative *************************************** + l_filename = l_filename && 'XYZ'. + try. + call method o->read_zip + exporting i_name = l_filename + importing e_rawdata = l_str. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'ZF' act = lo_ex->code ). + + endmethod. " read_zip + +********************************************************************** +* Identification of empty lines in the text files +********************************************************************** + method empty_lines. + data: + dummy_tab_exp type tt_dummy, + dummy_tab_act type tt_dummy, + l_string type string, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_tab = dummy_tab_exp + e_dummy_string = l_string. + + " Add empty line at the end ***************************** + l_string = l_string && cl_abap_char_utilities=>cr_lf. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Add empty line in the middle *************************** + replace first occurrence of cl_abap_char_utilities=>cr_lf in l_string + with cl_abap_char_utilities=>cr_lf && cl_abap_char_utilities=>cr_lf. + clear lo_ex. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'LE' act = lo_ex->code ). + + " Add empty line at the beginning ************************ + l_string = cl_abap_char_utilities=>cr_lf && l_string. + clear lo_ex. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'HE' act = lo_ex->code ). + + endmethod. "empty_lines + +********************************************************************** +* Test check of in and out data types +********************************************************************** + method map_file_structure. + data: + dummy_tab_exp type tt_dummy, + dummy_tab_act type tt_dummy, + l_string type string, + l_string_bak type string, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_tab = dummy_tab_exp + e_dummy_string = l_string_bak. + + " Duplicate field names ******************************* + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TCHAR' in l_string with 'TDATE'. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'DN' act = lo_ex->code ). + + " Empty field names *********************************** + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TCHAR' in l_string with ''. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'EN' act = lo_ex->code ). + + " Unknown field in text ******************************* + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TCHAR' in l_string with 'UNKNOWN'. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'MC' act = lo_ex->code ). + + " More fields than in target structure **************** + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TINTEGER' in l_string + with 'TINTEGER' && cl_abap_char_utilities=>horizontal_tab && 'EXCESS_FIELD'. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'CN' act = lo_ex->code ). + + " Empty field at the end ****************************** + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TINTEGER' in l_string + with 'TINTEGER' && cl_abap_char_utilities=>horizontal_tab. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'EN' act = lo_ex->code ). + + " Empty field at the end of data line ****************** + clear lo_ex. l_string = l_string_bak. + replace first occurrence of '1111' in l_string + with '1111' && cl_abap_char_utilities=>horizontal_tab. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = '>H' act = lo_ex->code ). + + + endmethod. "map_file_structure + +********************************************************************** +* STORE tests - basic functionality +********************************************************************** + method store_retrieve. + data: + dummy_exp type ty_dummy, + dummy_tab_exp type tt_dummy, + dummy_act type ty_dummy, + dummy_tab_act type tt_dummy, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_struc = dummy_exp + e_dummy_tab = dummy_tab_exp. + + " Instance method ******************************** + try. + o->store( i_name = 'STRUC' i_data = dummy_exp ). + o->store( i_name = 'TAB' i_data = dummy_tab_exp ). + + call method o->_retrieve + exporting i_name = 'STRUC' + importing e_data = dummy_act. + + call method o->_retrieve + exporting i_name = 'TAB' + importing e_data = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_act exp = dummy_exp ). + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Instance method - NEGATIVE ********************** + try. + call method o->_retrieve + exporting i_name = 'NOT_EXISTING' + importing e_data = dummy_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'NF' act = lo_ex->code ). + + " Static method *********************************** + clear: dummy_act, dummy_tab_act. + + call method zcl_mockup_loader=>retrieve + exporting i_name = 'STRUC' + importing e_data = dummy_act + exceptions others = 4. + + call method zcl_mockup_loader=>retrieve + exporting i_name = 'TAB' + importing e_data = dummy_tab_act + exceptions others = 4. + + assert_subrc( act = sy-subrc ). + assert_equals( act = dummy_act exp = dummy_exp ). + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Static method - NEGATIVE ************************ + call method zcl_mockup_loader=>retrieve + exporting i_name = 'NOT_EXISTING' + importing e_data = dummy_act + exceptions others = 4. + + assert_subrc( act = sy-subrc exp = 4 ). + assert_equals( act = sy-msgno exp = 500 ). " 0M(500) -> & & & & + + endmethod. "store_retrieve + +********************************************************************** +* STORE RETRIEVE types checking test +********************************************************************** + method retrieve_types. + data: + lo_ex type ref to zcx_mockup_loader_error, + l_src type bset_tab, + l_dst_tab type bset_tab, + l_dst_tt type table of bset, + l_dst_ts type sorted table of bset with unique key bukrs, + l_dst_str type bset, + l_dst_dif type table of bkpf. + + append initial line to l_src. + try. o->store( i_name = 'DATA' i_data = l_src ). + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + " Store to different kinds of same table ******************* + try. + call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_tab. + call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_tt. + call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_ts. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + " Store to structure *************************************** + try. call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_str. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'TT' act = lo_ex->code ). + + " Store to table with different structure ****************** + clear lo_ex. + try. call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_dif. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'TS' act = lo_ex->code ). + + endmethod. "retrieve_types + +********************************************************************** +* STORE RETRIEVE with table key and sieving (filtering) +********************************************************************** + method store_retrieve_with_key. + data: + dummy_exp type ty_dummy, + dummy_tab_exp type tt_dummy, + dummy_act type ty_dummy, + dummy_tab_act type tt_dummy, + ls_bset type bset, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_struc = dummy_exp + e_dummy_tab = dummy_tab_exp. + + try. o->store( i_name = 'TAB' i_data = dummy_tab_exp i_tabkey = 'TNUMBER' ). + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + delete dummy_tab_exp index 1. + + " Positive ***************************************** + try. + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2015' + importing e_data = dummy_act. + + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2016' + importing e_data = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_act exp = dummy_exp ). + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Retrieve to wrong structure ********************** + clear lo_ex. + try. + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2015' + importing e_data = ls_bset. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'TS' act = lo_ex->code ). + + " Retrieve - no data selected ********************** + clear lo_ex. + try. + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2000' + importing e_data = dummy_tab_act. " Table + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = '04' act = lo_ex->code ). + + clear lo_ex. + try. + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2000' + importing e_data = dummy_act. " Structure + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = '04' act = lo_ex->code ). + + + " Save structure ************************************ + clear lo_ex. + try. o->store( i_name = 'STRUC' i_data = dummy_exp i_tabkey = 'TNUMBER' ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'TO' act = lo_ex->code ). + + " Tab key that does not exist in the structure ****** + clear lo_ex. + try. o->store( i_name = 'TAB' i_data = dummy_tab_exp i_tabkey = 'UNDEFINED' ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'FM' act = lo_ex->code ). + + endmethod. "store_retrieve_with_key + +********************************************************************** +* LOAD AND STORE at once +********************************************************************** + method load_and_store. + data: + dummy_tab_exp type tt_dummy, + dummy_tab_act type tt_dummy, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing e_dummy_tab = dummy_tab_exp. + + " Positive test ************************************ + + try. + call method o->load_and_store + exporting i_obj = 'testdir/testfile_complete' + i_name = 'TAB' + i_type = 'LCL_TEST_MOCKUP_LOADER=>TT_DUMMY'. + + call method o->_retrieve + exporting i_name = 'TAB' + importing e_data = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Negative: type that not exists ******************** + + clear lo_ex. + try. + call method o->load_and_store + exporting i_obj = 'testdir/testfile_complete' + i_name = 'TAB' + i_type = '************'. + + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'WT' act = lo_ex->code ). + + endmethod. "load_and_store + +endclass. "lcl_Test_Mockup_Loader diff --git a/zmockup_loader-0.1.nugg b/zmockup_loader-0.1.nugg new file mode 100644 index 0000000..d6ae511 --- /dev/null +++ b/zmockup_loader-0.1.nugg @@ -0,0 +1,1722 @@ + + + + + + + * Local definitions and classes + *"* use this source file for any type of declarations (class +*"* definitions, interfaces or type declarations) you need for +*"* components in the private section + *"* use this source file for any macro definitions you need +*"* in the implementation part of the class + */--------------------------------------------------------------------------------\ +*| This file is part of Mockup loader | +*| | +*| The MIT License (MIT) | +*| | +*| Copyright (c) 2015 SBCG Team (www.sbcg.com.ua), Alexander Tsybulsky | +*| | +*| Permission is hereby granted, free of charge, to any person obtaining a copy | +*| of this software and associated documentation files (the "Software"), to deal | +*| in the Software without restriction, including without limitation the rights | +*| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | +*| copies of the Software, and to permit persons to whom the Software is | +*| furnished to do so, subject to the following conditions: | +*| | +*| The above copyright notice and this permission notice shall be included in all | +*| copies or substantial portions of the Software. | +*| | +*| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | +*| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | +*| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | +*| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | +*| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | +*| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | +*| SOFTWARE. | +*\--------------------------------------------------------------------------------/ +*/--------------------------------------------------------------------------------\ +*| CONTRIBUTORS | +*|--------------------------------------------------------------------------------| +*| Leading developers : Alexander Tsybulsky (atsybulsky@sbcg.com.ua) | +*| Svetlana Shlapak (sshlapak@sbcg.com.ua) | +*| Testing and ideas: Bohdan Petruschak (b.petrushchak@sbcg.com.ua) | +*|--------------------------------------------------------------------------------| +*| project homepage: https://github.com/sbcgua/mockup_loader | +*\--------------------------------------------------------------------------------/ + +********************************************************************** +* MACRO +********************************************************************** + define test_parse. + clear dummy. + read table lo_struc_descr->components into ls_component with key name = '&1'. + call method o->parse_field + exporting + is_component = ls_component + i_data = &2 + importing + e_field = dummy-&1. + end-of-definition. + + define test_positive. + test_parse &1 &2. + assert_equals( act = dummy-&1 exp = &3 ). + end-of-definition. + + define test_negative. + test_parse &1 &2. + assert_differs( act = dummy-&1 exp = &3 ). + end-of-definition. + +********************************************************************** +* Test Class definition +********************************************************************** + +class lcl_test_mockup_loader definition for testing + duration short + inheriting from cl_aunit_assert risk level harmless. + +* ================ + public section. + + types: + begin of ty_dummy, + mandt type mandt, + tdate type datum, + tchar type char8, + tstring type string, + talpha type belnr_d, + tdecimal type wrbtr, + tnumber type gjahr, + tinteger type i, + end of ty_dummy. + + types: + tt_dummy type table of ty_dummy. + +* ================ + private section. + + data o type ref to zcl_mockup_loader. "class under test + + class-methods: class_setup. + methods: setup. + + methods: read_zip for testing. + methods: integrated_test for testing. + + methods: parse_data for testing. + methods: parse_field for testing. + methods: empty_lines for testing. + methods: map_file_structure for testing. + + methods: store_retrieve for testing. + methods: retrieve_types for testing. + methods: store_retrieve_with_key for testing. + methods: load_and_store for testing. + + methods: get_dummy_data + importing + i_strict type abap_bool default abap_true + exporting + e_dummy_struc type ty_dummy + e_dummy_tab type tt_dummy + e_dummy_string type string. + +endclass. "lcl_test_mockup_loader + +* Friends +class zcl_mockup_loader definition local friends lcl_test_mockup_loader. + +********************************************************************** +* Implementation +********************************************************************** + +class lcl_test_mockup_loader implementation. + +********************************************************************** +* Setup methods +********************************************************************** + method class_setup. + zcl_mockup_loader=>class_set_source( i_type = 'MIME' i_path = 'ZMOCKUP_LOADER_UNIT_TEST' ). + endmethod. "class_setup + + method setup. + data lo_ex type ref to zcx_mockup_loader_error. + + try. + o = zcl_mockup_loader=>get_instance( ). + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + endmethod. "setup + +********************************************************************** +* Dummy data generation +********************************************************************** + method get_dummy_data. + data l_string type string. + + if i_strict = abap_true. + l_string = 'MANDT\tTDATE\tTCHAR\tTSTRING\tTALPHA\tTDECIMAL\tTNUMBER\tTINTEGER\n' + && '\t01.01.2015\tTrololo1\tString1\t100000\t1234567,81\t2015\t1111\n' + && '\t02.01.2015\tTrololo2\tString2\t200000\t1234567,82\t2016\t2222\n' . + else. + l_string = 'TDATE\tTSTRING\tTCHAR\tTDECIMAL\tTNUMBER\n' + && '01.01.2015\tString1\tTrololo1\t1234567,81\t2015\n' + && '02.01.2015\tString2\tTrololo2\t1234567,82\t2016\n' . + endif. + + replace all occurrences of '\t' in l_string with cl_abap_char_utilities=>horizontal_tab. + replace all occurrences of '\n' in l_string with cl_abap_char_utilities=>cr_lf. + + clear e_dummy_tab. + + e_dummy_struc-tdate = '20150101'. + e_dummy_struc-tchar = 'Trololo1'. + e_dummy_struc-tstring = 'String1'. + e_dummy_struc-tdecimal = '1234567.81'. + e_dummy_struc-tnumber = 2015. + if i_strict = abap_true. + e_dummy_struc-tinteger = 1111. + e_dummy_struc-talpha = '0000100000'. + endif. + append e_dummy_struc to e_dummy_tab. + + e_dummy_struc-tdate = '20150102'. + e_dummy_struc-tchar = 'Trololo2'. + e_dummy_struc-tstring = 'String2'. + e_dummy_struc-tdecimal = '1234567.82'. + e_dummy_struc-tnumber = 2016. + if i_strict = abap_true. + e_dummy_struc-tinteger = 2222. + e_dummy_struc-talpha = '0000200000'. + endif. + append e_dummy_struc to e_dummy_tab. + + read table e_dummy_tab into e_dummy_struc index 1. + e_dummy_string = l_string. + + endmethod. " get_dummy_data + +********************************************************************** +* Simple integrated test - most basic usage of the class +********************************************************************** + method integrated_test. + data: + dummy_act type ty_dummy, + dummy_exp type ty_dummy, + dummy_tab_act type tt_dummy, + dummy_tab_exp type tt_dummy, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_struc = dummy_exp + e_dummy_tab = dummy_tab_exp. + + " Strict ******************************************************** + try. + call method o->load_data + exporting i_obj = 'testdir/testfile_complete' + importing e_container = dummy_tab_act. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + call method o->load_data + exporting i_obj = 'testdir/testfile_complete' + importing e_container = dummy_act. + + assert_equals( act = dummy_act exp = dummy_exp ). + + call method o->load_data " No MANDT field in file + exporting i_obj = 'testdir/testfile_no_mandt' + importing e_container = dummy_tab_act. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + " NOT Strict **************************************************** + call method get_dummy_data + exporting i_strict = abap_false + importing + e_dummy_tab = dummy_tab_exp. + + try. + call method o->load_data + exporting i_obj = 'testdir/testfile_no_strict' + i_strict = abap_false + importing e_container = dummy_tab_act. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + endmethod. " integrated_test + +********************************************************************** +* Test of data parser - dummy data is supplied to the tested method +********************************************************************** + method parse_data. + data: + dummy_val type char40, + dummy_act type ty_dummy, + dummy_tab_act type tt_dummy, + dummy_htab type hashed table of ty_dummy with unique key tdate, + dummy_stab type sorted table of ty_dummy with unique key tdate, + dummy_exp type ty_dummy, + dummy_tab_exp type tt_dummy, + l_string type string, + lo_ex type ref to zcx_mockup_loader_error. + + " Strict parsing ********************************* + call method get_dummy_data + importing + e_dummy_struc = dummy_exp + e_dummy_tab = dummy_tab_exp + e_dummy_string = l_string. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_act. + + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_act exp = dummy_exp ). + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Parse to sorted and hashed tables *************** + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_stab. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_stab exp = dummy_tab_exp ). + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_htab. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_htab exp = dummy_tab_exp ). + + " NOT STRICT parsing ****************************** + call method get_dummy_data + exporting + i_strict = abap_false + importing + e_dummy_tab = dummy_tab_exp + e_dummy_string = l_string. + + try. + call method o->parse_data + exporting i_rawdata = l_string + i_strict = '' + importing e_container = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Fields out of bound (more fields than in header) *** + clear lo_ex. + call method get_dummy_data importing e_dummy_string = l_string. + replace first occurrence of '1111' in l_string + with '1111' && cl_abap_char_utilities=>horizontal_tab && 'EXCESS_FIELD'. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = '>H' act = lo_ex->code ). + + " Fields out of bound (less fields than in header) *** + clear lo_ex. + call method get_dummy_data importing e_dummy_string = l_string. + replace first occurrence of cl_abap_char_utilities=>horizontal_tab && '1111' + in l_string with ''. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = '<H' act = lo_ex->code ). + + " Parse to field (not table or structure) ************* + clear lo_ex. + call method get_dummy_data importing e_dummy_string = l_string. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_val. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'DT' act = lo_ex->code ). + + endmethod. "parse_Data + +********************************************************************** +* Individual field parsing test +********************************************************************** + method parse_field. + data: + dummy type ty_dummy, + lo_struc_descr type ref to cl_abap_structdescr, + ls_component type abap_compdescr, + lo_ex type ref to zcx_mockup_loader_error. + + lo_struc_descr ?= cl_abap_structdescr=>describe_by_data( dummy ). + + " Positive tests ****************************** + try. + test_positive TDATE '01.01.2015' '20150101'. + test_positive TCHAR 'ABC' 'ABC'. + test_positive TSTRING 'The string test' 'The string test'. + test_positive TALPHA '100000' '0000100000'. + test_positive TDECIMAL '1234,12' '1234.12'. + test_negative TDECIMAL '1234.12' '1234.12'. + test_positive TNUMBER '2015' '2015'. + test_positive TINTEGER '123' 123. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + " Negative tests (1) ************************** + clear lo_ex. + try. test_parse TDATE '01.012015'. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'PF' act = lo_ex->code ). + + " Negative tests (2) ************************** + clear lo_ex. + try. test_parse TNUMBER '20ha'. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'PF' act = lo_ex->code ). + + endmethod. "parse_Field + +********************************************************************** +* ZIP file read test - gets data from SMW0 ZMOCKUP_LOADER_UNIT_TEST +********************************************************************** + method read_zip. + data: + l_filename type string, + l_str type string, + lo_ex type ref to zcx_mockup_loader_error. + + assert_not_initial( act = lines( o->o_zip->files ) ). + + l_filename = 'testdir/testfile_complete.txt'. + + " Positive *************************************** + try. + call method o->read_zip + exporting i_name = l_filename + importing e_rawdata = l_str. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_not_initial( act = l_str ). + + " Negative *************************************** + l_filename = l_filename && 'XYZ'. + try. + call method o->read_zip + exporting i_name = l_filename + importing e_rawdata = l_str. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'ZF' act = lo_ex->code ). + + endmethod. " read_zip + +********************************************************************** +* Identification of empty lines in the text files +********************************************************************** + method empty_lines. + data: + dummy_tab_exp type tt_dummy, + dummy_tab_act type tt_dummy, + l_string type string, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_tab = dummy_tab_exp + e_dummy_string = l_string. + + " Add empty line at the end ***************************** + l_string = l_string && cl_abap_char_utilities=>cr_lf. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Add empty line in the middle *************************** + replace first occurrence of cl_abap_char_utilities=>cr_lf in l_string + with cl_abap_char_utilities=>cr_lf && cl_abap_char_utilities=>cr_lf. + clear lo_ex. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'LE' act = lo_ex->code ). + + " Add empty line at the beginning ************************ + l_string = cl_abap_char_utilities=>cr_lf && l_string. + clear lo_ex. + + try. + call method o->parse_data + exporting i_rawdata = l_string + importing e_container = dummy_tab_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'HE' act = lo_ex->code ). + + endmethod. "empty_lines + +********************************************************************** +* Test check of in and out data types +********************************************************************** + method map_file_structure. + data: + dummy_tab_exp type tt_dummy, + dummy_tab_act type tt_dummy, + l_string type string, + l_string_bak type string, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_tab = dummy_tab_exp + e_dummy_string = l_string_bak. + + " Duplicate field names ******************************* + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TCHAR' in l_string with 'TDATE'. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'DN' act = lo_ex->code ). + + " Empty field names *********************************** + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TCHAR' in l_string with ''. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'EN' act = lo_ex->code ). + + " Unknown field in text ******************************* + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TCHAR' in l_string with 'UNKNOWN'. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'MC' act = lo_ex->code ). + + " More fields than in target structure **************** + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TINTEGER' in l_string + with 'TINTEGER' && cl_abap_char_utilities=>horizontal_tab && 'EXCESS_FIELD'. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'CN' act = lo_ex->code ). + + " Empty field at the end ****************************** + clear lo_ex. l_string = l_string_bak. + replace first occurrence of 'TINTEGER' in l_string + with 'TINTEGER' && cl_abap_char_utilities=>horizontal_tab. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = 'EN' act = lo_ex->code ). + + " Empty field at the end of data line ****************** + clear lo_ex. l_string = l_string_bak. + replace first occurrence of '1111' in l_string + with '1111' && cl_abap_char_utilities=>horizontal_tab. + + try. o->parse_data( exporting i_rawdata = l_string importing e_container = dummy_tab_act ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( lo_ex ). + assert_equals( exp = '>H' act = lo_ex->code ). + + + endmethod. "map_file_structure + +********************************************************************** +* STORE tests - basic functionality +********************************************************************** + method store_retrieve. + data: + dummy_exp type ty_dummy, + dummy_tab_exp type tt_dummy, + dummy_act type ty_dummy, + dummy_tab_act type tt_dummy, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_struc = dummy_exp + e_dummy_tab = dummy_tab_exp. + + " Instance method ******************************** + try. + o->store( i_name = 'STRUC' i_data = dummy_exp ). + o->store( i_name = 'TAB' i_data = dummy_tab_exp ). + + call method o->_retrieve + exporting i_name = 'STRUC' + importing e_data = dummy_act. + + call method o->_retrieve + exporting i_name = 'TAB' + importing e_data = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_act exp = dummy_exp ). + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Instance method - NEGATIVE ********************** + try. + call method o->_retrieve + exporting i_name = 'NOT_EXISTING' + importing e_data = dummy_act. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'NF' act = lo_ex->code ). + + " Static method *********************************** + clear: dummy_act, dummy_tab_act. + + call method zcl_mockup_loader=>retrieve + exporting i_name = 'STRUC' + importing e_data = dummy_act + exceptions others = 4. + + call method zcl_mockup_loader=>retrieve + exporting i_name = 'TAB' + importing e_data = dummy_tab_act + exceptions others = 4. + + assert_subrc( act = sy-subrc ). + assert_equals( act = dummy_act exp = dummy_exp ). + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Static method - NEGATIVE ************************ + call method zcl_mockup_loader=>retrieve + exporting i_name = 'NOT_EXISTING' + importing e_data = dummy_act + exceptions others = 4. + + assert_subrc( act = sy-subrc exp = 4 ). + assert_equals( act = sy-msgno exp = 500 ). " 0M(500) -> & & & & + + endmethod. "store_retrieve + +********************************************************************** +* STORE RETRIEVE types checking test +********************************************************************** + method retrieve_types. + data: + lo_ex type ref to zcx_mockup_loader_error, + l_src type bset_tab, + l_dst_tab type bset_tab, + l_dst_tt type table of bset, + l_dst_ts type sorted table of bset with unique key bukrs, + l_dst_str type bset, + l_dst_dif type table of bkpf. + + append initial line to l_src. + try. o->store( i_name = 'DATA' i_data = l_src ). + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + " Store to different kinds of same table ******************* + try. + call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_tab. + call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_tt. + call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_ts. + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + " Store to structure *************************************** + try. call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_str. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'TT' act = lo_ex->code ). + + " Store to table with different structure ****************** + clear lo_ex. + try. call method o->_retrieve exporting i_name = 'DATA' importing e_data = l_dst_dif. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'TS' act = lo_ex->code ). + + endmethod. "retrieve_types + +********************************************************************** +* STORE RETRIEVE with table key and sieving (filtering) +********************************************************************** + method store_retrieve_with_key. + data: + dummy_exp type ty_dummy, + dummy_tab_exp type tt_dummy, + dummy_act type ty_dummy, + dummy_tab_act type tt_dummy, + ls_bset type bset, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing + e_dummy_struc = dummy_exp + e_dummy_tab = dummy_tab_exp. + + try. o->store( i_name = 'TAB' i_data = dummy_tab_exp i_tabkey = 'TNUMBER' ). + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + delete dummy_tab_exp index 1. + + " Positive ***************************************** + try. + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2015' + importing e_data = dummy_act. + + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2016' + importing e_data = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_act exp = dummy_exp ). + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Retrieve to wrong structure ********************** + clear lo_ex. + try. + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2015' + importing e_data = ls_bset. + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'TS' act = lo_ex->code ). + + " Retrieve - no data selected ********************** + clear lo_ex. + try. + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2000' + importing e_data = dummy_tab_act. " Table + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = '04' act = lo_ex->code ). + + clear lo_ex. + try. + call method o->_retrieve + exporting i_name = 'TAB' + i_sift = '2000' + importing e_data = dummy_act. " Structure + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = '04' act = lo_ex->code ). + + + " Save structure ************************************ + clear lo_ex. + try. o->store( i_name = 'STRUC' i_data = dummy_exp i_tabkey = 'TNUMBER' ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'TO' act = lo_ex->code ). + + " Tab key that does not exist in the structure ****** + clear lo_ex. + try. o->store( i_name = 'TAB' i_data = dummy_tab_exp i_tabkey = 'UNDEFINED' ). + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'FM' act = lo_ex->code ). + + endmethod. "store_retrieve_with_key + +********************************************************************** +* LOAD AND STORE at once +********************************************************************** + method load_and_store. + data: + dummy_tab_exp type tt_dummy, + dummy_tab_act type tt_dummy, + lo_ex type ref to zcx_mockup_loader_error. + + call method get_dummy_data + importing e_dummy_tab = dummy_tab_exp. + + " Positive test ************************************ + + try. + call method o->load_and_store + exporting i_obj = 'testdir/testfile_complete' + i_name = 'TAB' + i_type = 'LCL_TEST_MOCKUP_LOADER=>TT_DUMMY'. + + call method o->_retrieve + exporting i_name = 'TAB' + importing e_data = dummy_tab_act. + + catch zcx_mockup_loader_error into lo_ex. + fail( lo_ex->get_text( ) ). + endtry. + + assert_equals( act = dummy_tab_act exp = dummy_tab_exp ). + + " Negative: type that not exists ******************** + + clear lo_ex. + try. + call method o->load_and_store + exporting i_obj = 'testdir/testfile_complete' + i_name = 'TAB' + i_type = '************'. + + catch zcx_mockup_loader_error into lo_ex. + endtry. + + assert_not_initial( act = lo_ex ). + assert_equals( exp = 'WT' act = lo_ex->code ). + + endmethod. "load_and_store + +endclass. "lcl_Test_Mockup_Loader + + ABAP + + + + + + + + method class_constructor. + class_set_source( i_type = 'MIME' i_path = '' ). " Defaults +endmethod. + + + + + method class_set_source. + check i_type = 'MIME' or i_type = 'FILE'. "TODO some more sophisticated error handling + + g_mockup_load_type = i_type. + g_mockup_load_path = i_path. +endmethod. + + + method free_instance. + if go_instance is not initial. + free go_instance. + endif. +endmethod. + + + + + method get_instance. + + if go_instance is initial. + create object go_instance. + call method go_instance->initialize. + endif. + + ro_instance = go_instance. + +endmethod. + + + + method initialize. + data: l_key type wwwdatatab, + l_xstring type xstring, + l_size type int4, + lt_w3mime type table of w3mime, + ls_w3mime type w3mime. + + " Load data + case g_mockup_load_type. + when 'MIME'. " Load from SMW0 + l_key-relid = 'MI'. + l_key-objid = g_mockup_load_path. + + call function 'WWWDATA_IMPORT' + exporting + key = l_key + tables + mime = lt_w3mime[] + exceptions + others = 1. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = 'SMW0 data import error' code = 'RE' ). "#EC NOTEXT + endif. + + describe table lt_w3mime lines l_size. + l_size = sy-tleng * sy-tfill. + + when 'FILE'. " Load from frontend + call function 'GUI_UPLOAD' + exporting + filename = g_mockup_load_path + filetype = 'BIN' + importing + filelength = l_size + tables + data_tab = lt_w3mime + exceptions + others = 1. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Cannot upload file: { g_mockup_load_path }| code = 'RE' ). "#EC NOTEXT + endif. + + when others. + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = 'Wrong source type' code = 'WS' ). "#EC NOTEXT + endif. + + endcase. + + " Convert to XString + call function 'SCMS_BINARY_TO_XSTRING' + exporting + input_length = l_size + importing + buffer = l_xstring + tables + binary_tab = lt_w3mime[] + exceptions + failed = 1. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( 'Binary to string error' ). "#EC NOTEXT + endif. + + " Extract zip + if o_zip is initial. + create object o_zip. + endif. + + call method o_zip->load + exporting zip = l_xstring + exceptions others = 4. + + if sy-subrc is not initial or lines( o_zip->files ) = 0. + zcx_mockup_loader_error=>raise( msg = 'ZIP load failed' code = 'ZE' ). "#EC NOTEXT + endif. +endmethod. + + + + + + + + + method load_and_store. + data: + lo_type type ref to cl_abap_typedescr, + lo_dtype type ref to cl_abap_datadescr, + lr_data type ref to data. + + field-symbols <data> type data. + + " Create container to load zip data to + call method cl_abap_typedescr=>describe_by_name + exporting p_name = i_type + receiving p_descr_ref = lo_type + exceptions others = 4. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Type { i_type } not found| code = 'WT' ). "#EC NOTEXT + endif. + + lo_dtype ?= lo_type. + + create data lr_data type handle lo_dtype. + assign lr_data->* to <data>. + if <data> is not assigned. + zcx_mockup_loader_error=>raise( 'Data cannot be assigned' ). "#EC NOTEXT + endif. + + " Load from zip and store + call method load_data + exporting + i_obj = i_obj + i_strict = i_strict + importing + e_container = <data>. + + call method _store + exporting + i_name = i_name + i_data_ref = lr_data + i_tabkey = i_tabkey. + +endmethod. + + + + + + + method load_data. + data l_rawdata type string. + + if e_container is not supplied. + zcx_mockup_loader_error=>raise( msg = 'No container supplied' code = 'NC' ). "#EC NOTEXT + endif. + + call method me->read_zip + exporting i_name = i_obj && '.txt' + importing e_rawdata = l_rawdata. + + call method me->parse_data + exporting + i_rawdata = l_rawdata + i_strict = i_strict + importing + e_container = e_container. + +endmethod. + + + + + + + method load_raw. + data l_filename type string. + + if e_content is not supplied. + zcx_mockup_loader_error=>raise( msg = 'No container supplied' code = 'NC' ). "#EC NOTEXT + endif. + + if i_ext is initial. + l_filename = i_obj && '.txt'. + else. + l_filename = i_obj && i_ext. + endif. + + call method o_zip->get + exporting name = l_filename + importing content = e_content. + +endmethod. + + + + + + + + method map_file_structure. + data: + l_tabcnt type i, + l_fieldcnt type i, + lt_fields type tt_string, + l_field_name type string, + lt_dupcheck type tt_string. + + split i_line at cl_abap_char_utilities=>horizontal_tab into table lt_fields. + + " Check if the line ends with TAB + find all occurrences of cl_abap_char_utilities=>horizontal_tab in i_line match count l_tabcnt. + if l_tabcnt = lines( lt_fields ). " Line ends with TAB, last empty field is not added to table, see help for 'split' + zcx_mockup_loader_error=>raise( msg = 'Empty field at the end' code = 'EN' ). "#EC NOTEXT + endif. + + " Compare number of fields, check structure similarity + if i_strict = abap_true. + l_fieldcnt = lines( lt_fields ). + + " MANDT field may be skipped + read table io_struc_descr->components with key name = 'MANDT' transporting no fields. + if sy-subrc is initial. " Found in strcuture components + read table lt_fields with key table_line = 'MANDT' transporting no fields. + if sy-subrc is not initial. " But not found in the file + add 1 to l_fieldcnt. + endif. + endif. + + if l_fieldcnt <> lines( io_struc_descr->components ). + zcx_mockup_loader_error=>raise( msg = 'Different columns number' code = 'CN' ). "#EC NOTEXT + endif. + endif. + + " Check duplicate field names in incoming structure + lt_dupcheck[] = lt_fields[]. + sort lt_dupcheck[]. + delete adjacent duplicates from lt_dupcheck[]. + if lines( lt_dupcheck ) <> lines( lt_fields ). + zcx_mockup_loader_error=>raise( msg = 'Duplicate field names found' code = 'DN' ). "#EC NOTEXT + endif. + + " Compare columns names and make map + loop at lt_fields into l_field_name. + if l_field_name is initial. " Check empty fields + zcx_mockup_loader_error=>raise( msg = 'Empty field name found' code = 'EN' ). "#EC NOTEXT + endif. + + read table io_struc_descr->components with key name = l_field_name transporting no fields. + if sy-subrc is initial. + append sy-tabix to et_map. + else. + zcx_mockup_loader_error=>raise( msg = |Column { l_field_name } not found in target structure| code = 'MC' ). "#EC NOTEXT + endif. + endloop. + +endmethod. "analyse_structure + + + + + + + method parse_apply_exit. + data l_fmname type rs38l_fnam value 'CONVERSION_EXIT_XXXXX_INPUT'. + + replace first occurrence of 'XXXXX' in l_fmname with i_convexit. + + call function 'FUNCTION_EXISTS' + exporting + funcname = l_fmname + exceptions + function_not_exist = 1 + others = 2. + + if sy-subrc <> 0. + zcx_mockup_loader_error=>raise( msg = 'Conversion exit not found' code = 'EM' ). "#EC NOTEXT + endif. + + call function l_fmname + exporting input = i_data + importing output = e_field + exceptions others = 1. + + if sy-subrc <> 0. + zcx_mockup_loader_error=>raise( msg = 'Conversion exit failed' code = 'EF' ). "#EC NOTEXT + endif. + +endmethod. + + + + + + + method parse_data. + data: + lt_lines type table of string, + ls_line type string, + lt_map type int4_table, + + lo_type_descr type ref to cl_abap_typedescr, + lo_table_descr type ref to cl_abap_tabledescr, + lo_struc_descr type ref to cl_abap_structdescr, + ref_tab_line type ref to data. + + field-symbols: + <table> type any table, + <container> type any. + + clear e_container. + + " Identify container type and create temp container + lo_type_descr = cl_abap_typedescr=>describe_by_data( e_container ). + case lo_type_descr->kind. + when 'T'. " Table + lo_table_descr ?= lo_type_descr. + lo_struc_descr ?= lo_table_descr->get_table_line_type( ). + create data ref_tab_line type handle lo_struc_descr. + assign ref_tab_line->* to <container>. + assign e_container to <table>. + when 'S'. " Structure + lo_struc_descr ?= lo_type_descr. + assign e_container to <container>. + when others. " Not a table or structure ? + zcx_mockup_loader_error=>raise( msg = 'Table or structure containers only' code = 'DT' ). "#EC NOTEXT + endcase. + + " Read and process header line + split i_rawdata at cl_abap_char_utilities=>cr_lf into table lt_lines. + read table lt_lines into ls_line index 1. + if sy-subrc <> 0. + zcx_mockup_loader_error=>raise( msg = 'No header line found in the file' code = 'NH' ). "#EC NOTEXT + endif. + if ls_line is initial. + zcx_mockup_loader_error=>raise( msg = 'Header line is empty' code = 'HE' ). "#EC NOTEXT + endif. + + delete lt_lines index 1. + + call method me->map_file_structure + exporting + i_line = ls_line + io_struc_descr = lo_struc_descr + i_strict = i_strict + importing + et_map = lt_map. + + " Main data parsing loop + loop at lt_lines into ls_line. + if ls_line is initial. " Check empty lines + check sy-tabix < lines( lt_lines ). " Last line of a file may be empty, others - not + zcx_mockup_loader_error=>raise( msg = |Empty line { sy-tabix + 1 } cannot be parsed| code = 'LE' ). "#EC NOTEXT + endif. + + call method parse_line + exporting + i_line = ls_line + io_struc_descr = lo_struc_descr + it_map = lt_map + i_index = sy-tabix + 1 + importing + es_container = <container>. + + " Only first line goes to structure and then exits + if lo_type_descr->kind = 'S'. " Structure + exit. + else. " Table + insert <container> into table <table>. + endif. + + endloop. + +endmethod. + + + + + + + method parse_field. + data l_mask type string. + + case is_component-type_kind. + when 'D'. " Date + call function 'CONVERT_DATE_TO_INTERNAL' + exporting + date_external = i_data + accept_initial_date = 'X' + importing + date_internal = e_field + exceptions + date_external_is_invalid = 1 + others = 2. + + when 'C'. " Char + convexits + describe field e_field edit mask l_mask. + if l_mask is initial. + e_field = i_data. + else. + shift l_mask left deleting leading '='. + call method me->parse_apply_exit + exporting + i_data = i_data + i_convexit = l_mask + importing + e_field = e_field. + endif. + + when 'g'. " String + e_field = i_data. + + when 'P'. " Amount + call function 'HRCM_STRING_TO_AMOUNT_CONVERT' + exporting + string = i_data + decimal_separator = ',' + thousands_separator = '.' + importing + betrg = e_field + exceptions + convert_error = 1 + others = 2. + + when 'N' or 'I'. " Integer number + if i_data co '0123456789'. + e_field = i_data. + else. + sy-subrc = 4. + endif. + + endcase. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Field: { is_component-name }| code = 'PF' ). "#EC NOTEXT + endif. + +endmethod. + + + + + + + + + method parse_line. + data: + l_tabcnt type i, + lt_fields type table of string, + ls_field type string, + ls_component type abap_compdescr, + l_index type int4. + + field-symbols <field> type any. + + clear es_container. + split i_line at cl_abap_char_utilities=>horizontal_tab into table lt_fields. + + " Count TABs, if line ends with TAB last empty field is not added to table, see help for 'split' + find all occurrences of cl_abap_char_utilities=>horizontal_tab in i_line match count l_tabcnt. + add 1 to l_tabcnt. " Number of fields in the line + + " Check field number is the same as in header + if l_tabcnt > lines( it_map ). + zcx_mockup_loader_error=>raise( msg = |More fields than in header @{ i_index }| code = '>H' ). "#EC NOTEXT + elseif l_tabcnt < lines( it_map ). + zcx_mockup_loader_error=>raise( msg = |Less fields than in header @{ i_index }| code = '<H' ). "#EC NOTEXT + endif. + + " Move data to table line + loop at lt_fields into ls_field. + read table it_map into l_index index sy-tabix. " Read map + + read table io_struc_descr->components into ls_component index l_index. " Get component + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( 'No component found?!' ). "#EC NOTEXT + endif. + + check ls_component-name ne 'MANDT'. " Skip client fields + + assign component ls_component-name of structure es_container to <field>. + if <field> is not assigned. + zcx_mockup_loader_error=>raise( 'Field assign failed?!' ). "#EC NOTEXT + endif. + + call method parse_field + exporting + is_component = ls_component + i_data = ls_field + importing + e_field = <field>. + + endloop. + +endmethod. + + + + method purge. + data l_store type ty_store. + + if i_name = '*'. " Delete all + loop at at_store into l_store. + free l_store-data. + endloop. + clear at_store. + + else. " Delete specific record + read table at_store with key name = i_name into l_store. + check sy-subrc is initial. + delete at_store index sy-tabix. + free l_store-data. + endif. + +endmethod. + + + + + + method read_zip. + data: + l_xstring type xstring, + lo_conv type ref to cl_abap_conv_in_ce, + l_ex type ref to cx_root. + + call method o_zip->get + exporting name = i_name + importing content = l_xstring + exceptions zip_index_error = 1. + + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Cannot read { i_name }| code = 'ZF' ). "#EC NOTEXT + endif. + + shift l_xstring left deleting leading cl_abap_char_utilities=>byte_order_mark_little in byte mode. + + try. + lo_conv = cl_abap_conv_in_ce=>create( encoding = '4103' ). " UTF16 + lo_conv->convert( exporting input = l_xstring importing data = e_rawdata ). + catch cx_root into l_ex. + zcx_mockup_loader_error=>raise( msg = 'Codepage conversion error' code = 'CP' ). "#EC NOTEXT + endtry. + +endmethod. + + + + + + + method retrieve. + data lo_ex type ref to zcx_mockup_loader_error. + + try . + get_instance( )->_retrieve( + exporting i_name = i_name + i_sift = i_sift + importing e_data = e_data ). + + catch zcx_mockup_loader_error into lo_ex. + + " Switch to non-class exceptions to ensure better code readability + " and compatibility with substituted select results + " e.g. zcl_mockup_loader=>retrieve( ... ). if sy_subrc is not initial ... + call method cl_message_helper=>set_msg_vars_for_if_t100_msg exporting text = lo_ex. + message id sy-msgid type sy-msgty number sy-msgno raising retrieve_error + with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. + + endtry. + +endmethod. + + + + + + + method store. + data lr_data type ref to data. + field-symbols <data> type any. + + " Create clone container + create data lr_data like i_data. + assign lr_data->* to <data>. + if <data> is not assigned. + zcx_mockup_loader_error=>raise( 'Data cannot be assigned' ). "#EC NOTEXT + endif. + + <data> = i_data. " Copy data to container + + call method _store + exporting + i_name = i_name + i_data_ref = lr_data + i_tabkey = i_tabkey. + +endmethod. + + + + + + + method _retrieve. + data: + l_store type ty_store, + r_data_tab type ref to data, + ld_src type ref to cl_abap_typedescr, + ld_dst type ref to cl_abap_typedescr, + ld_tab type ref to cl_abap_tabledescr, + ld_src_line type ref to cl_abap_structdescr, + ld_dst_line type ref to cl_abap_structdescr. + + field-symbols: + <line> type any, + <tabkey> type any, + <src_tab> type any table, + <tmp_tab> type standard table, + <data> type any. + + clear e_data. + + " Find store + read table at_store with key name = i_name into l_store. + if sy-subrc is not initial. + zcx_mockup_loader_error=>raise( msg = |Cannot find store { i_name }| code = 'NF' ). "#EC NOTEXT + endif. + + assign l_store-data->* to <data>. + if <data> is not assigned. + zcx_mockup_loader_error=>raise( 'Data cannot be assigned' ). "#EC NOTEXT + endif. + + " Ensure types are the same + ld_src = cl_abap_typedescr=>describe_by_data( <data> ). + ld_dst = cl_abap_typedescr=>describe_by_data( e_data ). + + if ld_src->kind = 'T'. + ld_tab ?= ld_src. + ld_src_line ?= ld_tab->get_table_line_type( ). + endif. + + " If types are not equal try going deeper to table line structure + if ld_src->absolute_name ne ld_dst->absolute_name. + if ld_src->kind = 'T' and ld_dst->kind = 'T'. " Table => Table + ld_tab ?= ld_dst. + ld_dst_line ?= ld_tab->get_table_line_type( ). + elseif i_sift is not initial and ld_src->kind = 'T' and ld_dst->kind = 'S'. " Table + filter => Structure + ld_dst_line ?= ld_dst. + else. + zcx_mockup_loader_error=>raise( msg = |Types differ for store { i_name }| code = 'TT' ). "#EC NOTEXT + endif. + + if ld_src_line->absolute_name ne ld_dst_line->absolute_name. + zcx_mockup_loader_error=>raise( msg = |Types differ for store { i_name }| code = 'TS' ). "#EC NOTEXT + endif. + endif. + + " Copy or sift (filter with tabkey) values + if i_sift is initial. + e_data = <data>. + + else. " Assuming ld_src->kind = 'T' -> see STORE + assert ld_src->kind = 'T'. + assert ld_dst->kind ca 'ST'. + assign l_store-data->* to <src_tab>. + + case ld_dst->kind. + when 'T'. " Table + " Create temporary table (needed because DST table can be hashed or sorted) + ld_tab = cl_abap_tabledescr=>create( + p_line_type = ld_src_line + p_table_kind = cl_abap_tabledescr=>tablekind_std + p_unique = abap_false ). + + create data r_data_tab type handle ld_tab. + assign r_data_tab->* to <tmp_tab>. + + loop at <src_tab> assigning <line>. + assign component l_store-tabkey of structure <line> to <tabkey>. + if <tabkey> is not assigned. + zcx_mockup_loader_error=>raise( msg = 'Tabkey field not found' code = 'FM' ). "#EC NOTEXT + endif. + check <tabkey> = i_sift. + append <line> to <tmp_tab>. + endloop. + + e_data = <tmp_tab>. + free r_data_tab. + + when 'S'. " Structure + read table <src_tab> into e_data with key (l_store-tabkey) = i_sift. "#EC CI_ANYSEQ + endcase. + endif. + + if e_data is initial. + zcx_mockup_loader_error=>raise( msg = 'No data returned' code = '04' ). "#EC NOTEXT + endif. + +endmethod. + + + + + + + method _store. + data: + l_store type ty_store, + lo_type type ref to cl_abap_typedescr, + lo_tab_type type ref to cl_abap_tabledescr, + lo_str_type type ref to cl_abap_structdescr. + + " Check if tabkey exists + if i_tabkey is not initial. + lo_type = cl_abap_typedescr=>describe_by_data_ref( i_data_ref ). + if lo_type->kind <> 'T'. " Not table ? + zcx_mockup_loader_error=>raise( msg = 'Tabkey is relevant for tables only' code = 'TO' ). "#EC NOTEXT + endif. + + lo_tab_type ?= lo_type. lo_str_type ?= lo_tab_type->get_table_line_type( ). + + read table lo_str_type->components with key name = i_tabkey transporting no fields. + if sy-subrc <> 0. + zcx_mockup_loader_error=>raise( msg = 'Tabkey field not found' code = 'FM' ). "#EC NOTEXT + endif. + endif. + + " Store data + l_store-name = i_name. + l_store-tabkey = i_tabkey. + l_store-data = i_data_ref. + + me->purge( i_name ). + append l_store to me->at_store. + +endmethod. + + + + + *"* use this source file for the definition and implementation of +*"* local helper classes, interface definitions and type +*"* declarations + *"* use this source file for any type of declarations (class +*"* definitions, interfaces or type declarations) you need for +*"* components in the private section + *"* use this source file for any macro definitions you need +*"* in the implementation part of the class + + + + + + + + + + method RAISE. + data: + l_methname type string, + sys_call type sys_calls, + sys_stack type sys_callst. + + " Get stack information + call function 'SYSTEM_CALLSTACK' + exporting max_level = 2 + importing et_callstack = sys_stack. + + read table sys_stack into sys_call index 2. + l_methname = sys_call-eventname && '():'. + + raise exception type zcx_mockup_loader_error + exporting + methname = l_methname + msg = msg + code = code. + +endmethod. + + + +