package com.eactive.eai.adapter.handler;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;

import java.lang.reflect.Field;
import java.util.Properties;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.context.ApplicationContext;

import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.StandardType;

/**
 * TemplateCodeConvertAdapterErrorMsgHandler 단위테스트
 *
 * 검증 대상: generateNonStandardErrorResponseMessage
 * - 부모 클래스(TemplateAdapterErrorMsgHandler)가 반환한 JSON 문자열에서
 *   PropManager(AdapterErrorMessageHandler{CODE_CONVERT} 그룹)에 등록된
 *   매핑 정보로 지정 필드 값을 변환한다.
 */
class TemplateCodeConvertAdapterErrorMsgHandlerTest {

    private TemplateCodeConvertAdapterErrorMsgHandler handler;

    @BeforeEach
    void setUp() {
        handler = new TemplateCodeConvertAdapterErrorMsgHandler();
    }

    // ================================================================
    // 공통 헬퍼
    // ================================================================

    private static StandardItem field(String name, String value) {
        return new StandardItem(name, 3, StandardType.FIELD, 1, 0, 300, 1, "", "", value, name);
    }

    private static StandardItem group(String name) {
        return new StandardItem(name, 2, StandardType.GROUP, 1, 0, 0, 1, "", "", null, name);
    }

    private StandardMessage buildMsg(String errCode, String errMsg) {
        StandardMessage msg = new StandardMessage();
        StandardItem msgGroup = group("MSG");
        StandardItem mainMsg = group("MAIN_MSG");
        mainMsg.addItem(field("outp_msg_cd",   errCode));
        mainMsg.addItem(field("outp_msg_ctnt", errMsg));
        msgGroup.addItem(mainMsg);

        StandardItem msgList = new StandardItem(
                "MSG_LIST", 2, StandardType.GRID, 0, 0, 0, 1, "", "", null, "MSG_LIST");
        msgList.addItem(field("outp_msg_cd",   ""));
        msgList.addItem(field("outp_msg_ctnt", ""));
        msgGroup.addItem(msgList);
        msg.addItem(msgGroup);
        return msg;
    }

    private EAIMessage toEaiMessage(StandardMessage msg) {
        EAIMessage eaiMessage = new EAIMessage();
        eaiMessage.setStandardMessage(msg);
        return eaiMessage;
    }

    /**
     * ApplicationContextProvider 에 mock PropManager 를 주입한다.
     * 부모 클래스의 getProperty(group, key) 와
     * 자식 클래스의 getProperties(group) 을 동일한 mock 으로 처리한다.
     */
    private void injectMockPropManager(PropManager mockPropManager) throws Exception {
        ApplicationContext mockCtx = Mockito.mock(ApplicationContext.class);
        Mockito.when(mockCtx.getBean(PropManager.class)).thenReturn(mockPropManager);
        Field ctxField = ApplicationContextProvider.class.getDeclaredField("context");
        ctxField.setAccessible(true);
        ctxField.set(null, mockCtx);
    }

    /**
     * 부모 템플릿 결과가 될 JSON 과 코드 변환 설정을 함께 세팅하는 헬퍼.
     *
     * @param adapterGroupName 어댑터 그룹명
     * @param template         부모 핸들러에서 사용할 JSON 템플릿 문자열
     * @param convertProps     PROP_GROUP(CODE_CONVERT) 에서 반환될 Properties (null 가능)
     */
    private PropManager setupMock(String adapterGroupName, String template,
                                  Properties convertProps) throws Exception {
        PropManager mockProp = Mockito.mock(PropManager.class);
        // 부모 클래스: getProperty("AdapterErrorMessageHandler", "GROUP.template")
        Mockito.when(mockProp.getProperty(
                eq(TemplateAdapterErrorMsgHandler.PROP_GROUP),
                eq(adapterGroupName + ".template"))).thenReturn(template);
        // 자식 클래스: getProperties("AdapterErrorMessageHandler{CODE_CONVERT}")
        Mockito.when(mockProp.getProperties(
                eq(TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP))).thenReturn(convertProps);
        injectMockPropManager(mockProp);
        return mockProp;
    }

    /** convert.fields 와 매핑 항목들로 Properties 를 생성하는 헬퍼 */
    private static Properties convertProps(String adapterGroupName,
                                           String fields,
                                           String... mappings) {
        Properties p = new Properties();
        p.setProperty(adapterGroupName + ".convert.fields", fields);
        for (int i = 0; i < mappings.length - 1; i += 2) {
            p.setProperty(adapterGroupName + "." + mappings[i], mappings[i + 1]);
        }
        return p;
    }

    // ================================================================
    // 사전 조건 및 조기 반환
    // ================================================================

    @Nested
    @DisplayName("사전 조건 – 조기 반환")
    class EarlyReturn {

        @Test
        @DisplayName("부모 핸들러가 null 반환 시 null 그대로 반환")
        void 부모_null_반환시_null() throws Exception {
            PropManager mockProp = Mockito.mock(PropManager.class);
            // 템플릿 없음 → 부모 핸들러가 null 반환
            Mockito.when(mockProp.getProperty(anyString(), anyString())).thenReturn(null);
            injectMockPropManager(mockProp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "MY_GROUP", "MY_ADAPTER", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "오류")));

            assertNull(result);
            // getProperties 는 호출되지 않아야 함
            Mockito.verify(mockProp, Mockito.never())
                    .getProperties(TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP);
        }

        @Test
        @DisplayName("부모 핸들러가 빈 문자열 반환 시 그대로 반환 (변환 미수행)")
        void 부모_빈문자열_그대로_반환() throws Exception {
            setupMock("MY_GROUP", "   ", null); // blank → 부모도 null 반환

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "MY_GROUP", "MY_ADAPTER", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "오류")));

            assertNull(result);
        }

        @Test
        @DisplayName("CODE_CONVERT 그룹의 Properties 가 null 이면 템플릿 결과 그대로 반환")
        void convert_props_null_시_원본_반환() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            setupMock("MY_GROUP", template, null); // getProperties → null

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "MY_GROUP", "MY_ADAPTER", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "오류")));

            assertEquals("{\"resCode\":\"40000\"}", result);
        }

        @Test
        @DisplayName("convert.fields 키가 없으면 템플릿 결과 그대로 반환")
        void convert_fields_없으면_원본_반환() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            // convert.fields 를 설정하지 않은 빈 Properties
            setupMock("MY_GROUP", template, new Properties());

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "MY_GROUP", "MY_ADAPTER", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "오류")));

            assertEquals("{\"resCode\":\"40000\"}", result);
        }

        @Test
        @DisplayName("convert.fields 가 공백이면 템플릿 결과 그대로 반환")
        void convert_fields_공백이면_원본_반환() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            Properties cp = new Properties();
            cp.setProperty("MY_GROUP.convert.fields", "   ");
            setupMock("MY_GROUP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "MY_GROUP", "MY_ADAPTER", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "오류")));

            // 필드가 공백이므로 split 후 trim → blank → skip → 변환 없음
            assertEquals("{\"resCode\":\"40000\"}", result);
        }
    }

    // ================================================================
    // 단순 필드 코드 변환
    // ================================================================

    @Nested
    @DisplayName("단순 필드 코드 변환")
    class SimpleFieldConvert {

        @Test
        @DisplayName("단일 필드 값 변환")
        void 단일_필드_변환() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
            Properties cp = convertProps("GRP",
                    "resCode",
                    "resCode.40000", "TB_ERR_999");
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "Bad Request")));

            assertEquals("{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"Bad Request\"}", result);
        }

        @Test
        @DisplayName("여러 필드 동시 변환")
        void 여러_필드_변환() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
            Properties cp = convertProps("GRP",
                    "resCode,resMessage",
                    "resCode.40000",    "TB_ERR_999",
                    "resMessage.40000", "요청파라미터에 문제가 있습니다.(필수값 입력오류)");
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "40000")));

            assertEquals(
                "{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"요청파라미터에 문제가 있습니다.(필수값 입력오류)\"}",
                result);
        }

        @Test
        @DisplayName("매핑에 없는 값은 원본 그대로 유지")
        void 매핑_없는_값_원본_유지() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            Properties cp = convertProps("GRP",
                    "resCode",
                    "resCode.40000", "TB_ERR_999");   // 99999 에 대한 매핑 없음
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("99999", "기타오류")));

            assertEquals("{\"resCode\":\"99999\"}", result);
        }

        @Test
        @DisplayName("convert.fields 쉼표 구분 중 공백 포함해도 정상 처리")
        void fields_공백_포함_정상처리() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
            Properties cp = convertProps("GRP",
                    " resCode , resMessage ",   // 공백 포함
                    "resCode.40000",    "TB_ERR_999",
                    "resMessage.40000", "필수값 오류");
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "40000")));

            assertEquals("{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"필수값 오류\"}", result);
        }

        @Test
        @DisplayName("매핑에 없는 값은 default 키로 폴백 변환")
        void 매핑_없는_값_default_폴백() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            Properties cp = convertProps("GRP",
                    "resCode",
                    "resCode.40000",   "TB_ERR_999",
                    "resCode.default", "TB_ERR_DEFAULT");  // 폴백
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("99999", "")));   // 99999 매핑 없음

            assertEquals("{\"resCode\":\"TB_ERR_DEFAULT\"}", result);
        }

        @Test
        @DisplayName("매핑이 있으면 default 보다 우선 적용")
        void 매핑_존재시_default_미사용() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            Properties cp = convertProps("GRP",
                    "resCode",
                    "resCode.40000",   "TB_ERR_999",
                    "resCode.default", "TB_ERR_DEFAULT");
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "")));   // 40000 매핑 존재

            assertEquals("{\"resCode\":\"TB_ERR_999\"}", result);
        }

        @Test
        @DisplayName("매핑도 default 도 없으면 원본 유지")
        void 매핑_default_모두없으면_원본_유지() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            Properties cp = convertProps("GRP",
                    "resCode",
                    "resCode.40000", "TB_ERR_999"  // 99999 매핑 없음, default 도 없음
            );
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("99999", "")));

            assertEquals("{\"resCode\":\"99999\"}", result);
        }

        @Test
        @DisplayName("여러 필드에서 일부는 매핑, 일부는 default 로 변환")
        void 여러_필드_매핑과_default_혼합() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
            Properties cp = new Properties();
            cp.setProperty("GRP.convert.fields", "resCode,resMessage");
            cp.setProperty("GRP.resCode.40000",       "TB_ERR_999");      // 정확 매핑
            cp.setProperty("GRP.resMessage.default",  "기타 오류입니다."); // resMessage 는 default 만
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "Bad Request")));

            assertEquals("{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"기타 오류입니다.\"}", result);
        }

        @Test
        @DisplayName("여러 에러코드에 대한 각각 다른 매핑 적용")
        void 다른_에러코드_다른_매핑() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            Properties cp = new Properties();
            cp.setProperty("GRP.convert.fields", "resCode");
            cp.setProperty("GRP.resCode.40000", "TB_ERR_999");
            cp.setProperty("GRP.resCode.50000", "TB_ERR_500");
            setupMock("GRP", template, cp);

            // 40000 → TB_ERR_999
            Object result1 = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "")));
            assertEquals("{\"resCode\":\"TB_ERR_999\"}", result1);

            // 50000 → TB_ERR_500
            Object result2 = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("50000", "")));
            assertEquals("{\"resCode\":\"TB_ERR_500\"}", result2);
        }
    }

    // ================================================================
    // 중첩 경로(dot path) 필드 코드 변환
    // ================================================================

    @Nested
    @DisplayName("중첩 경로(dot path) 필드 코드 변환")
    class NestedPathConvert {

        @Test
        @DisplayName("1단계 중첩 경로 필드 변환 – result.code")
        void 한단계_중첩_경로_변환() throws Exception {
            // 템플릿이 중첩 JSON 을 생성하는 경우 → 변환 전 JSON 을 직접 구성
            // 부모 render 결과를 미리 알고 있으므로, 간단한 템플릿 + 고정값 활용
            String template = "{\"result\":{\"code\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}}";
            Properties cp = convertProps("GRP",
                    "result.code",
                    "result.code.40000", "TB_ERR_999");
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "")));

            assertEquals("{\"result\":{\"code\":\"TB_ERR_999\"}}", result);
        }

        @Test
        @DisplayName("2단계 중첩 경로 필드 변환 – a.b.code")
        void 두단계_중첩_경로_변환() throws Exception {
            // 부모가 반환할 JSON: 고정 문자열 + stdmsg 치환 없이 직접 지정
            // 어댑터 그룹명 키 + template 이 fixed JSON 을 반환하도록 설정
            String fixedJson = "{\"a\":{\"b\":{\"code\":\"ERR_001\"}}}";
            PropManager mockProp = Mockito.mock(PropManager.class);
            Mockito.when(mockProp.getProperty(
                    eq(TemplateAdapterErrorMsgHandler.PROP_GROUP),
                    eq("GRP.template"))).thenReturn(fixedJson);   // 변수 없는 고정 JSON
            Properties cp = convertProps("GRP",
                    "a.b.code",
                    "a.b.code.ERR_001", "MAPPED_CODE");
            Mockito.when(mockProp.getProperties(
                    eq(TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP))).thenReturn(cp);
            injectMockPropManager(mockProp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("", "")));

            assertEquals("{\"a\":{\"b\":{\"code\":\"MAPPED_CODE\"}}}", result);
        }

        @Test
        @DisplayName("중첩 경로가 존재하지 않으면 해당 필드 변환 건너뜀")
        void 없는_중첩_경로_건너뜀() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            Properties cp = convertProps("GRP",
                    "nonExist.code",       // JSON 에 없는 경로
                    "nonExist.code.40000", "MAPPED");
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "")));

            // 변환 대상 필드가 없으므로 원본 그대로
            assertEquals("{\"resCode\":\"40000\"}", result);
        }
    }

    // ================================================================
    // 복합 시나리오
    // ================================================================

    @Nested
    @DisplayName("복합 시나리오")
    class Combined {

        @Test
        @DisplayName("일부 필드만 매핑 존재 – 나머지는 원본 유지")
        void 일부_필드_매핑_나머지_원본() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
            Properties cp = convertProps("GRP",
                    "resCode,resMessage",
                    "resCode.40000", "TB_ERR_999"
                    // resMessage 매핑 없음
            );
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "Bad Request")));

            // resCode 는 변환, resMessage 는 원본 유지
            assertEquals("{\"resCode\":\"TB_ERR_999\",\"resMessage\":\"Bad Request\"}", result);
        }

        @Test
        @DisplayName("프로퍼티 그룹명 검증 – PROP_GROUP 상수 값")
        void PROP_GROUP_상수_검증() {
            assertEquals("AdapterErrorMessageHandler{CODE_CONVERT}",
                    TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP);
        }

        @Test
        @DisplayName("부모 PROP_GROUP 과 자식 PROP_GROUP 이 다른 그룹을 사용")
        void 부모_자식_PROP_GROUP_다름() {
            // 부모: "AdapterErrorMessageHandler"
            // 자식: "AdapterErrorMessageHandler{CODE_CONVERT}"
            assertNotEquals(
                    TemplateAdapterErrorMsgHandler.PROP_GROUP,
                    TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP);
        }

        @Test
        @DisplayName("변환 후에도 JSON 에 변환 대상 외 필드는 그대로 유지")
        void 변환_후_비대상_필드_유지() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\",\"extra\":\"value\",\"resMessage\":\"${MSG.MAIN_MSG.outp_msg_ctnt}\"}";
            Properties cp = convertProps("GRP",
                    "resCode",
                    "resCode.40000", "TB_ERR_999");
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "오류")));

            assertEquals("{\"resCode\":\"TB_ERR_999\",\"extra\":\"value\",\"resMessage\":\"오류\"}", result);
        }

        @Test
        @DisplayName("convert.fields 에 등록된 필드가 JSON 루트에 없어도 예외 없이 처리")
        void JSON에_없는_필드_등록시_예외_없음() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            Properties cp = convertProps("GRP",
                    "resCode,nonExistField",
                    "resCode.40000",         "TB_ERR_999",
                    "nonExistField.40000",   "MAPPED");
            setupMock("GRP", template, cp);

            Object result = handler.generateNonStandardErrorResponseMessage(
                    "GRP", "ADP", new Properties(), null,
                    toEaiMessage(buildMsg("40000", "")));

            // nonExistField 는 getJsonValue 가 null 반환 → 건너뜀, 예외 없음
            assertEquals("{\"resCode\":\"TB_ERR_999\"}", result);
        }

        @Test
        @DisplayName("inboundAdapterGroupName 이 달라지면 다른 convert.fields 키를 사용")
        void 다른_어댑터그룹_다른_키_사용() throws Exception {
            String template = "{\"resCode\":\"${MSG.MAIN_MSG.outp_msg_cd}\"}";
            Properties cp = new Properties();
            cp.setProperty("GROUP_A.convert.fields", "resCode");
            cp.setProperty("GROUP_A.resCode.40000",  "A_MAPPED");
            cp.setProperty("GROUP_B.convert.fields", "resCode");
            cp.setProperty("GROUP_B.resCode.40000",  "B_MAPPED");
            PropManager mockProp = Mockito.mock(PropManager.class);
            Mockito.when(mockProp.getProperty(
                    eq(TemplateAdapterErrorMsgHandler.PROP_GROUP),
                    anyString())).thenReturn(template);
            Mockito.when(mockProp.getProperties(
                    eq(TemplateCodeConvertAdapterErrorMsgHandler.PROP_GROUP))).thenReturn(cp);
            injectMockPropManager(mockProp);

            EAIMessage msg = toEaiMessage(buildMsg("40000", ""));

            Object resultA = handler.generateNonStandardErrorResponseMessage(
                    "GROUP_A", "ADP", new Properties(), null, msg);
            Object resultB = handler.generateNonStandardErrorResponseMessage(
                    "GROUP_B", "ADP", new Properties(), null, msg);

            assertEquals("{\"resCode\":\"A_MAPPED\"}", resultA);
            assertEquals("{\"resCode\":\"B_MAPPED\"}", resultB);
        }
    }

}
